Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XPath来匹配元素和属性_Xml_Powershell_Xpath_Attributes_Element - Fatal编程技术网

Xml 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 {

匹配属性和元素的正确XPath语法是什么

更多信息

我创建了以下函数来查找包含给定值的元素和属性:

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}']“
    -引发异常

使用以下XPath解决了这个问题:
/*[.='{0}']|/*[.='{0}']

i、 e


使用以下XPath解决了这个问题:
/@*[.='{0}']|/*[.='{0}']

i、 e


您的XPath表达式派生方法有三个缺陷,如问题的注释所示

  • 它不处理在同一级别有多个同名元素的情况
  • 它不能正确处理值中的引号
  • 它不处理XML名称空间
  • 以下是我对解决这些问题的函数的看法(我还为它命名了一个我认为在cmdlet命名方案中更合适的名称):

    对于您的示例输入,我得到以下XPath:

    /root[1]/child1[1]/child2[1]/@attribute1 /root[1]/child1[1]/child2[1]/child3[1] /root[1]/child1[1]/child2Part2[1] /根目录[1]/child1[1]/child2[1]/@attribute1 /根目录[1]/child1[1]/child2[1]/child3[1] /root[1]/child1[1]/child2Part2[1]
    您的XPath表达式派生方法有三个缺陷,如问题的注释所示

  • 它不处理在同一级别有多个同名元素的情况
  • 它不能正确处理值中的引号
  • 它不处理XML名称空间
  • 以下是我对解决这些问题的函数的看法(我还为它命名了一个我认为在cmdlet命名方案中更合适的名称):

    对于您的示例输入,我得到以下XPath:

    /root[1]/child1[1]/child2[1]/@attribute1 /root[1]/child1[1]/child2[1]/child3[1] /root[1]/child1[1]/child2Part2[1] /根目录[1]/child1[1]/child2[1]/@attribute1 /根目录[1]/child1[1]/child2[1]/child3[1] /root[1]/child1[1]/child2Part2[1]

    您生成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]