带有后代和后代 text() 谓词的 XPath 查询

发布于 2024-09-27 01:54:25 字数 761 浏览 1 评论 0原文

我想构造一个 XPath 查询,它将返回“div”或“table”元素,只要它有包含文本“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)]

但没有返回正确的结果。

感谢您的帮助。

I would like to construct an XPath query that will return a "div" or "table" element, so long as it has a descendant containing the text "abc". The one caveat is that it can not have any div or table descendants.

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

So the only correct result of this query would be:

/div/table/form/div 

My best attempt looks something like this:

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

but does not return the correct result.

Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

赏烟花じ飞满天 2024-10-04 01:54:25

有些不同::)

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

看起来比其他解决方案短很多,不是吗? :)

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

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

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

<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,都必须获得相同的结果。

Something different: :)

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

Seems a lot shorter than the other solutions, doesn't it? :)

Translated to simple English: For any text node in the document that contains the string "abc" select its first ancestor that is either a div or a table.

This is more efficient, as only one full scan of the document tree (and not any other) is required, and the ancestor::* traversal is very cheap compared to a descendent:: (tree) scan.

To verify that this solution "really works":

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

when this transformation is performed on the provided XML document:

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

the wanted, correct result is produced:

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

Note: It isn't necessary to use XSLT -- any XPath 1.0 host -- such as DOM, must obtain the same result.

在巴黎塔顶看东京樱花 2024-10-04 01:54:25
//*[self::div|self::table] 
   [descendant::text()[contains(.,"abc")]]  
   [not(descendant::div|descendant::table)]

contains(//text(), "abc") 的问题是函数强制转换采用第一个节点的节点集。

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

The problem with contains(//text(), "abc") is that functions cast node sets taking the first node.

枯叶蝶 2024-10-04 01:54:25

你可以试试:

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

这有帮助吗?

you could try:

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

does that help?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文