列出子节点元包含某些值123456的所有节点

时间:2015-08-05 20:19:04

标签: xml powershell xpath

如果他们的子节点元素包含Pdt 1,我希望下面的脚本输出Pdt3123456,但它不输出任何内容。什么是正确的语法?

我知道问题来自

中的错误标准语法@id='$_.id'
ForEach-Object {
    $meta = $xml.SelectSingleNode("//catalogue/produits/produit[@id='$_.id']/metas/meta[@code='$meta_code']")
}

这是整个脚本的一部分:

$xml=[xml]@'
<?xml version="1.0" encoding="iso-8859-1"?>
<catalogue>
  <produits>
    <produit id="pdt1" libelle="produit 1" cat="PDT">
      <metas date="2015.07.24">
        <meta code="123456" value="123456"></meta>
        <meta code="789012" value="ghijkl"></meta>
        <meta code="345678" value="mnopqr"></meta>
      </metas>
    </produit>
    <produit id="pdt2" libelle="produit 2" cat="PDT">
      <metas date="2015.07.24">
        <meta code="123456" value="abcdef"></meta>
        <meta code="789012" value="ghijkl"></meta>
        <meta code="345678" value="mnopqr"></meta>
      </metas>
    </produit>
    <produit id="pdt3" libelle="produit 3" cat="PDT">
      <metas date="2015.07.24">
        <meta code="123456" value="123456"></meta>
        <meta code="789012" value="ghijkl"></meta>
        <meta code="345678" value="mnopqr"></meta>
      </metas>
    </produit>
  </produits>
</catalogue>
'@

$meta_code = "123456"

$xml.catalogue.produits.produit | where {$_.cat.startsWith("PDT")} | ForEach-Object {
    $meta = $xml.SelectSingleNode("//catalogue/produits/produit[@id='$_.id']/metas/meta[@code='$meta_code']")
    if($meta) {Write-Host $_.libelle "in"  $meta.code}
}

3 个答案:

答案 0 :(得分:2)

如果将$_.id放在字符串中,PowerShell只会将$_扩展为其字符串表示形式。 .id仍然是文字字符串。要在字符串中展开当前对象的id属性,需要使用子表达式:

"//catalogue/produits/produit[@id='$($_.id)']/metas/meta[@value='$meta_code']"

据说,从它的外观来看,您要选择libelle属性以字母cat开头且包含PDT的产品的<meta>属性value属性具有变量$meta_code中指定值的节点。如果是这种情况,您可以将整个代码压缩为一个XPath expression

$meta_code = "123456"
$xpath = "//catalogue/produits/produit" +
         "[starts-with(@cat,'PDT') and metas/meta/@value='$meta_code']"
$xml.SelectNodes($xpath) | % { '{0} in {1}' -f $_.libelle, $meta_code }

答案 1 :(得分:2)

我认为问题在于您的XQuery字符串:

$meta = $xml.SelectSingleNode("//catalogue/produits/produit[@id='$_.id']/metas/meta[@code='$meta_code']")

PowerShell将$_.id解释为$_.ToString() + ".id",在您的情况下,最终为pdt1.id。当然,没有节点匹配该id。

相反,将$_.id包装为表达式$($_.id)

$meta = $xml.SelectSingleNode("//catalogue/produits/produit[@id='$($_.id)']/metas/meta[@code='$meta_code']")

或者,更好的是,使用-f字符串格式运算符:

$xquery = "//catalogue/produits/produit[@id='{0}']/metas/meta[@code='{1}']" -f $_.id,$meta_code
$meta = $xml.SelectSingleNode($xQuery)

您可以完全放弃对SelectSingleNode的调用,因为您已经在ForEach-Object脚本块中获得了该节点。您可以找到所需的元节点:

$xml.catalogue.produits.produit |
    Where-Object { $_.cat -like 'PDT*' } |
    ForEach-Object { 
        $produit = $_
        $meta = $produit.metas.meta | Where-Object { $_.code -eq $meta_code }
        if( $meta )
        {
            Write-Host -Message ('{0} in {1}' -f $produit.libelle,$meta.code)
        }
    }

答案 2 :(得分:0)

试试这个Xpath - &#34; // produits / poduit / @ id [./ meta [@code =&#39; 123456&#39;]]&#34;