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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3920957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 13:20:04  来源:igfitidea点击:

XPath query with descendant and descendant text() predicates

xmlxpathdescendantpredicates

提问by juan234

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.

我想构造一个 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>

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.

谢谢你的帮助。

回答by Dimitre Novatchev

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 divor a table.

翻译成简单的英语:对于文档中包含字符串的任何文本节点,"abc"选择其第一个祖先,即 adiv或 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.

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

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:

当对提供的 XML 文档执行此转换时

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

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

回答by juan234

//*[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.

问题contains(//text(), "abc")在于函数转换节点集采用第一个节点。

回答by Dennis Münkle

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?

这有帮助吗?