【问题标题】:XQuery 3: Count occurrences of element names across documentXQuery 3:计算文档中元素名称的出现次数
【发布时间】:2021-08-25 20:04:20
【问题描述】:

基于Count number of elements with same tag

我将使用 BaseX 9.5.2 运行此查询。

给定数据

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book category="COOKING">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
    </book>
    <book category="CHILDREN">
        <title lang="en">Harry Potter</title>
        <author>J K. Rowling</author>
    </book>
    <book category="WEB">
        <title lang="en">XQuery Kick Start</title>
        <author>James McGovern</author>
        <author>Per Bothner</author>
        <author>Kurt Cagle</author>
        <author>James Linn</author>
        <author>Vaidyanathan Nagarajan</author>
    </book>
    <book category="WEB">
        <title lang="en">Learning XML</title>
        <author>Erik T. Ray</author>
    </book>
</bookstore>

我想生成这样的表格

+----------+--------------+
|          |              |
| Element  | total_count  |
+----------+--------------+
|          |              |
| title    | 4            |
+----------+--------------+
|          |              |
| author   | 8            |
+----------+--------------+

我可以得到一个唯一元素名称的列表

let $sep := '&#09;' (: tab :)

for $elems in doc(
  'books'
)/bookstore/book/*

let $currname := name(
  $elems
)

group by $currname

return string-join(
       (
        $currname
       ),
       $sep
)

也就是说,

title
author

我想我想用count(),但我不知道该怎么说我要数父书。在上面提到的我回答的问题中,要计数的元素名称在查询中是硬编码的。在这种情况下,我使用的是通配符。

【问题讨论】:

    标签: xml grouping xquery counting basex


    【解决方案1】:

    我正在使用 BaseX v.9.5.2

    请尝试以下 XQuery。

    XQuery

    xquery version "3.1";
    
    declare context item := document {
    <bookstore>
        <book category="COOKING">
            <title lang="en">Everyday Italian</title>
            <author>Giada De Laurentiis</author>
        </book>
        <book category="CHILDREN">
            <title lang="en">Harry Potter</title>
            <author>J K. Rowling</author>
        </book>
        <book category="WEB">
            <title lang="en">XQuery Kick Start</title>
            <author>James McGovern</author>
            <author>Per Bothner</author>
            <author>Kurt Cagle</author>
            <author>James Linn</author>
            <author>Vaidyanathan Nagarajan</author>
        </book>
        <book category="WEB">
            <title lang="en">Learning XML</title>
            <author>Erik T. Ray</author>
        </book>
    </bookstore>
    };
    
    <root>
    {
      let $title := count(./bookstore/book/title)
      let $author := count(distinct-values(./bookstore/book/author))
      return <r>
        <title>{$title}</title>
        <unique_author_count>{$author}</unique_author_count>
      </r>
    }
    </root>
    

    XQuery #2

    declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
    
    declare option output:method 'text';
    declare option output:item-separator '&#10;';
        
    declare context item := document {
    <bookstore>
        <book category="COOKING">
            <title lang="en">Everyday Italian</title>
            <author>Giada De Laurentiis</author>
        </book>
        <book category="CHILDREN">
            <title lang="en">Harry Potter</title>
            <author>J K. Rowling</author>
        </book>
        <book category="WEB">
            <title lang="en">XQuery Kick Start</title>
            <author>James McGovern</author>
            <author>Per Bothner</author>
            <author>Kurt Cagle</author>
            <author>James Linn</author>
            <author>Vaidyanathan Nagarajan</author>
        </book>
        <book category="WEB">
            <title lang="en">Learning XML</title>
            <author>Erik T. Ray</author>
        </book>
    </bookstore>
    };
    
    let $sep := '&#09;' (: tab :)
    
    for $elems in ./bookstore/book/*
    let $currname := local-name($elems)
    group by $currname
    return string-join(($currname, count(distinct-values($elems[local-name()=$currname])),$sep))
    

    【讨论】:

    • 感谢您的回复,但我想要一个可概括的查询,以发现不同类型的元素,这些元素显示为像 /bookstore/book 这样的根的子元素,并计算每个元素的出现次数。这将包括此输入的标题和作者元素。您已将元素类型硬编码到您的解决方案中。
    • @MarkMiller,您需要非常明确您的目标。它应该是一个最小的可重现示例。对于您的情况,它意味着以下内容:(1)输入 XML。 (2) 您的逻辑,以及试图实现它的 XQuery。 (3) 基于上述#1 的期望输出。 (4) XQuery 处理器及其版本。
    • 我非常感谢您的贡献,但最小可重现查询的所有这些部分都存在。 @Martin Honen 和我现在正在 xquery fiddle 中解决它。
    • @MarkMiller, #1 ne #3
    • 谢谢,这很有帮助。现在计数是正确的,但连接不是我所期望的。 “title4”,后跟四个选项卡,出现在第一行,“author8”,后跟八个选项卡,出现在第二行。我会继续尝试。
    【解决方案2】:

    由于您已经进行了分组,count($elems) 将在 return 子句中具有正确的值。

    我认为您最初使用 let $sep 会导致问题,我建议的分组 count($elems)https://xqueryfiddle.liberty-development.net/bFDbxm7 对我来说效果很好,我已将 $sep 移动到声明的变量中。

    【讨论】:

    • 我将返回块更新为 return string-join(($currname, count($elems) ), $sep),但得到“预期项目,找到序列...”
    • 这可能是由于$sep的错误绑定,我认为不是count($elems)的添加导致了这种情况。
    • 不适合我使用 Saxon xqueryfiddle.liberty-development.net/bFDbxm7/1,稍后将使用 BaseX 进行检查。
    • BaseX 将您最初的尝试重写为例如distinct-values(document { ... }/bookstore/book/* ! name(.)) 这样您就不会收到关于 $sep 被绑定到多个项目的序列的错误。
    • for子句之前的let子句中变量的绑定变化是由group by子句引起的,与序列化或输出格式无关。
    猜你喜欢
    • 1970-01-01
    • 2018-10-19
    • 2022-11-30
    • 2014-07-08
    • 2022-11-22
    • 2020-06-09
    • 2020-02-04
    • 1970-01-01
    相关资源
    最近更新 更多