使用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中对这两种方法都做了注释