【问题标题】:XPath query with descendant and descendant text() predicates带有后代和后代 text() 谓词的 XPath 查询
【发布时间】:2011-04-24 16:08:09
【问题描述】:

我想构造一个返回“div”或“table”元素的 XPath 查询,只要它有一个包含文本“abc”的后代。需要注意的是,它不能有任何 div 或 table 后代。

<div>
  <table>
    <form>
      <div>
        <span>
          <p>abcdefg</p>
        </span>
      </div>
      <table>
        <span>
          <p>123456</p>
        </span>
      </table>
    </form>
  </table>
</div>

所以这个查询的唯一正确结果是:

/div/table/form/div 

我最好的尝试是这样的:

//div[contains(//text(), "abc") and not(descendant::div or descendant::table)] | //table[contains(//text(), "abc") and not(descendant::div or descendant::table)]

但没有返回正确的结果。

感谢您的帮助。

【问题讨论】:

    标签: xml xpath descendant predicates


    【解决方案1】:

    不同的东西::)

    //text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1]
    

    似乎比其他解决方案短很多,不是吗? :)

    翻译成简单的英语:对于文档中包含字符串"abc" 的任何文本节点,请选择其第一个祖先,即divtable

    这样效率更高,因为只需要对文档树进行一次完整扫描(而不需要任何其他),并且与 descendent:: 相比,ancestor::* 遍历非常便宜(树) 扫描。

    要验证此解决方案“确实有效”:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="/">
      <xsl:copy-of select=
      "//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] "/>
     </xsl:template>
    </xsl:stylesheet>
    

    在提供的 XML 文档上执行此转换时

    <div>
      <table>
        <form>
          <div>
            <span>
              <p>abcdefg</p>
            </span>
          </div>
          <table>
            <span>
              <p>123456</p>
            </span>
          </table>
        </form>
      </table>
    </div>
    

    产生想要的正确结果

    <div>
       <span>
          <p>abcdefg</p>
       </span>
    </div>
    

    注意:不必使用 XSLT——任何 XPath 1.0 主机——例如 DOM,都必须获得相同的结果。

    【讨论】:

    • 感谢您的回复并感谢您的 +1。我更喜欢这个答案的紧凑性,但是我无法让它在我的测试中工作。对这个问题的其他两个答复对我有用。你的回复有可能有错别字吗?我不能声称了解所有这一切。 [1] 有什么作用?同样,如果您对为什么这个答案对我和其他人不起作用有任何见解,我将不胜感激。我会为您的时间 +1,但我是这个网站的新手,还没有能力。谢谢。
    • @juan234:我在答案中添加了一些验证码,每个人都可以运行并验证结果的正确性。这个验证显示了表达式的正确性——没有 no 拼写错误。由于不同的原因,您可能会遇到问题:从使用不兼容的 XPath 1.0 引擎到您的代码中的问题——找出需要查看您的代码的原因。 [1] 表示由紧靠[1] 右侧的部分表达式选择的节点集中的第一个节点——在反向轴上(例如ancestor:: 它实际上表示文档顺序中的最后一个节点)。
    • 我知道这是旧的......但我只是在寻找在后代中进行文本匹配的不同方法时偶然发现了这一点......这是优雅且易于理解的。 ..但足够聪明,我必须先看到它,现在我对 xpath 有了更多了解 :)
    • @DanNguyen,是的,XPath 是一种迷人的语言。如果您对此主题感兴趣,我会厚颜无耻地推荐我的课程:“XSLT 2.0 和 1.0 基础”(pluralsight.com/courses/xslt-foundations-part1)——涵盖 XPath 1.0 和 XPath 2.0,以及课程“XPath 的演变:XPath 3.0 的新功能” " (pluralsight.com/courses/xpath-3-0-whats-new) -- 涵盖 XPath 3.0
    【解决方案2】:
    //*[self::div|self::table] 
       [descendant::text()[contains(.,"abc")]]  
       [not(descendant::div|descendant::table)]
    

    contains(//text(), "abc") 的问题是函数转换节点集获取第一个节点。

    【讨论】:

      【解决方案3】:

      你可以试试:

      //div[
        descendant::text()[contains(., "abc")] 
        and not(descendant::div or descendant::table)
      ] | 
      //table[
        descendant::text()[contains(., "abc")] 
        and not(descendant::div or descendant::table)
      ]
      

      这有帮助吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-09
        • 1970-01-01
        • 2018-09-13
        • 2018-08-24
        • 1970-01-01
        • 1970-01-01
        • 2011-08-14
        • 1970-01-01
        相关资源
        最近更新 更多