Xquery根据条件分组结果

时间:2010-11-24 01:40:54

标签: xml xquery

我对xquery分组有疑问。根据我的理解,通常的情况是在for循环中的文档上使用distinct-values,但是因为我在对值进行分组之前有条件要完成,并且我不太确定如何做到这一点。

这是我的xmldb的一部分:

<element tag="0001,0000" name="Pos1>198</element>
<element tag="0001,0001" name="Pos2">123</name>
<element tag="0002,0001" name="Pos3">433</element>
<element tag="000b,0000" name="Pos3">16</element>
<element tag="0005,0000" name="Pos4>532</element>
<element tag="0005,0001" name="Pos5">342</name>
<element tag="0008,0001" name="Pos6">17</element>

要满足的条件是x坐标(数字或十六进制)必须是奇数值(例如,从上面的xml,我只需要来自tag =“0001,...”的结果,tag =“ 000b,...“,tag =”0005,...“),然后计算每组中的项目数。

这就是结果的样子:

<group>
<element xcoord="0001">2</element>
<element xcoord="000b">1</element>
<element xcoord="0005">2</element>
</group>

到目前为止,我的xquery代码看起来像这样,我可以生成具有奇数x坐标的结果,但我不知道如何继续进行分组。

import module namespace functx="http://www.functx.com" at "http://www.xqueryfunctions.com/xq/functx-1.0-nodoc-2007-01.xq"; 

for $x in collection('/db/mapdb/')//element
let $coord := number(functx:substring-before-last($x/@tag, ","))
where $coord mod 2 != 0
return $x

请告诉我。非常感谢你。

4 个答案:

答案 0 :(得分:4)

此XQuery

for $x in 
  distinct-values(/*/*/substring-before(@tag,',')
                    [contains('13579bdf', 
                               substring(., string-length(.))
                              )
                     ]
                  )
 return
   <element xcoord="{$x}">
    {count(/*/*[$x eq substring-before(@tag,',')])}
   </element>

生成想要的正确结果

<element xcoord="0001">2</element>
<element xcoord="000b">1</element>
<element xcoord="0005">2</element>

答案 1 :(得分:3)

这个XQuery:

<group>{
    for $key in distinct-values(/root/element/tokenize(@tag,',')[1])
                   [contains('13579bdf',substring(.,string-length(.)))]
    return <element xcoord="{$key}">{
               count(/root/element[tokenize(@tag,',')[1] eq $key])
          }</element>
}</group>

使用此输入:

<root>
    <element tag="0001,0000" name="Pos1">198</element>
    <element tag="0001,0001" name="Pos2">123</element>
    <element tag="0002,0001" name="Pos3">433</element>
    <element tag="000b,0000" name="Pos3">16</element>
    <element tag="0005,0000" name="Pos4">532</element>
    <element tag="0005,0001" name="Pos5">342</element>
    <element tag="0008,0001" name="Pos6">17</element>
</root>

输出:

<group>
    <element xcoord="0001">2</element>
    <element xcoord="000b">1</element>
    <element xcoord="0005">2</element>
</group>

注意:xs:hexBinary数据类型没有内置运算符,eqne除外。

答案 2 :(得分:0)

您没有说明您使用的处理器。我在try.zorba-xquery.com上测试了以下代码(它也适用于Saxon或支持XQuery 1.1和XPath 2.0的其他处理器):

let $xmldb :=
  (
    <element tag="0001,0000" name="Pos1">198</element>,
    <element tag="0001,0001" name="Pos2">123</element>,
    <element tag="0002,0001" name="Pos3">433</element>,
    <element tag="000b,0000" name="Pos3">16</element>,
    <element tag="0005,0000" name="Pos4">532</element>,
    <element tag="0005,0001" name="Pos5">342</element>,
    <element tag="0008,0001" name="Pos6">17</element>
  )
for $x in $xmldb
let $coord := tokenize($x/@tag, ",")[1]
group by $coord
where contains('13579bdf',substring($coord,string-length($coord)))
return <element xcoord="{$coord}">{count($x)}</element>

希望有帮助吗?

答案 3 :(得分:0)

如果您使用的是XQuery 1.0处理器,那么group by的常用模式是:

let $values := ...
for $key in distinct-values(for $value in $values return my:key($value))
let $group := $values[my:key(.)=$key]
return ...

其中my:key是获取每个输入值的键的函数/表达式。

在您的情况下,您可以这样填写模式:

for $coord in distinct-values($xmldb/(tokenize(.,",")[1]))
let $x := $xmldb[tokenize(.,",")[1] = $coord]
return <element xcoord="{$coord}">{count($x)}</element>

这是否有效执行取决于您的实施。我已经写了一个blog post关于如何编写一个XQSharp将识别的组。

编辑:我错过了所有x坐标必须为奇数的要求。这可以通过添加where子句来修复,以约束坐标的最后一个字符:

for $coord in distinct-values($xmldb/(tokenize(.,",")[1]))
where contains('13579bdf',substring($coord,string-length($coord)))
let $x := $xmldb[tokenize(.,",")[1] = $coord]
return <element xcoord="{$coord}">{count($x)}</element>