Search code examples
xmlpowershellrecursionnodeshashtable

XML recursive node adding


I'm struggling with recursive adding child nodes to XML in Powershell. The main goal is to update the XML files based on the provided file.

ex. XML looks like this:

<a>
    <b>
        <c1>Value0</c1>
    </b>
</a>

and I want to add node with child nodes to make it looks like this (the order is not important):

<a>
    <b>
        <c>
            <d1>Value1</d2>
            <d2>Value2</d2>
            <d3>Value3</d3>
        </c>
        <c1>Value0</c1>
    </b>
</a>

I created two functions for this:

function InsertRecursively {
    param (
        $OriginalXml,
        $DataToInsert
    )

    foreach ($key in $DataToInsert.Keys) {        
        
        if ($DataToInsert.$key.GetType().Name -eq "Hashtable") {
            SetChildItem -XML $OriginalXml -ChildName $key
            InsertRecursively -OriginalXml $OriginalXml.$key -DataToInsert $DataToInsert.$key
        }
        else {
            SetChildItem -Xml $OriginalXml -ChildName $key -ChildValue $DataToInsert.$key
        }
    }
}
function SetChildItem {
    param (
        $Xml,
        $ChildName,
        $ChildValue
    )

    if ($null -eq $Xml.$ChildName) {
        $child = $ssCont.CreateElement($ChildName)

        if ($ChildValue) {
            $child.InnerText = $ChildValue.ToString()
        }

        $Xml.AppendChild($child) > $null
        Write-Host "Adding item '$ChildName'"
    }
    elseif (($null -ne $ChildValue) -and ($Xml.$ChildName -ne $ChildValue)) {
        $Xml.$ChildName = $ChildValue.ToString()
        Write-Host "Updating value of item '$ChildName'"
    }
    else {
        Write-Host "Item '$ChildName' is set correctly"
    }

    return $Xml
}

When the function adds the first child to the existing node everything works fine, problem is when the function wants to add another child to this child node - then the $Xml parameter in the SetChildItem function is just an empty string, not a node where the function can add a child. The result is an error that the string does not contain a method AppendChild.


Solution

  • Here is how I would do it with Xml Linq in c#. You can used the Xml Linq library with Power Shell.

                string input = @"
                            <a>
                    <b>
                        <c1>Value0</c1>
                    </b>
                </a>";
    
                XDocument doc = XDocument.Parse(input);
    
                XElement nodeB = doc.Descendants("b").FirstOrDefault();
    
                XElement nodeC = new XElement("c", new object[] {
                    new XElement("d1", "Value1"),
                    new XElement("d2", "Value2"),
                    new XElement("d2", "Value3")
                });
    
                nodeB.Add(nodeC);
    

    If you want the new node as first item use : nodeB.AddFirst(nodeC);