我有一些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
我做错了什么?
答案 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