Monday, June 16, 2008

I've been looking all over trying to find a smart way to create nested XML in powershell, and after combining a few sources I have come up with something that works pretty well.  Now I don't recommend actually doing it this way unless you have to.  This is a fairly laborious process that I'm undertaking only because my particular situation requires that I do not use compiled code.  A C# object model using the Linq XML serializer is far easier, consistent, and less prone to bugs than this.  However sometime you just have to write a hack.

# Create the results file
$output = $args[0] + "\results.xml"
$outxml = New-Object "System.Xml.XmlDocument"
$outxml.LoadXml("<?xml version=`"1.0`" encoding=`"utf-8`"?><Results xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`" xmlns:xsd=`"http://www.w3.org/2001/XMLSchema`"></Results>")
 
# Tests
$elem = $outxml.CreateElement("Tests")
$outxml.get_ChildNodes().Item(1).AppendChild($elem)
 
# Test
$elem = $outxml.CreateElement("Test")
$elem.SetAttribute("xsi:type","MemoryTest")
$outxml.SelectSingleNode("Results/Tests").AppendChild($elem)
 
# Name
$elem = $outxml.CreateElement("Name")
$elem.PSBase.InnerText = "Video"
$nsMgr = New-Object System.Xml.XmlNamespaceManager($outxml.get_NameTable())
$nsMgr.AddNamespace("type", "MemoryTest")
$outxml.SelectSingleNode("Results/Tests/Test", $nsMgr).AppendChild($elem)

 

Notice the use of the XmlNamespaceManager.  This allows you to have multiple Test nodes within Tests each with a different type.  This makes sure you can add elements to the right trees. 

Again, this is the grunt work of XML serialization that lots of programmers end up doing, but really shouldn't have to.  Go use the Linq serializer.