Xml XPath来匹配元素和属性
匹配属性和元素的正确XPath语法是什么 更多信息 我创建了以下函数来查找包含给定值的元素和属性:Xml XPath来匹配元素和属性,xml,powershell,xpath,attributes,element,Xml,Powershell,Xpath,Attributes,Element,匹配属性和元素的正确XPath语法是什么 更多信息 我创建了以下函数来查找包含给定值的元素和属性: function Get-XPathToValue { [CmdletBinding()] param ( [Parameter(Mandatory)] [xml]$Xml , [Parameter(Mandatory)] [string]$Value ) process {
function Get-XPathToValue {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[xml]$Xml
,
[Parameter(Mandatory)]
[string]$Value
)
process {
$Xml.SelectNodes("//*[.='{0}']" -f ($Value -replace "'","''")) | %{
$xpath = ''
$elem = $_
while (($elem -ne $null) -and ($elem.NodeType -ne 'Document')) {
$xpath = '/' + $elem.Name + $xpath
$elem = $elem.SelectSingleNode('..')
}
$xpath
}
}
}
这与元素匹配,但与属性不匹配
通过将$Xml.SelectNodes(“/*[.='{0}']”
替换为$Xml.SelectNodes(“/*[.='{0}']”)
我可以匹配属性,但不能匹配元素
示例
[xml]$sampleXml = @"
<root>
<child1>
<child2 attribute1='hello'>
<ignoreMe>what</ignoreMe>
<child3>hello</child3>
<ignoreMe2>world</ignoreMe2>
</child2>
<child2Part2 attribute2="ignored">hello</child2Part2>
</child1>
<notMe>
<norMe>Not here</norMe>
</notMe>
</root>
"@
Get-XPathToValue -Xml $sampleXml -Value 'hello'
应返回:
/root/child1/child2/attribute1
/root/child1/child2/child3
/root/child1/child2Part2
你试过什么?
我试着匹配:
-返回匹配的元素,但返回所有属性/@*|*[.='{0}']
-返回匹配的属性,但返回所有元素/*|@*[.='{0}']
-返回匹配的元素/*[.='{0}']|@*[.='{0}']”
-返回匹配的属性/@*[.='{0}']|*[.='{0}']”
-引发异常/(@*|*)[.='{0}']“
/*[.='{0}']|/*[.='{0}']
i、 e
使用以下XPath解决了这个问题:
/@*[.='{0}']|/*[.='{0}']
i、 e
您的XPath表达式派生方法有三个缺陷,如问题的注释所示
您的XPath表达式派生方法有三个缺陷,如问题的注释所示
您生成XPath字符串的算法有缺陷。当同一级别中有多个同名元素时,它就会崩溃。如果我可以问的话,它到底有什么意义?`很好,我会改进。这只是一个帮助我进行分析的实用工具。我有时必须处理大型XML文件,我必须在te中打开它们xt编辑器,找到被报告为错误的值,然后计算出相关元素的xpath,这样我就可以编写一个脚本,将该值与许多其他文件中的相同值进行比较,看看它们是否也有问题。如果我能帮上忙,我不喜欢手动操作;因此这只需要节省一点工作量。这不是任何用途的代码面向r的解决方案;只针对我的实用工具。其中还有一个缺陷。XPath没有字符串转义。你不能用
'
替换'
,一切都很好,这不是怎么回事。第三个缺陷是它完全忽略了XML名称空间。你生成XPath字符串的算法有缺陷。它会随着一旦在同一级别中有多个同名元素。如果我可以问的话,它有什么意义?`好的意义;我会改进。这只是一个帮助我进行分析的实用工具。我有时不得不处理大型XML文件,我必须在文本编辑器中打开它们,找到报告为错误的值,然后制定一个解决方案n xpath到相关元素,这样我就可以编写一个脚本,将此值与许多其他文件中的相同值进行比较,看看它们是否也有问题。如果我能帮助的话,我不喜欢手动操作;因此这只会节省一点工作量。这不是任何面向用户的解决方案的代码;只是针对我的实用工具带的代码。还有另一个fla其中w。XPath没有字符串转义。您不能用'
替换'
,一切都很好,这不是它的工作方式。第三个缺陷是它完全忽略XML名称空间。小心。当测试值-b时,XPath将选择a
和b
“
for谢谢@kjhughes;更正。最初考虑到属性不会有文本节点(不考虑其他含义)时,我没有这样做;但现在它们有单独的条件,这就更好了。小心。XPath在测试值-b时将选择a
和b
”
对于谢谢@kjhughes;更正。当我最初考虑属性没有文本节点时,我没有这样做(没有考虑其他含义);但是现在它们有了单独的条件,这就更好了。很好的一个,谢谢@Tomalak.NB:我认为上面的内容还没有涵盖名称空间?可以通过使用/*[local-name()='$($elem.name)]
轻松解决这个问题。它涵盖了名称空间,但是[local-name()='$($elem.LocalName)')和namespace-uri()='$($elem.NamespaceURI)“]
在$precedingExpr
中会更好。事实上,我们现在就包括这一点。问题是,它仍然不能生成XPath,以解决所有可能的方式在XML中声明名称空间。这是可能的,但生成的XPath变得非常臃肿。很好的一个,谢谢@Tomalak.NB:我认为上面的内容仍然不适用但是r名称空间?可以通过使用/*[local-name()='$($elem.name)]
轻松解决这个问题。它涵盖了名称空间,但是[local-name()='$($elem.LocalName)'和namespace-uri()='$($elem.NamespaceURI)
function Convert-ValueToXpath {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[xml]$Xml
,
[Parameter(Mandatory)]
[string]$Value
)
process {
$escapedValue = "concat('', '" + ($value -split "'" -join "', ""'"", '") + "')"
$Xml.SelectNodes("(//*|//@*)[normalize-space() = {0}]" -f $escapedValue) | % {
$xpath = ''
$elem = $_
while ($true) {
if ($elem.NodeType -eq "Attribute") {
$xpath = '/@' + $elem.Name
$elem = $elem.OwnerElement
} elseif ($elem.ParentNode) {
$precedingExpr = "./preceding-sibling::*[local-name() = '$($elem.LocalName)' and namespace-uri() = '$($elem.NamespaceURI)']"
$pos = $elem.SelectNodes($precedingExpr).Count + 1
$xpath = '/' + $elem.Name + "[" + $pos + "]" + $xpath
$elem = $elem.ParentNode
} else {
break;
}
}
$xpath
}
}
}
/root[1]/child1[1]/child2[1]/@attribute1
/root[1]/child1[1]/child2[1]/child3[1]
/root[1]/child1[1]/child2Part2[1]