根据给定的值集检查节点内容

时间:2009-07-30 13:08:36

标签: xml xpath

给出如下的XML文档:

<root>
    <foo>
        <bar>a</bar>
        <bar>b</bar>
        <bar>c</bar>
    </foo>
    ...
</root>

如何检索具有foo个子节点且具有特定值的所有bar个节点?

例如,如果我需要所有foo - 具有bar的元素 - 具有值ac的子元素,我目前正在使用此表达式:

//*/foo[bar/text()='a'][bar/text()='c']

这很好,但如果我有更多的“bar - 约束”它会变得笨拙,而且我不太喜欢以编程方式生成的XPath表达式:)。我正在寻找的是这些方面的东西(显然无效的语法):

//*/foo[bar/text() in-set('a', 'c')]

有什么想法吗?

5 个答案:

答案 0 :(得分:1)

您可以使用

//*/foo[bar/text()='a' or bar/text()='c']

XPath中没有'in'运算符。这是一个list of xpath operators

答案 1 :(得分:1)

目前还不完全清楚你是否想要AND或OR。带有两个过滤器的XPath示例是AND(即要求foo同时包含“a”和“c”),但对其他回复的注释似乎暗示您实际上想要一个OR(任何foo带有“a”或“c”)。使用XPath 2.0,后者非常简单:

//foo[bar[. = ('a', 'c')]]

AND有点棘手:

//foo[count(distinct-values(data(bar[. = ('a', 'c')])))) = 2]

或者,如果您要使用变量(我将展示XQuery语法,但实际上您应该使用XPath实现API为外部变量提供值):

let $values := ('a', 'c')
return //foo[count(distinct-values(data(bar[. = $values])))) = count($values)]

答案 2 :(得分:0)

如果您可以访问XPath 2.0,则可以使用matches function

//foo[fn:matches(bar, "a|c")]

不幸的是XPath 2.0并没有被广泛支持。

Tomalak的回答给了我一个想法:

//foo[bar[fn:matches(text(),"a|c")]]

这可能有用,因为它不是在节点集上工作,而是在单个文本节点上工作。

答案 3 :(得分:0)

对于“AND”表达,你或多或少地坚持你现在拥有的东西。虽然我把它写成:

//*/foo[bar/text()='a' and bar/text()='c']

对于“OR”表达式(您的问题尚不清楚),您可以尝试:

//*/foo[bar[contains(',a,c,', concat(',', text(), ','))]]

或者,更可读的是:

//*/foo[
  bar[
    contains(
      ',a,c,', 
      concat(',', text(), ',')
    )
  ]
]

这会找到<foo>元素,这些元素包含自身符合某个规则的<bar>个元素。规则是:“文本值(用逗号括起来)包含在搜索字符串中(用逗号括起来)”。

对于'a'的文字值和'a,b'的搜索字符串,您需要在',a,'内查找',a,b,'。因此,如果任何内部<bar>元素匹配,则将选择外部<foo>元素。

显然,你必须选择一个不能包含在值中的分隔符。从您的示例代码中,我选择',',但任何有效字符都可以。

答案 4 :(得分:0)

您可以偷偷摸摸地为它添加一个元素,如:

<values>
   <value>a</value>
   <value>c</value>
</values>

然后这个XPath

/root/foo[count(bar[.=/root/values/value]) = count(/root/values/value)]

将找到所有foo个元素,其中值在您的值列表中的bar子元素的数量等于该列表中的值的数量。这将起作用 - 如果所有bar元素都包含不同的值。