XPath:使用单个路径表达式查询查找重复n次的节点

时间:2014-02-09 21:05:42

标签: xpath xquery exist-db

我正在练习编写一些XPath查询,并且陷入了困境。以下是我正在使用的示例文档:

<dept-db>
  <dept>
    <name>HR</name>
      <emp>
        <name>John</name>
        <country>USA</country>
      </emp>
      <emp>
        <name>Chris</name>
        <country>USA</country>
      </emp>
  </dept>
  <dept>
    <name>Technology</name>
    <emp>
      <name>Oliver</name>
      <country>UK</country>
    </emp>
    <emp>
      <name>Emily</name>
      <country>USA</country>
    </emp>
  </dept>
</dept-db>

我想要实现的是检索其国家/地区在文档中出现两次以上的所有员工。我从一个更简单的查询开始,即一个应该找到重复的查询:

<!-- language: lang-xsl -->
doc("emp.xml")//emp[preceding::emp/country=./country or following::emp/country=./country]

尽管它会返回所有员工(显然Oliver不应列在结果中)。

我是XPath的新手,我不太确定我是否得到了点''的概念。说明权。我希望上述查询的行为如下:迭代一组emp节点,并检查每个检查是否有一个员工在文档中当前一个节点上方和下方显示的节点中具有相同的国家/地区。

我会感谢一个解释(点说明符的应用程序来执行GROUP BY类查询)并帮助使查询工作(除非单个路径表达式不可能?)。如果重要的话,我正在使用eXide(eXist-db 2.1的一部分)和XQuery 3.0来执行查询。

3 个答案:

答案 0 :(得分:4)

在XPath 2.0中,您可以执行

//emp[count(index-of(//country/text(), country/text())) > 2]

index-of将在整个文档中指出country/text()出现的索引,然后我们需要做的就是对它们进行计数并检查是否有超过2个。

答案 1 :(得分:3)

如果您坚持使用XQuery 1.0,则可以在单个表达式中执行此操作,但需要将源文档绑定到变量。我使用过$src。这是有效的,因为您有效地访问源文档两次并加入谓词:

$src//emp[let $emp-country := country return count($src//data(country)[. = $emp-country]) > 2]

您也可以重写一下,以使其更清晰:

let $all-countries := $src//data(country)
return
    $src//emp[let $emp-country := country return count($all-countries[. = $emp-country]) > 2]

答案 2 :(得分:2)

由于你能够使用XQuery 3.0的group by条款,我会为此而努力。此查询按国家/地区对员工进行分组,仅返回发生次数超过两次的国家/地区:

for $employee in //emp
let $country := $employee/country
group by $country
where count($employee) > 2
return $employee

关于你的方法:

  • 我无法重现您的查询的任何问题。使用eXist DB的在线演示,我在结果中没有得到任何“Oliver”。使用BaseX和Zorba也可以正常工作。您确定文档中没有第二位英国员工吗?
  • 您写道“其国家/地区出现了两次以上”:这就是我在上面实施的内容。查看您的查询,您可能想要“至少两次”?如果是这样,请更改where子句以满足您的要求。如果没有,您的查询中的问题是您可能希望使用and而不是or,但这将省略该国家/地区的第一个和最后一个员工。