如何在PowerShell中使用InsertAfter

时间:2011-06-16 22:51:26

标签: powershell insertafter

我有一些xml文件,我想将一个xml文件的内容插入到另一个文件中。我以为我会使用LastChild和InsertAfter方法来完成此任务。到目前为止它对我不起作用。

这是parent.xml文件:

<manifest>
  <manifestExecution>
    <assetDetail>
      <fileAsset fileAssetGuid="parentguid1">
    <parentfile1 />
      </fileAsset>
      <fileAsset fileAssetGuid="parentguid2">
    <parentfile2 />
      </fileAsset>
    </assetDetail>
  </manifestExecution>
</manifest>

这是child.xml文件:

<manifest>
  <manifestExecution>
    <assetDetail>
     <fileAsset fileAssetGuid="childguid1">
    <childfile1 />
     </fileAsset>
    </assetDetail>
  </manifestExecution>
</manifest>

我想要做的是从child.xml中选择 fileAsset 节点,并在parent.xml中的最后一个 fileAsset 节点之后插入parent.xml。

这是我的测试代码:

$parent = [xml] (Get-Content d:\temp\parent.xml)
$parentnode = $parent.manifest.manifestExecution.assetDetail
$child = [xml] (Get-Content d:\temp\child.xml)
$childnode = $child.manifest.manifestExecution.assetDetail.InnerXml
$parentnode.InsertAfter($childnode, $parentnode.LastChild)

以下是我收到的错误信息:

Cannot convert argument "0", with value: "<fileAsset fileAssetGuid="childguid1"> <childfile1 /></fileAsset>", for "InsertAfter" to type "System.Xml.XmlNode": "Cannot conver t the "<fileAsset fileAssetGuid="childguid1"><childfile1 /></fileAsset>" value of type "System.String" to type "System.Xml.XmlNode"." At line:5 char:24 + $parentnode.InsertAfter <<<< ($childnode, $parentnode.LastChild) + CategoryInfo : NotSpecified: (:) [], MethodException + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

我做错了什么?

2 个答案:

答案 0 :(得分:6)

您需要遍历$childnode的子项,将其从父项中删除,然后将它们导入新的文档上下文($child$parent不同XmlDocument实例)在追加$parentnode之前。

这会将fileAsset中的所有$childnode个节点附加到$parentnode

$parent = [xml](get-content d:\temp\parent.xml)
$parentnode = $parent.manifest.manifestexecution.assetdetail
$child = [xml](get-content d:\temp\child.xml)
$childnode = $child.manifest.manifestexecution.assetdetail

while ($childnode.haschildnodes) {
  $cn = $childnode.firstchild
  $cn = $childnode.removechild($cn)
  $cn = $parentnode.ownerdocument.importnode($cn, $true)
  $parentnode.appendchild($cn)
}

幸运的是,大多数这些方法返回相同的XmlNode或新版本,因此while循环的主体可以像这样链接在一起:

$parentnode.appendchild( $parentnode.ownerdocument.importnode( $childnode.removechild( $childnode.firstchild ), $true ))

InsertAfter(newChild,referenceChild)也可以工作,但会有所不同,因为它还需要引用它之后插入的节点。

答案 1 :(得分:0)

你的第一个问题是你没有得到一个XML元素,而是一个字符串。您需要从XML文档中获取XML节点,但您使用的速记方法是猜测您需要一个字符串。通常你可以通过将它显式地转换为[System.Xml.XmlElement]来强制它,但这并不总是有效。您可以使用“SelectSingleNode”可靠地获取元素。

你还没有遇到第二个问题,但它就在眼前。一旦获得了XML,它仍然无法工作,因为它来自不同的XML文档,因此您需要“导入”该节点。您需要调整它以使XML与您想象的方式保持一致,但代码可以正常工作。

$parentString = @"
<manifest>
  <manifestExecution>
    <assetDetail>
      <fileAsset fileAssetGuid="parentguid1">
    <parentfile1 />
      </fileAsset>
      <fileAsset fileAssetGuid="parentguid2">
    <parentfile2 />
      </fileAsset>
    </assetDetail>
  </manifestExecution>
</manifest>
"@
$childString = @"
<manifest>
  <manifestExecution>
    <assetDetail>
     <fileAsset fileAssetGuid="childguid1">
    <childfile1 />
     </fileAsset>
    </assetDetail>
  </manifestExecution>
</manifest>
"@

$parent = [xml] ($parentString)
$parentnode = $parent.manifest.manifestExecution.assetDetail
$child = [xml] ($childString)
$xpath = '/manifest/manifestExecution/assetDetail'
$childnode = $child.SelectSingleNode($xpath)
Write-Host("So the child is $($childnode.OuterXML)")
$importedNode = $parent.ImportNode($childNode,$true)
Write-Host("And after importing: $($importedNode.OuterXML)")
$parentnode.InsertAfter($importednode, $parentnode.LastChild)
Write-Host("To finally yield: $($parent.OuterXML)")

此外,如果您正确地将其转换为XmlElement,您可能会发现可以使用类似原始代码的内容。

$childnode = [System.Xml.XmlElement]$child.manifest.manifestExecution.assetDetail.InnerXml