Monthly Archive

Categories

XML to Word

Found an interesting challenge on the WinIT magazine forum.  Take an XML file

<recipe name="bread" prep_time="5 mins" cook_time="3 hours">
<title>Basic bread</title>
<ingredient amount="8" unit="dL">Flour</ingredient>
<ingredient amount="10" unit="grams">Yeast</ingredient>
<ingredient amount="4" unit="dL" state="warm">Water</ingredient>
<ingredient amount="1" unit="teaspoon">Salt</ingredient>
<instructions>
<step>Mix all ingredients together.</step>
<step>Knead thoroughly.</step>
<step>Cover with a cloth, and leave for one hour in warm room.</step>
<step>Knead again.</step>
<step>Place in a bread baking tin.</step>
<step>Cover with a cloth, and leave for one hour in warm room.</step>
<step>Bake in the oven at 180(degrees)C for 30 minutes.</step>
</instructions>
</recipe>

and turn it into a Word document.  I came up with this as a first pass.  Length of the script can be cut by using functions

## remove existing document
$file = "c:\scripts\test.doc"
if (Test-Path $file){Remove-Item -Path $file}
## read xml file
$x = Get-Content -Path c:\scripts\test.xml

## open word document
$word = New-Object -ComObject "Word.application"
$word.visible = $true
$doc = $word.Documents.Add()
$doc.Activate()

## recipe title
$word.Selection.Font.Name = "Cambria"
$word.Selection.Font.Size = "20"
$word.Selection.TypeText($x.recipe.title)
$word.Selection.TypeParagraph()

$word.Selection.Font.Name = "Calibri"
$word.Selection.Font.Size = "11"
$word.Selection.TypeText("Preparation Time = $($x.recipe.prep_time)")
$word.Selection.TypeParagraph()

$word.Selection.Font.Name = "Calibri"
$word.Selection.Font.Size = "11"
$word.Selection.TypeText("Preparation Time = $($x.recipe.cook_time)")
$word.Selection.TypeParagraph()
## ingredients
$word.Selection.Font.Name = "Cambria"
$word.Selection.Font.Size = "14"
$word.Selection.TypeText("Ingredients")
$word.Selection.TypeParagraph()

$word.Selection.Font.Name = "Calibri"
$word.Selection.Font.Size = "11"
for ($i=0; $i -le ($x.recipe.ingredient.length -1); $i++){

$ingdnt = $x.recipe.ingredient[$i].amount + " " + $x.recipe.ingredient[$i].unit + " " + $x.recipe.ingredient[$i]."#text" + " " + $x.recipe.ingredient[$i].state
$word.Selection.TypeText($ingdnt)
$word.Selection.TypeParagraph()
}
## instructions
$instructions = $x.recipe.instructions.step | out-string
$word.Selection.Font.Name = "Cambria"
$word.Selection.Font.Size = "14"
$word.Selection.TypeText("Instructions")
$word.Selection.TypeParagraph()
$word.Selection.Font.Name = "Calibri"
$word.Selection.Font.Size = "11"
$word.Selection.TypeText($instructions)
$word.Selection.TypeParagraph()

$doc.SaveAs([REF]$file)
$Word.Quit()

The interesting part is working with XML.  By reading it into $x we create an xmldocument object.  We can then step through the attributes and the elements, convert them to strings where necessary and output to the word document.  If you’ve not played with XML before its worth spending a little time experimenting at the various levels in the document – especially putting them through get-member.

Couple of points to note.  The way the ingredient element text and the associated attributes are obtained. The way just the instruction steps are retrieved.

Interesting problem.  For this particular file I found it easier to do this way than using Select-XML from CTP 3.  Select-XML is good for investigating XML but you do have to learn XPath syntax

Technorati Tags: ,

Leave a Reply