I have a scenario where I need to chain nest XmlElements, and I got a working solution using a recursive function, but I can't help but feel that it can be made better.

Here's my code so far:

function AppendChild
    if ($string.Length -gt 0)
        $child = $XML.CreateElement($string[0])
        $child.InnerText = ""
        AppendChild -string ($string | Select -Skip 1) -obj $child -XML $XML

$string = "this is a somewhat long string" -split " "

$XML = New-Object System.Xml.XmlDocument
$root = $XML.CreateElement($string[0])

AppendChild -string ($string | Select -Skip 1) -obj $root -XML $XML

$root.OuterXml # <this><is><a><somewhat><long><string></string></long></somewhat></a></is></this>

Any suggestions?

  • \$\begingroup\$ Your code doesn't work for me. \$\endgroup\$ – Dangph Apr 28 '16 at 10:21
  • \$\begingroup\$ @Dangph What error are you encountering? I've made some edits to the script to make it more compatible with other versions of PowerShell. \$\endgroup\$ – Negorath Apr 28 '16 at 12:46
  • \$\begingroup\$ Sorry, I should have said why it didn't work. It was the [System.Xml.XmlDocument]::new(). Is that a new feature in PowerShell? \$\endgroup\$ – Dangph Apr 29 '16 at 0:08
  • \$\begingroup\$ @Dangph Yes, I can't find any changelogs for it at the moment, but I belive it came with PowerShell 4. \$\endgroup\$ – Negorath Apr 29 '16 at 5:02
  • \$\begingroup\$ I see. I have PS3. \$\endgroup\$ – Dangph Apr 29 '16 at 5:27

I don't think you need recursion. Just a simple loop will do. We can just keep a reference to the last element in the document, which we update every time we append a new element, and we keep appending to that.

$tagNames = "this     is a somewhat long string" -split "\s+"
$XML = New-Object System.Xml.XmlDocument

$lastElt = $XML

$tagNames | % { 
    $elt = $XML.CreateElement($_)
    $lastElt = $lastElt.AppendChild($elt)

$xml.OuterXml # <this><is><a><somewhat><long><string /></long></somewhat></a></is></this>

I also changed it to split the string on \s+, which is a regular expression meaning "one or whitespace characters", so that multiple consecutive spaces (or tabs or whatever) will be counted as a single thing as far as -split is concerned.

I change $string to $tagNames because it is important to name variables accurately otherwise you will confuse yourself.

  • \$\begingroup\$ Excellent! It seems so obvious now, it's even much faster according to my tests. Thanks for your answer :) \$\endgroup\$ – Negorath Apr 29 '16 at 4:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.