如何使用PowerShell与XPath判断XML节点是否拥有指定层级的共同祖先
高效统计共享同一祖先的节点数量
原来的循环逐次对比方式确实只能两两判断,不够高效。我们可以结合XPath和PowerShell的分组功能,直接实现按祖先节点统计
方案一:通过XPath直接定位祖先并统计
我们可以先选中TOP下的所有直接子节点(也就是你要找的目标祖先A和B),然后对每个祖先节点统计其下所有<match>的数量:
[xml] $xml = "<TOP> <A> <X><match>yes</match></X> <X><match>yes</match></X> <Y><match>yes</match></Y> </A> <B> <X><match>yes</match></X> <Z><match>yes</match></Z> </B> </TOP>" # 遍历TOP的所有直接子节点(A、B),统计每个节点下的match数量 $xml.SelectNodes("//TOP/*") | ForEach-Object { $ancestorName = $_.Name $matchCount = $_.SelectNodes(".//match").Count Write-Host "祖先节点 <$ancestorName> 下共有 $matchCount 个 <match> 节点" }
执行这段代码会直接输出:
祖先节点 <A> 下共有 3 个 <match> 节点 祖先节点 <B> 下共有 2 个 <match> 节点
方案二:先获取所有,再按祖父节点分组统计
如果你还是想先拿到所有<match>节点,再进行分组统计,可以用PowerShell的Group-Object功能,自动按祖父节点(也就是你说的上两层父节点)归类:
[xml] $xml = "<TOP> <A> <X><match>yes</match></X> <X><match>yes</match></X> <Y><match>yes</match></Y> </A> <B> <X><match>yes</match></X> <Z><match>yes</match></Z> </B> </TOP>" $matches = $xml.SelectNodes("//match") # 按match节点的祖父节点(ParentNode.ParentNode)分组 $matches | Group-Object -Property { $_.ParentNode.ParentNode.Name } | ForEach-Object { Write-Host "祖先节点 <$($_.Name)> 下共有 $($_.Count) 个 <match> 节点" }
这个方案的输出和上面完全一致,而且代码更简洁,不需要手动维护previous变量来逐次对比。
关于你尝试的XPath表达式问题
你之前写的/TOP/A[//X[1]/match][//X[2]/match]逻辑有问题,因为//X[1]/match是全局范围内第一个<X>下的<match>,不是A节点下的。如果要筛选出包含多个<match>的祖先节点,可以用这个XPath:
/TOP/*[count(.//match) > 1]
它会选中TOP下所有包含至少2个<match>的子节点,也就是你的例子中的A和B。
内容的提问来源于stack exchange,提问作者Trond
相关产品推荐
相关产品推荐

