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



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

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

测试.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 是根,www

是根子级,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>

哈雷!这就是我想要按年份分组的记录都完好无损的。然后,我想从每个单独的记录中删除<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>标签。

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

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>

然后你可以在$i/*[not(name()="year")]周围添加一个包装<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 <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>

最新更新