Refactoring using a Pure Function - VB

[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 = _
"https://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 = _
"https://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 = _
"https://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]