2011-06-16 64 views
4

我有一些xml文件,我想將一個xml文件的內容插入到另一個文件中。我想我會使用LastChild和InsertAfter方法來完成這個。到目前爲止,它不適合我。如何在PowerShell中使用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> 

我想要做的就是選擇fileAsset節點(S)從parent.xml中的最後fileAsset節點之後,從child.xml插入到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

我在做什麼錯?

回答

6

您需要通過$childnode的孩子迭代,從他們的父母將其刪除,並追加到$parentnode之前它們導入到新文檔上下文($child$parent不同XmlDocument實例)。

這會將所有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)也可以工作,但會做得有點不同,因爲它還需要對將要插入的節點的引用。

+0

嗨喬爾,感謝您的好評。你的代碼工作得很好! – Keith 2011-06-17 20:43:26

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