Blog - Title

Refactoring using a Pure Function - VB

Refactoring using a Pure Function - VB

  • Comments 0

[Table of Contents] [Next Topic]

It would be useful to refactor this example to clean up the code that determines the style of the paragraph. We can make a function that has no side effects that returns the style name:

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOC

Public Function GetParagraphStyle(para As XElement) As String
    Dim w As XNamespace = _
        "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
    Return CStr(para.Elements(w + "pPr") _
        .Elements(w + "pStyle") _
        .Attributes(w + "val") _
        .FirstOrDefault())
End Function
 

Now, the query is as follows:

Dim paragraphs = _
    mainPartDoc.Root _
        .Element(w + "body") _
        .Descendants(w + "p") _
        .Select(Function(p) _
            New With { _
                .ParagraphNode = p, _
                .Style = GetParagraphStyle(p) _
            } _
        )
 

We can rewrite the version that uses a query expression:

Dim paragraphs = _
    From p In mainPartDoc.Root _
        .Element(w + "body") _
        .Descendants(w + "p") _
    Let style = GetParagraphStyle(p) _
    Select New With { _
        .ParagraphNode = p, _
        .Style = style _
    }
 

This is easier to read.

Because we wrote the GetParagraphStyle function without side effects, we were free to use it without worrying about how it would impact the execution of our query.

The entire example follows.

Imports System.IO
Imports System.Xml
Imports DocumentFormat.OpenXml.Packaging
 
Module Module1
    <System.Runtime.CompilerServices.Extension()> _
    Public Function GetPath(ByVal el As XElement) As String
        Return el _
            .AncestorsAndSelf _
            .InDocumentOrder _
            .Aggregate("", Function(seed, i) seed & "/" & i.Name.LocalName)
    End Function
 
    Public Function LoadXDocument(ByVal part As OpenXmlPart) _
            As XDocument
        Using streamReader As StreamReader = New StreamReader(part.GetStream())
            Using xmlReader As XmlReader = xmlReader.Create(streamReader)
                Return XDocument.Load(xmlReader)
            End Using
        End Using
    End Function
 
    Public Function GetParagraphStyle(ByVal para As XElement) As String
        Dim w As XNamespace = _
            "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
        Return CStr(para.Elements(w + "pPr") _
                       .Elements(w + "pStyle") _
                       .Attributes(w + "val") _
                       .FirstOrDefault())
    End Function
 
    Sub Main()
        Dim w As XNamespace = _
            "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
        Dim filename As String = "SampleDoc.docx"
        Using wordDoc As WordprocessingDocument = _
            WordprocessingDocument.Open(filename, True)
            Dim mainPart As MainDocumentPart = _
                wordDoc.MainDocumentPart
            Dim mainPartDoc As XDocument = LoadXDocument(mainPart)
            Dim paragraphs = _
                mainPartDoc.Root _
                    .Element(w + "body") _
                    .Descendants(w + "p") _
                    .Select(Function(p) _
                        New With { _
                            .ParagraphNode = p, _
                            .Style = GetParagraphStyle(p) _
                        } _
                    )
 
            For Each p In paragraphs
                Dim s As String
                If Not p.Style Is Nothing Then
                    s = p.Style.PadRight(12)
                Else
                    s = "".PadRight(12)
                End If
                Console.WriteLine("{0} {1}", s, _
                    p.ParagraphNode.GetPath())
            Next
        End Using
    End Sub
End Module
 

[Table of Contents] [Next Topic] [Blog Map]

Leave a Comment
  • Please add 7 and 7 and type the answer here:
  • Post