首页 文章

Xpath选择祖先

提问于
浏览
4

我试图找到一个公式,根据它在XML层次结构中的位置为元素创建一个URL .

这是我的示例xml:

<Xml>
    <Site Url="http://mysite.abc">
        <Content></Content>
        <SubSites>
            <Site Url="/sub1">
                <Content></Content>
                <SubSites>
                    <Site Url="/sub2">
                        <Content></Content>
                        <SubSites>
                            <Site Url="/sub3">
                                <Content></Content>
                            </Site>
                        </SubSites>
                    </Site>
                </SubSites>
            </Site>
        </SubSites>
    </Site>
</Xml>

我在Powershell中有一个函数,从顶部和每个'Content'元素递归迭代我想要生成祖先Url值的串联 . 因此它应该为每个“内容”节点连续生成:

http://mysite.abc
http://mysite.abc/sub1
http://mysite.abc/sub1/sub2
http://mysite.abc/sub1/sub2/sub3

我现在用作开头:( $ Node ='Content'元素)

$Sites = $Node | Select-XML -XPath  "//ancestor::Site"

但是对于每个$ Node,它选择所有'Site'元素 . 它期望它在xml结构中找到更多的祖先 .

如果有人知道如何将值直接与Xpath连接起来会特别好,但对于初学者来说,我很乐意知道我当前的方法出了什么问题 .

2 回答

  • 1

    //ancestor::Site 将为您提供相对于树中任何节点( // )的祖先 Site 节点 .

    使用 ./ancestor::Site 仅获取相对于当前节点的祖先( . ):

    $Sites = $Node | Select-XML -XPath  "./ancestor::Site"
    
  • 4

    提供Mathias R. Jessen's helpful answer的替代方案(这可以很好地解释您的方法的问题并提供有效的解决方案):

    由于任何给定的 Content 节点的 Site nodes seem to always be the parent node ,您可以简单地 refer to the respective Site node with an .. path component .

    这种方法允许你 process the entire document at once

    Select-Xml -LiteralPath sample.xml -XPath  "//Content/.." | ForEach-Object -Begin {
        $ancestralUrl = ''
      } -Process {
        $thisUrl = $_.Node.Url
        if ($thisUrl -match '^https?://') {
          $ancestralUrl = $thisUrl
        } else {
          $thisUrl = $ancestralUrl += $thisUrl
        }
        $thisUrl
      }
    

    以上产量:

    http://mysite.abc
    http://mysite.abc/sub1
    http://mysite.abc/sub1/sub2
    http://mysite.abc/sub1/sub2/sub3
    

    事实上,你甚至可以 combine the above approach with the ancestor function (尽管在这里会有点过分):

    Select-Xml -LiteralPath sample.xml '//Content/ancestor::Site' | ForEach-Object -Begin {
      $ancestralUrl = ''
    } -Process {
      $thisUrl = $_.Node.Url
      if ($thisUrl -match '^https?://') {
        $ancestralUrl = $thisUrl
      } else {
        $thisUrl = $ancestralUrl += $thisUrl
      }
      $thisUrl
    }
    

相关问题