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
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