提问人:nickf 提问时间:4/6/2009 最后编辑:Keavonnickf 更新时间:12/6/2018 访问量:188460
XPath 选择多个标签
XPath to select multiple tags
问:
给定这种简化的数据格式:
<a>
<b>
<c>C1</c>
<d>D1</d>
<e>E1</e>
<f>don't select this one</f>
</b>
<b>
<c>C2</c>
<d>D2</d>
<e>E1</e>
<g>don't select me</g>
</b>
<c>not this one</c>
<d>nor this one</d>
<e>definitely not this one</e>
</a>
您将如何选择作为元素子级的所有 s、s 和 s?C
D
E
B
基本上,像这样:
a/b/(c|d|e)
在我自己的情况下,导致选择那些 , , 节点的查询实际上非常复杂,所以我想避免这样做:a/b/
C
D
E
a/b/c|a/b/d|a/b/e
这可能吗?
答:
52赞
annakata
4/6/2009
#1
您可以通过属性测试来避免重复:
a/b/*[local-name()='c' or local-name()='d' or local-name()='e']
与 Dimitre 的反对意见相反,在 OP 没有指定与命名空间的交互的真空中,上述内容并不正确。轴是命名空间限制的,不是。如果 OP 的意图是捕获任何命名空间(考虑到问题的 OR 性质,我认为这甚至是一种可能的情况),那么它是“另一个仍然有一些赞成票的答案”,这是不正确的。self::
local-name()
c|d|e
没有定义,你就不能确定,尽管如果 OP 澄清了他的问题,我很乐意删除我的答案,因为我真的不正确。
评论
3赞
Charles Duffy
10/18/2010
作为第三方,我个人认为 Dimitre 的建议是更好的做法,除非用户有明确(和充分)的理由关心与命名空间无关的标签名称;如果有人对我混合在不同命名空间内容中的文档(可能打算由不同的工具链读取)这样做,我会认为他们的行为非常不合适。也就是说,正如你所建议的,这个论点有点不合时宜。
5赞
Ghostrider
5/26/2012
正是我想要的。XML 命名空间在现实生活中的使用方式是一团糟。由于无法指定 /a/b/(:c|:d|*e) 之类的内容,您的解决方案正是所需要的。纯粹主义者可以随心所欲地争论,但用户并不在乎应用程序是否中断,因为无论生成输入文件的内容都搞砸了命名空间。他们只是希望它起作用。
7赞
meustrus
1/10/2014
我只模糊地知道这两个答案之间有什么区别,没有人费心去解释。“namespace restrictive”是什么意思?如果我使用 ,这是否意味着它将匹配具有任何命名空间的标签?如果我使用 ,它必须匹配什么命名空间?我怎么只匹配?local-name()
self::
OhMy:c
-3赞
Calvin
4/6/2009
#2
不确定这是否有帮助,但使用 XSL,我会做这样的事情:
<xsl:for-each select="a/b">
<xsl:value-of select="c"/>
<xsl:value-of select="d"/>
<xsl:value-of select="e"/>
</xsl:for-each>
并且此 XPath 不会选择 B 节点的所有子节点:
a/b/*
评论
0赞
nickf
4/6/2009
感谢 Calvin,但我没有使用 XSL,实际上 B 下面还有更多我不想选择的元素。我将更新我的示例以使其更清晰。
0赞
Calvin
4/6/2009
哦,好吧,在这种情况下,annakata 似乎有解决方案。
256赞
Dimitre Novatchev
4/7/2009
#3
一个正确答案是:
/a/b/*[self::c or self::d or self::e]
请注意,这
a/b/*[local-name()='c' or local-name()='d' or local-name()='e']
既太长又不正确。此 XPath 表达式将选择如下节点:
OhMy:c
NotWanted:d
QuiteDifferent:e
评论
2赞
Guasqueño
11/27/2015
'or' 不适用于 for-each,您需要使用垂直线代替 '|'
9赞
Dimitre Novatchev
11/27/2015
@Guasqueño 是一个逻辑运算符 -- 它对两个布尔值进行操作。XPath 联合运算符在两组节点上运行。这些是完全不同的,每个都有特定的用例。使用可以解决原来的问题,但它会导致更长、更复杂、更具有挑战性的理解 XPath 表达式。此答案中较简单的表达式(使用运算符)生成所需的节点集,并且可以在 XSLT 操作的“select”属性中指定。试试吧。or
|
|
or
<xsl:for-each>
5赞
Dimitre Novatchev
8/2/2018
@JonathanBenn,任何“不关心命名空间”的人其实都不关心XML,也不使用XML。只有当我们想选择具有该本地名称的所有元素时,无论元素位于哪个命名空间中,使用 of 才是正确的。这是一个非常罕见的情况 -- 一般来说,人们确实关心 和 、 或 、 、local-name()
kitchen:table
sql:table
architecture:column
sql:column
array:column
military:column
3赞
Jonathan Benn
8/2/2018
@DimitreNovatchev你说得好。我正在使用 XPath 进行 HTML 检查,这是一个命名空间不那么重要的边缘情况......
2赞
Keith Tyler
1/10/2019
这太棒了。你从哪里想出来的?
16赞
Pavel Repin
3/30/2011
#4
为什么不呢?我刚刚尝试了 Saxon XML 库(用一些 Clojure 优点很好地包裹起来),它似乎有效。 是 OP 描述的文档。a/b/(c|d|e)
abc.xml
(require '[saxon :as xml])
(def abc-doc (xml/compile-xml (slurp "abc.xml")))
(xml/query "a/b/(c|d|e)" abc-doc)
=> (#<XdmNode <c>C1</c>>
#<XdmNode <d>D1</d>>
#<XdmNode <e>E1</e>>
#<XdmNode <c>C2</c>>
#<XdmNode <d>D2</d>>
#<XdmNode <e>E1</e>>)
评论
0赞
Martin Burch
2/9/2016
这对我来说效果很好。XPath 2.0 似乎是 Python 2 上 lxml 中 HTML 解析的默认值。
0赞
Jules Kerssemakers
11/7/2023
我已经在 XPath 1.0(默认的 java/JAXB)中尝试过,但得到一个错误 该解决方案在 XPath 1.0 中有效。a/b/(c|d|e)
javax.xml.transform.TransformerException: A location step was expected following the '/' or '//' token.
a/b/[self::c or self::d]
上一个:如何合并两个 jQuery 结果
下一个:更改文件夹中的所有匹配项
评论