在XQuery中,如何基于给定的谓词递归过滤后代?

时间:2011-10-27 14:25:54

标签: xml xslt filter xquery predicate

鉴于此XML片段:

<root> <!-- $root points here -->
  <!-- ... -->
  <A visible="true">
    <B visible="false">
      <C visible="true"/> <!-- but effectively false! -->
    </B>
    <D visible="true">
      <E visible="true" />
      <F visible="false" />
    </D>
  </A>
  <!-- ... -->
</root>

运行查询$root//A会给我A及其所有后代。到目前为止一切都很好。

我想要的是用谓词来过滤A的后代,比如说[@visible=true]。我希望查询返回

  <A visible="true">
    <D visible="true">
      <E visible="true" />
    </D>
  </A>
相反,即。过滤掉与谓词不匹配的所有子元素(或其父元素与其不匹配)。

考虑一个像上面描述的XML系统的GUI系统,在渲染它时我可以在树中过滤可见元素。

我认为这对于XSLT来说是微不足道的,但我一定会使用XQuery。

2 个答案:

答案 0 :(得分:2)

它可以在XQuery中完成而不需要太多努力。只需要一个函数递归重写限定节点,同时应用过滤器:

declare function local:rewrite($node as node()) as node()?
{
    typeswitch ($node)
    case element() return
        if (local:filter($node)) then
            element {node-name($node)}
            {
                $node/@*,
                for $child in $node/node() return local:rewrite($child)
            }
        else
            ()
    default return
        $node
};

declare function local:filter($node as element()) as xs:boolean
{
    $node/@visible
};

然后使用路径表达式选择A并将函数应用于结果:

for $a in $root//A return local:rewrite($a)

该函数使用一种通用模式来使用XQuery来处理所谓的XSLT任务。事实上,我认为这样做也是非常可以接受的。就我而言,我感谢不必在这里留下XQuery符号的好处......

答案 1 :(得分:1)

您可以使用XQuery Update执行此操作并删除所有不可见的内容:

copy $c:=$root
modify delete node $c//*[@visible="false"]
return $c