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
XPath query with descendant and descendant text() predicates
提问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?
这有帮助吗?

