【问题标题】:How to count occurences of a node in XML using XQuery?如何使用 XQuery 计算 XML 中节点的出现次数?
【发布时间】:2017-09-19 21:01:05
【问题描述】:

输入文件:

<?xml version="1.0" encoding="UTF-8"?> 
        <books>
            <book id="6636551">
                <master_information>
                    <book_xref>
                        <xref type="Fiction" type_id="1">72771KAM3</xref>
                        <xref type="Non_Fiction" type_id="2">US72771KAM36</xref>
                    </book_xref>
                </master_information>
                <book_details>
                    <price>24.95</price>
                    <publish_date>2000-10-01</publish_date>
                    <description>An in-depth look at creating applications with XML.</description>
                </book_details>
            </book>
            <book id="119818569">
                <master_information>
                    <book_xref>
                        <xref type="Fiction" type_id="1">070185UL5</xref>
                        <xref type="Non_Fiction" type_id="2">US070185UL50</xref>
                    </book_xref>
                </master_information>
                <book_details>
                    <price>19.25</price>
                    <publish_date>2002-11-01</publish_date>
                    <description>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</description>
                </book_details>
            </book>
            <book id="119818568">
                <master_information>
                    <book_xref>
                        <xref type="Fiction" type_id="1">070185UK7</xref>
                        <xref type="Non_Fiction" type_id="2">US070185UK77</xref>
                    </book_xref>
                </master_information>
                <book_details>
                    <price>5.95</price>
                    <publish_date>2004-05-01</publish_date>
                    <description>After the collapse of a nanotechnology society in England, the young survivors lay the foundation for a new society.</description>
                </book_details>
            </book>
            <book id="119818567">
                <master_information>
                    <book_xref>
                        <xref type="Fiction" type_id="1">070185UJ0</xref>
                        <xref type="Non_Fiction" type_id="2">US070185UJ05</xref>
                    </book_xref>
                </master_information>
                <book_details>
                    <price>4.95</price>
                    <publish_date>2000-09-02</publish_date>
                    <description>When Carla meets Paul at an ornithology conference, tempers fly as feathers get ruffled.</description>
                </book_details>
            </book>
        </books>

我编写了 XQuery 来显示特定字段的计数,如下所示:

for $x in //book_xref
let $c := string-join(('name of element:', count($x)), '&#10;')
return $c

预期输出:

name of element: 4

但输出结果为:

name of element:
1
name of element:
1
name of element:
1
name of element:
1

之后我明白了它为什么这样做。我尝试汇总计数值,但没有成功。此外,找不到任何函数来自动获取元素的名称,以便它自动包含在字符串中。

理想情况下,目标输出是

book_xref:4

我需要什么来实现这一目标?我错过了什么?

谢谢!我很欣赏你的回应。

【问题讨论】:

    标签: xml xpath xquery


    【解决方案1】:

    concat('book_xref:', count(//book_xref)) 怎么样?

    您在输出中得到 4 个不同结果的原因是您正在迭代所有出现的 book_xref

    此外,您可以使用 $x/name() 获得名称,但由于您已经知道要选择的内容,因此没有必要。

    获取所有元素名称及其出现次数的一种简单但不是很有效的方法是:

    let $names := distinct-values(//*/name())
    for $x in $names
    let $c := concat($x, ':', count(//*[name()=$x]), '&#10;')
    return $c
    

    产生:

    books:1
    book:4
    master_information:4
    book_xref:4
    xref:8
    book_details:4
    price:4
    publish_date:4
    description:4
    

    【讨论】:

    • 有道理。谢谢!复杂的部分 - 我想知道 thingy 的名称,以便我可以扩展查询以应用于 XML 文件中的所有节点。但现在似乎比我想象的要难。如何选择所有且仅不同的节点并显示它们的出现次数?
    • 我尝试使用此代码自动获取名称let $x := //book_xref let $c := count($x) return concat($x/name(), $c),但它不起作用。怎么了?
    • @Fenil - $x 将出现 4 次 book_xref 因此当您在 concat 中执行 $x/name() 时,您应该会收到关于 concat 的第一个参数是一个或多个序列的错误字符。
    • 有道理。我现在可以让它工作了。关于您用于获取所有节点的代码,这对我的较小测试文件很有效,但由于内存分配稀缺而无法在常规大文件上执行。对于您所说的效率,如何优化这样的查询?你的有效方法是什么?
    • @Fenil:如果有帮助,请accept这个答案,并将您的新问题作为实际问题提出——它们对于基于评论的后续行动来说太重要了。谢谢。
    【解决方案2】:

    对于您的初始目标,@daniel-haley 已经有了一个简洁的解决方案。

    如果您想有效地计算文档中所有元素名称的出现次数,在 XQuery 3.0 中,您可以使用映射和 fn:fold-left(...) 函数来迭代处理所有元素并保持计数(至少在支持迭代求值的 XQuery 处理器中)永远不会同时在内存中拥有所有元素,即使是同名元素:

    fold-left(
      //*,
      map{},
      function($map, $node) {
        let $name := $node/local-name()
        return map:merge((map { $name: ($map($name), 0)[1] + 1 }, $map))
      }
    )
    

    使用group by 的更简单的解决方案更具可读性,但内存效率可能更低:

    map:merge(
      for $node in //*
      group by $name := $node/node-name()
      return map { $name: count($node) }
    )
    

    两个查询的结果相同:

    map {
      'price': 4,
      'book': 4,
      'books': 1,
      'book_details': 4,
      'master_information': 4,
      'book_xref': 4,
      'xref': 8,
      'description': 4,
      'publish_date': 4
    }
    

    【讨论】:

    • 谢谢,里奥!我是 XQuery 的新手,知道这很有帮助!感谢您的意见。
    猜你喜欢
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多