3

我想知道 Xquery 是否有任何类似于 distinct-values 但返回节点的函数。

让我更清楚一点:例如,我有一个参考书目,对于其中的每个作者,我想列出他写的所有书籍。在我的具体案例中,作者元素是这样的:

<author>
  <last> Shakespear </last>
  <first> William </first>
</author>

在作者上使用 distinct-values 会返回 ShakespearWilliam,据我所知,它没有帮助。我想要一个保留元素作者结构而不考虑重复的函数。

如果您找到另一种查询方式,请告诉我。有谁有想法吗?

4

2 回答 2

4

获得不同节点的一个问题是如何确定两个节点是不同的。这是 XML 中的一个复杂主题。如果重复节点将具有相同的节点标识(即:它们引用相同的节点),那么您可以使用类似functx:distinct-nodes()的函数。否则,您需要某种类型的哈希来确定节点是否“足够”以被视为相等,或者使用 deep-equal() 进行比较,这对于大型数据集表现不佳。

如果姓氏和名字相同时两个<author>s 相等,那么您可以使用像concat(last,first)哈希这样简单的东西并使用 xpath 获得不同的值:

$xml/author[index-of($xml/author/concat(last,first), concat(last,first))[1]]

这仍然不理想,因为您在每一步都在计算哈希,因此对于大型数据集它会变慢。为了提高性能,您可以做的一件事是预先计算数据的哈希值,即:

<author hash="ShakespearWilliam">
  <last>Shakespear</last>
  <first>William</first>
</author>

和:

$xml/author[index-of($xml/author/@hash, @hash)[1]]

如果您可以通过哈希有效地获取有序节点(理想情况下使用有序数据库索引),那么有一种更有效的删除重复项的方法:

declare function local:nodupes($first, $rest)
{
    if (empty($rest)) then $first
    else if ($first/@hash eq $rest[1]/@hash)
    then local:nodupes($rest[1], subsequence($rest,2))
    else ($first, local:nodupes($rest[1], subsequence($rest,2)))
};

然后用你的有序集合调用它:

let $ordered :=
  for $a in $xml/author
  order by $a/@hash
  return $a
return 
  local:nodupes((),$ordered)
于 2012-10-02T16:27:41.260 回答
2

XQuery 3.0 有一个“分组依据”结构,例如,这允许您按 (first name, last name) 的值对作者进行分组。当您对节点进行分组时,您基本上就有了答案:当且仅当它们位于不同的组中时,节点才是不同的。

周围有很多产品实现了 XQuery 3.0 草案的这一部分。Saxon 9.4 就是其中之一。

于 2012-10-02T16:54:31.283 回答