Xquery Not [name()=“Name”]方法和XML结构

时间:2014-09-06 01:33:23

标签: xml xpath xquery

如果您有任何想法如何改进问题,我将尽力解释我的问题和预期结果。

假设我有一个.xml文档,如下所示;

的test.xml

<db>
    <www>
        <year >1990</year>
        <author>Daren</author>
    </www>
    <www>
        <year>1990</year>
        <author>Daren</author>  
    </www>
    <www>
        <year>1989</year>
        <author>Daren</author>
    </www>
</db>

db是root用户,www是root的孩子,而另一些孩子则是www。

我想按年份对记录进行分组;我已设法使用以下代码执行此操作:

<publications>
{
for $x in distinct-values(/*/*/year)
let $item := /*/*[year = $x]
where $item/author =  "Daren"
return <year-Pub>{<year>{$x}</year>} {for $i in $item where $i/author = "Daren" return $i }</year-Pub>
}
</publications>

其输出为:

<?xml version="1.0" encoding="UTF-8"?>
<publications>
   <year-Pub>
      <year>1990</year>
      <www>
         <year>1990</year>
         <author>Daren</author>
      </www>
      <www>
         <year>1990</year>
         <author>Daren</author> 
      </www>
   </year-Pub>
   <year-Pub>
      <year>1989</year>
      <www>
         <year>1989</year>
         <author>Daren</author>
      </www>
   </year-Pub>
</publications>

Harray!这就是我希望按年份分组的记录完整无缺。然后,我想从每个单独的记录中删除<year></year>标记,因为它显示在分组记录的顶部。这就是问题依然存在的地方。我设计了一种方法,使用$i/*[not(name()="year")]从每个条目中删除记录标记 像这样:

<publications>
{
for $x in distinct-values(/*/*/year)
let $item := /*/*[year = $x]
where $item/author =  "Daren"
return <year-Pub>{<year>{$x}</year>} {for $i in $item where $i/author = "Daren" return $i/*[not(name()="year")] }</year-Pub>
}
</publications> 

但输出是:

<?xml version="1.0" encoding="UTF-8"?>
<publications>
   <year-Pub>
      <year>1990</year>
      <author>Daren</author>
      <author>Daren</author>
   </year-Pub>
   <year-Pub>
      <year>1989</year>
      <author>Daren</author>
   </year-Pub>
</publications>

正如您所看到的<www></www>标签消失了,我可以看到为什么这是因为当您写$i/*[not(name()="year")]时,您要说的是从$i开始下一步www的子项并返回没有<year></year>标记的记录。我只是不确定如何修改我的代码以提供所需的结果,其中包含<www></www>标记并删除了<year></year>标记。

2 个答案:

答案 0 :(得分:1)

使用XQuery 3.0,您可以使用group by表达式对结果进行分组。然后我还为你编写了一个过滤函数,它将删除特定名称的任何后代元素。您可以使用该过滤器功能过滤出year www以及您希望的任何其他元素。

xquery version "3.0";

declare function local:filter($nodes as node()*, $names as xs:string+) {
    for $n in $nodes
    return
        typeswitch($n)
            case element() return
                if(not(local-name($n) = $names))then
                    element {node-name($n)} {
                        local:filter($n/(@*|child::node()), $names)
                    }
                else()

            default return
                $n
};

<publications>
{
    for $w in /db/www
    let $year := $w/year
    group by $year
    return
        <year-Pub>
            <year>{$year}</year>
            {
                (: add any other names you wish to
                   filter into the sequence with "year" :)

                local:filter($w, ("year"))
            }
        </year-Pub>
}</publications>

答案 1 :(得分:0)

然后你可以在<www>

周围添加一个包裹$i/*[not(name()="year")]
<publications>
{
for $x in distinct-values(/*/*/year)
let $item := /*/*[year = $x]
where $item/author =  "Daren"
return 
    <year-Pub>
    {<year>{$x}</year>} 
    {
        for $i in $item 
        where $i/author = "Daren" 
        return <www>{$i/*[not(name()="year")]}</www> 
    }
    </year-Pub>
}
</publications>

输出:

<?xml version="1.0" encoding="UTF-8"?>
<publications>
   <year-Pub>
      <year>1990</year>
      <www>
         <author>Daren</author>
      </www>
      <www>
         <author>Daren</author>
      </www>
   </year-Pub>
   <year-Pub>
      <year>1989</year>
      <www>
         <author>Daren</author>
      </www>
   </year-Pub>
</publications>