XPath选择多个标签

nic*_*ckf 119 xml xpath

鉴于这种简化的数据格式:

<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>
Run Code Online (Sandbox Code Playgroud)

你会如何选择所有元素的Cs,Ds和Es B

基本上,像:

a/b/(c|d|e)
Run Code Online (Sandbox Code Playgroud)

在我自己的情况,而不是只a/b/,查询导致到选择那些C,D,E节点其实是相当复杂的,所以我想避免这样做:

a/b/c|a/b/d|a/b/e
Run Code Online (Sandbox Code Playgroud)

这可能吗?

Dim*_*hev 194

一个正确的答案是:

/a/b/*[self::c or self::d or self::e]
Run Code Online (Sandbox Code Playgroud)

请注意这一点

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']
Run Code Online (Sandbox Code Playgroud)

既太长又不正确.此XPath表达式将选择以下节点:

OhMy:c

NotWanted:d 

QuiteDifferent:e
Run Code Online (Sandbox Code Playgroud)

  • @Guasqueño,`或`是一个逻辑运算符 - 它运行两个布尔值.XPath**union**运算符`|`在两组节点上运行.这些是完全不同的,每个都有特定的用例.使用`|`**可以解决原始问题,但它会导致更长,更复杂和更难以理解XPath表达式.这个答案中更简单的表达式使用`或'运算符产生有用的节点集,并且*can*可以在`<xsl:for-each>`XSLT操作的"select"属性中指定.就试一试吧. (7认同)
  • @JonathanBenn,任何"不关心命名空间"的人实际上并不关心XML,也不使用XML.如果我们想要选择具有该本地名称的所有元素,那么`local-name()`的使用是正确的,无论该元素所在的命名空间如何.这是一种非常罕见的情况 - 通常人们会关心这些差异之间:`kitchen:table`和`sql:table`,或者`architecture:column`,`sql:column`,`array:column`,`military:column`之间 (4认同)
  • '或'不适用于for-each,你需要使用垂直线代替'|' (2认同)
  • @DimitreNovatchev你说的很对。我正在使用XPath进行HTML检查,这是一个极端的情况,其中名称空间不是那么重要... (2认同)
  • 那是超级的.你在哪里想出来的? (2认同)

ann*_*ata 43

您可以使用属性测试来避免重复:

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']
Run Code Online (Sandbox Code Playgroud)

与Dimitre的对立观点相反,上述情况并非真实,其中OP尚未指定与名称空间的交互.该self::轴是命名空间限制性的,local-name()是没有的.如果OP的意图是捕获c|d|e而不管命名空间(我建议甚至可能是针对问题的OR性质的情况)那么它是"另一个仍有一些积极投票的答案",这是不正确的.

如果没有定义,你就无法确定,但如果OP澄清他的问题使我不正确,我很乐意将我的答案删除为真的不正确.

  • 我只有最简单的想法,这两个答案之间的区别是什么,没有人打扰解释."命名空间限制"是什么意思?如果我使用`local-name()`,这是否意味着它会将标签与任何命名空间匹配?如果我使用`self ::`,它必须匹配哪个命名空间?我怎么才匹配'OhMy:c`? (7认同)
  • 正是我在寻找的东西.XML名称空间在现实生活中的使用方式是一种不圣洁的混乱.由于缺乏能够指定类似/ a/b /(*:c |*:d |*e)的内容,您的解决方案正是您所需要的.纯粹主义者可以争论他们想要的一切,但是用户并不关心应用程序是否会中断,因为生成他们的输入文件会搞乱命名空间.他们只是想让它发挥作用. (4认同)
  • 在这里作为第三方发言 - 就个人而言,我发现Dimitre的建议是更好的做法,除非用户有明确(和良好)理由关心与名称空间无关的标签名称; 如果有人对我在混合了不同命名空间的内容(可能是由不同的工具链读取)的文档做了这个,我会认为他们的行为非常不合适.也就是说,这个论点 - 正如你的建议 - 有点不合适. (3认同)
  • @annakata:发布这个例子,因为这正是我所寻找的,我有理由这样做. (3认同)

Pav*_*pin 14

为什么不a/b/(c|d|e)呢?我刚刚尝试使用Saxon XML库(很好地包含了一些Clojure的优点),它似乎工作. abc.xml是OP描述的文档.

(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>>)
Run Code Online (Sandbox Code Playgroud)

  • 是的,但那是XPath 2.0 (7认同)