使用Xquery

时间:2019-07-13 15:56:36

标签: xquery basex

考虑父标签和子标签,我会计算所有不同的项目。

例如,如果文档包含:

    <root>
      <A value="5.1">
        <B value="3.5">
          <C value="1.4">
            <D value="0.2">
              <E value="X"/>
            </D>
          </C>
        </B>
      </A>
      <A value="5.1">
        <B value="3.5">
          <C value="1.4">
            <D value="0.4">
              <E value="Y"/>
            </D>
          </C>
        </B>
      </A>
      <A value="4.6">
        <B value="3.1">
          <C value="1.5">
            <D value="0.2">
              <E value="X"/>
            </D>
          </C>
        </B>
      </A>
      <A value="5.0">
        <B value="3.6">
          <C value="1.4">
            <D value="0.2">
              <E value="X"/>
            </D>
          </C>
        </B>
      </A>
    </root>

我将计算AB,ABC,ABCD,BCD等所有不同的项目。

我尝试了这个xquery命令,但是仅获得了单个项目的不同值:

count(distinct-values(doc('partitioncollection')/root/A/@value)) -> 3
count(distinct-values(doc('partitioncollection')/root/B/@value)) -> 3
count(distinct-values(doc('partitioncollection')/root/C/@value)) -> 2

更具体地说,如果我想计算所有可能值对的计数,结果应显示:

A/B : 3
A/B/C : 3
A/B/C/D : 4
A/B/C/D/E : 4
B/C : 3
B/C/D : 4
B/C/D/E : 4
C/D : 3
C/D/E : 3
D/E : 2

C/E : should be 3 because there are 3 distinct pairs of values: 

<C value="1.4"><E value="X"/>
<C value="1.4"><E value="Y"/>
<C value="1.5"><E value="X"/>

A/D : should be 4 because there are 4 distinct pairs of values: 

<A value="5.1"><D value="0.2">
<A value="5.1"><D value="0.4">
<A value="4.6"><D value="0.2">
<A value="5.0"><D value="0.2">
etc.

由于计算复杂,我相信创建一个以单个标记集(即A-D或C-E等)并返回计数器值的函数会更容易

1 个答案:

答案 0 :(得分:2)

我仍然不确定问题的描述是否准确(不清楚结构是否始终为A/B/C/D/E,也不清楚对于更深层次的内容是否只想比较,例如B/C是具有相同值的A的子代),但总的来说,我认为可以使用分组和递归来解决;我想出了

declare function local:distinct-descendants($elements as element()*) as xs:string*
{
    for $element-group in $elements[*]
    group by $element-name := node-name($element-group)
    let $max-depth := max($element-group/count(.//*)) + 1
    for $level in 2 to $max-depth
      let $groups := 
        for $path-group in $element-group
        group by $group-path := string-join(subsequence($path-group/descendant-or-self::*/node-name(), 1, $level), '/')
        for $value-group in $path-group
        group by $value-seq := string-join(subsequence($value-group/descendant-or-self::*/@value, 1, $level), '|')
        return head($group-path)
      for $level-group in $groups
      group by $level-path := $level-group
      order by head($level)
      return $level-path || ' : ' || count($level-group)
    ,
    if ($elements/*) then local:distinct-descendants($elements/*) else ()
};

local:distinct-descendants(root/*)

https://xqueryfiddle.liberty-development.net/nbUY4kz/4,此输出

A/B : 3
A/B/C : 3
A/B/C/D : 4
A/B/C/D/E : 4
B/C : 3
B/C/D : 4
B/C/D/E : 4
C/D : 3
C/D/E : 3
D/E : 2

使用BaseX可以得到相同的结果。

如果结构始终为A/B/C/D/E,则代码可能有点太复杂,在这种情况下,不需要node-name()上的第一个分组。

我还必须在“路径”序列(例如A/B/C)和@value序列上分组两次,也许有更简单的方法,但是我无法关联唯一的{ {1}}具有嵌套结构的序列,无需进行重复的分组。

也许

@value
https://xqueryfiddle.liberty-development.net/nbUY4kz/6

有点简单,但仍然可以完成工作。

我认为,只要子树都有一个孩子,但是前两次尝试都可以,但是如果没有,则尝试失败。因此,在子元素数量任意的一般情况下,似乎有必要计算后代的路径和值并将其分组:

declare function local:distinct-descendants($elements as element()*) as xs:string*
{
    let $max-depth := max($elements/count(descendant-or-self::*))
    for $level in 2 to $max-depth
      let $groups := 
        for $path-group in $elements
        group by 
          $group-path := string-join(subsequence($path-group/descendant-or-self::*/node-name(), 1, $level), '/'),
          $value-seq := string-join(subsequence($path-group/descendant-or-self::*/@value, 1, $level), '|')
        return head($group-path)
      for $level-group in $groups
      group by $level-path := $level-group
      order by head($level)
      return $level-path || ' : ' || count($level-group)
    ,
    if ($elements/*) then local:distinct-descendants($elements/*) else ()
};

local:distinct-descendants(root/*)

https://xqueryfiddle.liberty-development.net/nbUY4kz/14