使用Xquery对不同元素对进行计数

使用Xquery对不同元素对进行计数,xquery,basex,Xquery,Basex,考虑到父标签和子标签,我会计算所有不同的项目 例如,如果文档包含: <root> <A value="5.1"> <B value="3.5"> <C value="1.4"> <D value="0.2"> <E value="X"/> </D> </C&

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

例如,如果文档包含:

    <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>
更具体地说,如果我想计算所有可能值对的计数,结果应该显示:

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/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
付款:3
转交:3
D/E:2
C/E:应为3,因为有3对不同的值:
A/D:应为4,因为有4对不同的值:
等

由于计算复杂,我认为更容易创建一个函数,将其作为一组标记(即a-D或C-e等)并返回计数器的值。我仍然不确定是否准确描述了该问题(不清楚结构是否总是
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/*)
此时,输出

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
,那么代码可能有点太复杂,在这种情况下,不需要
节点-name()
上的第一个分组

我还必须在内部进行两次分组,在“路径”序列(例如,
A/B/C
)和
@value
序列上,可能有更简单的方法,但在不进行重复分组的情况下,我无法将唯一的
@value
序列和嵌套结构联系起来

或许

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/*)
at有点简单,但仍然可以完成这项工作

我认为,只要子树都有一个子元素,前两次尝试就可以正常工作,但如果没有子元素,则会中断;因此,在任意数量的子元素的一般情况下,似乎有必要从子元素计算路径和值,并将其分组:

declare variable $value-separator as xs:string external := '|';

declare function local:distinct-descendants($elements as element()*) as xs:string*
{
    for $element-group in $elements[*]
    group by $element-name := node-name($element-group)
    return
        (
            let $groups :=
                for $descendant-group in $element-group//*
                group by
                    $path-key := string-join(($descendant-group/ancestor-or-self::* except $element-group/ancestor::*)/node-name(), '/'),
                    $value-key := string-join(($descendant-group/ancestor-or-self::* except $element-group/ancestor::*)/@value, $value-separator)
                return $path-key
            for $path-group in $groups
            group by $path-key := $path-group
            return $path-key || ' : ' || count($path-group)
            ,
            if ($element-group/*) then local:distinct-descendants($element-group/*) else ()
        )
};

local:distinct-descendants(root/*)

我仍然不确定问题是否被准确描述(不清楚结构是否总是
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/*)
此时,输出

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
,那么代码可能有点太复杂,在这种情况下,不需要
节点-name()
上的第一个分组

我还必须在内部进行两次分组,在“路径”序列(例如,
A/B/C
)和
@value
序列上,可能有更简单的方法,但在不进行重复分组的情况下,我无法将唯一的
@value
序列和嵌套结构联系起来

或许

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/*)
at有点简单,但仍然可以完成这项工作

我认为,只要子树都有一个子元素,前两次尝试就可以正常工作,但如果没有子元素,则会中断;因此,在任意数量的子元素的一般情况下,似乎有必要从子元素计算路径和值,并将其分组:

declare variable $value-separator as xs:string external := '|';

declare function local:distinct-descendants($elements as element()*) as xs:string*
{
    for $element-group in $elements[*]
    group by $element-name := node-name($element-group)
    return
        (
            let $groups :=
                for $descendant-group in $element-group//*
                group by
                    $path-key := string-join(($descendant-group/ancestor-or-self::* except $element-group/ancestor::*)/node-name(), '/'),
                    $value-key := string-join(($descendant-group/ancestor-or-self::* except $element-group/ancestor::*)/@value, $value-separator)
                return $path-key
            for $path-group in $groups
            group by $path-key := $path-group
            return $path-key || ' : ' || count($path-group)
            ,
            if ($element-group/*) then local:distinct-descendants($element-group/*) else ()
        )
};

local:distinct-descendants(root/*)

我可以理解
A
B
元素构成父/子元素的“对”,但为什么“ABC”是一对,为什么是“BC”不是吗?文档结构在同一嵌套结构中只包含相同类型的元素,这样就可以向下看并比较<代码> @值>代码>属性,或者是元素的任意数量和名称和嵌套?从一开始就已经设置了项目的数量。但是如果您考虑这个示例,只添加一个例子。,也许我的问题对您更清楚。我可以理解
A
B
元素构成父/子元素的“对”,但为什么“ABC”是一对,为什么是“BC”不是吗?文档结构在同一嵌套结构中只包含相同类型的元素,这样就可以向下看并比较<代码> @值>代码>属性,或者是元素的任意数量和名称和嵌套?从一开始就已经设置了项目的数量。但是如果您考虑这个示例,只添加一个例子。谢谢你的回复。谢谢你的回复。我已经尝试了你的解决方案,他们工作正常。但是你没有想到我也会有无序组合,比如CE、AC、AD、ABE、ACE等等。我怎样才能更正你的代码?Morover,我更喜欢最后一个解决方案,因为它是最不复杂的计算。不是吗?SIER想一个函数,它把一个路径作为输入并返回请求的计数?我在对你的问题的评论中同时回答了这个问题,即在没有给出确切结果的情况下,输入一个例子的例子不能精确地描述问题,所以恐怕是你没有考虑精确地描述问题。作为第二个例子,现在划船进入CE、AC、AD、ABE、ACE,同样没有显示确切的结构或您想要的结果,这看起来不像是一次认真的尝试,以准确描述可能的输入和输出。至于您对编写一个取路径并返回计数的函数的评论,您是否有任何已知路径可以提供给that函数,因为您知道文档结构或至少知道与比较相关的元素?很抱歉,我知道文档结构,并且所有项都有一个子项。我的问题有两种可能性:1)正如您建议的解决方案一样,我可以计算所有路径的所有可能计数;谢谢你的回复。我已经尝试过你的解决方案,它们工作正常。但你没有想到我也会有无序组合,比如CE、AC、AD、ABE、ACE等等。如何更正您的代码?更重要的是,我更喜欢最后一种解决方案,因为它在计算上是最简单的。难道不更容易想到一个函数,它以一条路径作为输入并返回请求的计数吗?我在一个comm中对这两种方法都做了注释