XML递归节点添加

XML recursive node adding

我正在为在 Powershell 中向 XML 递归添加子节点而苦苦挣扎。 主要目标是根据提供的文件更新 XML 文件。

例如。 XML 看起来像这样:

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

我想添加带有子节点的节点,使其看起来像这样(顺序不重要):

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

我为此创建了两个函数:

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
}

当函数将第一个子节点添加到现有节点时一切正常,问题是当函数想要将另一个子节点添加到该子节点时 - 那么 SetChildItem 函数中的 $Xml 参数只是一个空字符串,而不是函数可以添加子节点的节点。结果报错,字符串不包含方法AppendChild.

以下是我在 C# 中使用 Xml Linq 的方法。您可以将 Xml Linq 库与 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);

如果你想将新节点作为第一项使用:nodeB.AddFirst(nodeC);

像下面这样更简单的东西:

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

应该输出

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