Home > front end >  XML recursive node adding
XML recursive node adding

Time:03-19

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.

CodePudding user response:

Something simpler like the below:

$xml = [xml]@"
<a>
    <b>
        <c1>Value0</c1>
    </b>
</a>
"@

$newElements = [xml]@"
        <c>
            <d1>Value1</d1>
            <d2>Value2</d2>
            <d3>Value3</d3>
        </c>
"@

$newNode = $xml.ImportNode($newElements.get_DocumentElement(), $true)
$xml.SelectSingleNode('//b').AppendChild($newNode)

Should output

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

CodePudding user response:

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

  • Related