在另一个节点之后插入新的XML节点

时间:2017-02-16 22:45:47

标签: xml powershell xml-parsing selectsinglenode

我真的很难在PowerShell中操作一些我需要作为正文发送回Web服务的XML。任何人都可以帮助我按照需要的方式获取XML吗?

<?xml version="1.0" encoding="UTF-8"?>
<EdgeGateway>
<Configuration>
    <GatewayInterfaces>
        <GatewayInterface>
            <InterfaceType>uplink</InterfaceType>
            <SubnetParticipation>
                <Gateway>1.2.3.4</Gateway>
                <Netmask>255.255.255.240</Netmask>
                <IpAddress>1.2.3.5</IpAddress>
# Missing the IpRange XML section - defined below
                <UseForDefaultRoute>true</UseForDefaultRoute>
            </SubnetParticipation>
            <UseForDefaultRoute>true</UseForDefaultRoute>
        </GatewayInterface>
    </GatewayInterfaces>
</Configuration>
</EdgeGateway>

需要成为:

<?xml version="1.0" encoding="UTF-8"?>
<EdgeGateway>
<Configuration>
    <GatewayInterfaces>
        <GatewayInterface>
            <InterfaceType>uplink</InterfaceType>
            <SubnetParticipation>
                <Gateway>1.2.3.4</Gateway>
                <Netmask>255.255.255.240</Netmask>
                <IpAddress>1.2.3.5</IpAddress>
# New Content added here
                <IpRanges>
                    <IpRange>
                        <StartAddress>1.2.3.5</StartAddress>
                        <EndAddress>1.2.3.5</EndAddress>
                    <IpRange>
                </IpRanges>
 # End of new content
                <UseForDefaultRoute>true</UseForDefaultRoute>
            </SubnetParticipation>
            <UseForDefaultRoute>true</UseForDefaultRoute>
        </GatewayInterface>
    </GatewayInterfaces>
</Configuration>
</EdgeGateway>

到目前为止,我已经能够为新内容创建新的XML节点/元素,但我无法将其插入到正确的位置。我可以使用AppendChild()方法,但它会将内容放在<UseForDefaultRoute>部分之后 - 而不是之前。

我已尝试InsertBefore()InsertAfter(),但它只是不想工作。 最后,当我执行AppendChild()方法时,我还得到了一些我不期待的额外文本,关于xmlns的内容?

<IpRanges xmlns=""><IpRange><StartAddress>1.2.3.5</StartAddress><EndAddress>1.2.3.5</EndAddress></IpRange></IpRanges>

这是我设法放在一起的,请记住它已经破碎了:(

# load XML file
[xml]$doc = $response

# create node <StartAddress>
$startNode = $doc.CreateNode('element', 'StartAddress', '')
$start = $doc.CreateTextNode('1.2.3.5')
$startNode.AppendChild($start) | Out-Null

# create node <EndAddress>
$endNode = $doc.CreateNode('element', 'EndAddress', '')
$end = $doc.CreateTextNode('1.2.3.5')
$endNode.AppendChild($end) | Out-Null

# create node <IpRange> and append child nodes <StartAddress> and     <EndAddress>
$ipRange = $doc.CreateNode('element', 'IpRange', '')
$ipRange.AppendChild($startNode) | Out-Null
$ipRange.AppendChild($endNode) | Out-Null

# create node <IpRanges> and append child nodes <IpRange>
$ipRanges = $doc.CreateNode('element', 'IpRanges', '')
$ipRanges.AppendChild($ipRange) | Out-Null

# append node <IpRanges> to node <SubnetParticipation>
$subnetParticpation = $doc.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[1].SubnetParticipation.AppendChild($ipRanges)

...根据Ansgar的建议,这是我尝试使用命名空间。 (碎)

[xml]$fragment = "<dummy xmlns:xsi='http://www.vmware.com/vcloud/v1.5'><IpRanges>$($ipRanges.InnerXml)</IpRanges></dummy>"

# $fragment.InnerXml ..returns..
# <dummy xmlns:xsi="http://www.vmware.com/vcloud/v1.5"><IpRanges><IpRange><StartAddress>185.39.247.98</StartAddress><EndAddress>185.39.247.98</EndAddress></IpRange></IpRanges></dummy>

# $body is the full XML Document I want to paste into
[xml]$xml = $body

$nsm = New-Object Xml.XmlNamespaceManager $xml.NameTable
$nsm.AddNamespace('xsi', $xml.NamespaceURI)
$node = $xml.ImportNode($fragment.DocumentElement.IpRanges, $true)

$subnetPart = $xml.SelectSingleNode("//IpAddress[text()='185.39.247.98']", $nsm)
$subnetPart

# returns nothing

2 个答案:

答案 0 :(得分:1)

您可以在其他节点之后插入新节点,如下所示:

$node = $doc.SelectSingleNode("//IpAddress[text()='1.2.3.5']")
$node.ParentNode.InsertAfter($ipRanges, $node)

答案 1 :(得分:0)

考虑XSLT,这是一种特殊用途,符合W3C标准的语言,旨在将XML文件转换为其他XML,HTML甚至文本格式。 PowerShell可以调用内置的XslCompiledTransform类,传入源文件,xslt脚本和输出文件的参数。

XSLT (使用Identity Transform按原样复制并更新SubnetParticipation节点)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>

  <!-- Identity Transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="SubnetParticipation">
    <xsl:copy>
      <xsl:apply-templates />
      <IpRanges>
        <IpRange>
          <StartAddress>1.2.3.5</StartAddress>
          <EndAddress>1.2.3.5</EndAddress>
        </IpRange>
      </IpRanges>
    </xsl:copy>
  </xsl:template>

</xsl:transform>

<强>的PowerShell

param ($xml, $xsl, $output)

if (-not $xml -or -not $xsl -or -not $output) {
    Write-Host "& .\xslt.ps1 [-xml] xml-input [-xsl] xsl-input [-output] transform-output"
    exit;
}

trap [Exception]{
    Write-Host $_.Exception;
}

$xslt = New-Object System.Xml.Xsl.XslCompiledTransform;

$xslt.Load($xsl);
$xslt.Transform($xml, $output);

Write-Host "generated" $output;

命令行调用(或批处理脚本调用)

Powershell.exe -File "C:\Path\To\PowerShell\Script.ps1"
 "C:\Path\To\Source.xml" "C:\Path\To\Transform.xsl" "C:\Path\To\Output.xml"

<强>输出

<?xml version="1.0" encoding="utf-8"?>
<EdgeGateway>
  <Configuration>
    <GatewayInterfaces>
      <GatewayInterface>
        <InterfaceType>uplink</InterfaceType>
        <SubnetParticipation>
          <Gateway>1.2.3.4</Gateway>
          <Netmask>255.255.255.240</Netmask>
          <IpAddress>1.2.3.5</IpAddress>
          <UseForDefaultRoute>true</UseForDefaultRoute>
          <IpRanges>
            <IpRange>
              <StartAddress>1.2.3.5</StartAddress>
              <EndAddress>1.2.3.5</EndAddress>
            </IpRange>
          </IpRanges>
        </SubnetParticipation>
        <UseForDefaultRoute>true</UseForDefaultRoute>
      </GatewayInterface>
    </GatewayInterfaces>
  </Configuration>
</EdgeGateway>