如何在XML中使用insertAfter()在特定元素后插入元素

5

我的 .xml 文件长这样

<?xml version="1.0" encoding="UTF-8"?>
<layoutMaster xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="..\schema\m.xsd">
  <deviceFamily>
    <deviceFamilyUniqueID>DeviceFamilyWayside_2</deviceFamilyUniqueID>
    <name>DeviceFamilyWayside_2</name>
    <device>SAMSUNG</device>
    <device>SONY</device>
    <deviceFamilyOptions>
      <name>false</name>
    </deviceFamilyOptions>
  </deviceFamily>
  <deviceFamily>
    <deviceFamilyUniqueID>DeviceFamilyWayside_4</deviceFamilyUniqueID>
    <name>DeviceFamilyWayside_4</name>
    <device>IPHONE</device>
    <device>MAC</device>
    <deviceFamilyOptions>
      <name>false</name>
    </deviceFamilyOptions>
  </deviceFamily>
</layoutMaster>

我希望在最后一个设备之后将一个新设备添加到deviceFamily[deviceFamilyUniqueID ='DeviceFamilyWayside_2']中:

于是我在PowerShell中尝试了以下代码:

$Path = ".\config.xml"
[xml]$xmlFile = Get-Content -Path $Path

$xmlNewElementDevice = $xmlFile.CreateElement("device")
$xmlNewElementDevice.AppendChild($xmlFile.CreateTextNode("ALCATEL"))

$xmlTargetDeviceWayside = $xmlFile.SelectSingleNode('//layoutMaster/deviceFamily[deviceFamilyUniqueID = "DeviceFamilyWayside_2"]')
$xmlTargetDeviceWayside.InsertAfter($xmlNewElementDevice,$xmlTargetDeviceWayside.name)

但是我收到了这个错误:

无法将参数“1”(值“DeviceFamilyWayside_2”)从“InsertAfter”转换为类型“System.Xml.XmlNode”:“无法将“DeviceFamilyWayside_2”值从“System.String”转换为类型“System.Xml.XmlNode”。"

我想要的最终结果应该像这样:

<?xml version="1.0" encoding="UTF-8"?>
<layoutMaster xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="..\schema\m.xsd">
  <deviceFamily>
    <deviceFamilyUniqueID>DeviceFamilyWayside_2</deviceFamilyUniqueID>
    <name>DeviceFamilyWayside_2</name>
    <device>SAMSUNG</device>
  <device>SONY</device>
    <device>ALCATEL</device>    <--------------- here
    <deviceFamilyOptions>
      <name>false</name>
    </deviceFamilyOptions>
  </deviceFamily>
  <deviceFamily>
    <deviceFamilyUniqueID>DeviceFamilyWayside_4</deviceFamilyUniqueID>
    <name>DeviceFamilyWayside_4</name>
    <device>IPHONE</device>
  <device>MAC</device>
    <deviceFamilyOptions>
      <name>false</name>
    </deviceFamilyOptions>
  </deviceFamily>
</layoutMaster>
2个回答

6

在节点<deviceFamilyOptions>之前插入新节点:

[xml]$xml = Get-Content -Path $Path

$newNode = $xml.CreateElement("device")
$newNode.InnerText = 'ALCATEL'

$parent = $xml.SelectSingleNode('//layoutMaster/deviceFamily[deviceFamilyUniqueID="DeviceFamilyWayside_2"]')
$ref    = $parent.SelectSingleNode('./deviceFamilyOptions')

$parent.InsertBefore($newNode, $ref) | Out-Null

或者选择最后一个<device>节点作为参考节点,在该节点之后插入新节点:

$parent = $xml.SelectSingleNode('//layoutMaster/deviceFamily[deviceFamilyUniqueID="DeviceFamilyWayside_2"]')
$ref    = $parent.SelectSingleNode('./device[last()]')

$parent.InsertAfter($newNode, $ref) | Out-Null

哥们,你已经两次救了我,非常感谢你,我真的非常感激你,谢谢! - J. Sam

0
考虑到与XPath同级的XSLT(专门用于转换XML的特殊语言),PowerShell可以使用System.Xml.Xsl.XslCompiledTransform扩展来运行XSLT 1.0脚本。 XSLT (保存为.xsl,一个特殊的.xml文件)
<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>

  <!-- Conditionally Update Needed Node -->
  <xsl:template match="deviceFamily[deviceFamilyUniqueID = 'DeviceFamilyWayside_2']">    
     <xsl:copy>        
       <xsl:apply-templates select="deviceFamilyUniqueID|name|device"/>          
       <device>ALCATEL</device>
       <xsl:apply-templates select="deviceFamilyOptions"/>
     </xsl:copy>    
  </xsl:template>

</xsl:transform>

Powershell (适用于任何 XML 数据源和 XSLT 脚本的通用脚本)

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

命令行

Powershell.exe -File "C:\Path\To\PowerShell\Script.ps1"^
 "C:\Path\To\Input.xml" "C:\Path\To\XSLTScript.xsl" "C:\Path\To\Ouput.xml"

输出 (漂亮的缩进)

<?xml version="1.0" encoding="UTF-8"?>
<layoutMaster xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:noNamespaceSchemaLocation="..\schema\m.xsd">
   <deviceFamily>
      <deviceFamilyUniqueID>DeviceFamilyWayside_2</deviceFamilyUniqueID>
      <name>DeviceFamilyWayside_2</name>
      <device>SAMSUNG</device>
      <device>SONY</device>
      <device>ALCATEL</device>
      <deviceFamilyOptions>
         <name>false</name>
      </deviceFamilyOptions>
   </deviceFamily>
   <deviceFamily>
      <deviceFamilyUniqueID>DeviceFamilyWayside_4</deviceFamilyUniqueID>
      <name>DeviceFamilyWayside_4</name>
      <device>IPHONE</device>
      <device>MAC</device>
      <deviceFamilyOptions>
         <name>false</name>
      </deviceFamilyOptions>
   </deviceFamily>
</layoutMaster>

XSL转换演示


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接