2016-07-20 119 views
1

如果我有像XML文件:解析XML在PowerShell中

<?xml version="1.0" encoding="utf-8"?> 
<package date-created="19/07/2016" version="6" system="6"> 
    <description /> 
    <system /> 
    <res id="1057002654" name="ABC" path="/DEF" type="F" mimeType="application/x-shared"> 
    <description /> 
    <keywords /> 
    <resver id="1057014163" major="1" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057014677" major="2" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057015106" major="3" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057016183" major="4" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057016374" major="5" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057017622" major="6" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057017704" major="7" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057017863" major="8" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    </res> 
</package> 

可能有几百个项目,以及其中可能有一个或多个。在Powershell中,我试图寻找最后的resver id值,其中res ID等于。

我开始了与此:

$path = 'C:\TEST\package.xml' 
$myxml = [xml](Get-Content $path) 
$node = $myxml.package.res.resver | where {$_.id -eq "1057002654"} 
$node.id = '123' 
$myxml.Save($path) 

这只是一个简单的测试,看看我能得到我想要的位和更新,但失败:

Property 'id' cannot be found on this object; make sure it exists and is settable. 

那么我想是这样的:

$xml = [xml](Get-Content 'C:\TEST\package.xml') 
$nodes = $xml.SelectNodes("//*[@res]") 
foreach ($node in $nodes) { 

$node.Attributes | %{$_} > C:\TEST\disk.txt } 

这实际上在所有属性的值写入到一个txt文件,但不能看m找到一种方法来真正做我想做的事。

/编辑 - 更正了我的实际意图。结束了这样的代码,其中$参考是在阵列$参考

foreach ($Ref in $References) 
{ 
    $xml = [xml](Get-Content 'C:\TEST\package.xml') 
    $res = $xml.SelectSingleNode('//res[@id = $Ref]/child::resver') 
    $resource = $res.id + ".txt" 

    # more stuff here 
} 

项目收到此错误,但:

Exception calling "SelectSingleNode" with "1" argument(s): "Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function." 
At C:\TEST\script.ps1:22 char:38 
+ [string] $res = $xml.SelectSingleNode <<<< ('//res[@id = $Ref]/child::resver') 
    + CategoryInfo   : NotSpecified: (:) [], MethodInvocationException 
    + FullyQualifiedErrorId : DotNetMethodException 
+5

你应该[不使用正则表达式(http://stackoverflow.com/a/1732454/52598)来解析XML,但XPath或XQuery的。 fwiw - 我可以推荐RegexBuddy更好地感受正则表达式*(不是附属的,但是狂热的用户)*。编写xquery留作练习*(阅读为:不是我的一杯茶,很抱歉)* –

+2

这不是有效的XML,节点名称本身不能有一个属性值(并且'='不允许作为名称的一部分) –

+0

@LievenKeersmaekers - 为真正的垃圾问题道歉。我已经完全重构了它,所以如果你能看一看,我们将不胜感激。 – hshah

回答

3

使用parent::轴找到合适的父使用正确的ID定位<resver />节点后的节点:

$path = 'C:\TEST\package.xml' 
$myxml = [xml](Get-Content $path) 
# Locate resver, select parent res node 
$res = $myxml.SelectSingleNode('//resver[@id = "1057014163"]/parent::res') 
# Update id 
$res.SetAttribute('id','123') 
# Save document 
$myxml.Save($path) 

你也可以使用..别名父节点:

//resver[@id = "1057014163"]/.. 

或者as PetSerAl notes,选择具有所描述的子节点res节点:

//res[resver/@id = "1057014163"] 

为了做它的其他方式(全部找到resver子节点id基于父节点的值id):

$ids = $myxml.SelectNodes('//res[@id = "1057002654"]/resver[@id]') |Select -Expand id 

(注意使用SelectNodes()而非SelectSingleNode()

+0

感谢你和@PetSerAl。一直让我疯狂的年龄! :) – hshah

+0

对不起,在我的问题中增加了一点点,因为我意识到我是一个白痴,反过来看着它。我有res ID并需要最后的resver id。得到的代码,但它给我的错误:( – hshah

+0

@hshah看到更新 –