选择节点但省略返回子节点的XQuery

时间:2011-03-01 19:04:56

标签: xml xslt xpath xquery

我正在尝试创建一个xquery表达式,它将返回所选节点但不会返回其子节点。这可能是最好的例子。我有以下myNode节点:

<myNode>
  <myElements id="1">
    <myElement key="one">aaa</myElement>
    <myElement key="two" >bbb</myElement>
    <myElement key="three">ccc</myElement>
  </myElements>
  <myElements id="2">
    <myElement key="one">ddd</myElement>
    <myElement key="two" >eee</myElement>
    <myElement key="three">fff</myElement>
  </myElements>
</myNode>

我有兴趣退回&lt; myElements&gt;节点,但没有更低。我想要的回报如下:

<myNode>
  <myElements id="1" />
  <myElements id="2" />
</myNode>

<myNode>
  <myElements id="1"></myElements>
  <myElements id="2"></myElements>
</myNode>

我目前有一个xpath表达式,看起来像下面的内容(这个插图简化了),正如预期的那样,它返回了myElement子节点:


$results/myNode/MyElements
我是在叫错树吗?这在XPath / XQuery中甚至可能吗?

4 个答案:

答案 0 :(得分:3)

尝试这种递归算法..

    xquery version "1.0";

    declare function local:passthru($x as node()) as node()* {   for $z in $x/node() return local:recurseReplace($z) };

    declare function local:recurseReplace($x as node()) {
        typeswitch ($x) 
            (: Changes based on a condition :)
            case element(myElements) return <myElements id="{$x/@id}" />
            (: IGNORE ANY CHANGES :)
            case text() return $x
            case comment() return comment {"an altered comment"}
            case element() return element {fn:node-name($x)} {for $a in $x/attribute()
                                                              return $a, local:passthru($x)}
            default return ()           
};

    let $doc := 
<myNode>   
  <myElements id="1">
        <myElement key="one">aaa</myElement>
        <myElement key="two" >bbb</myElement>
        <myElement key="three">ccc</myElement>   
  </myElements>   
  <myElements id="2">
        <myElement key="one">ddd</myElement>
        <myElement key="two" >eee</myElement>
        <myElement key="three">fff</myElement>   
  </myElements> 
</myNode> 
return local:recurseReplace($doc)

答案 1 :(得分:2)

对于此类任务,XQuery非常不如XSLT:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="myElements/node()"/>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<myNode>
    <myElements id="1">
        <myElement key="one">aaa</myElement>
        <myElement key="two" >bbb</myElement>
        <myElement key="three">ccc</myElement>
    </myElements>
    <myElements id="2">
        <myElement key="one">ddd</myElement>
        <myElement key="two" >eee</myElement>
        <myElement key="three">fff</myElement>
    </myElements>
</myNode>

产生了想要的正确结果:

<myNode>
  <myElements id="1" />
  <myElements id="2" />
</myNode>

解释:身份规则,覆盖myElements

的子节点

答案 2 :(得分:2)

XQuery 返回顶级节点,它不会返回他们的子节点。但是返回的节点仍然连接到它们的子节点,无论显示结果的代码是选择在您实际选择的节点下显示完整的子树。

理解您的问题的第一步是要意识到您不希望查询从源文档中选择节点,您希望它通过拥有不同的子节点来构造与原始节点不同的新节点。

这意味着它是您想要生成与原始文档相同但只有一些小变化的结果文档的查询之一。正如Dimitre所说,XSLT比XQuery在这类问题上要好得多。但是,正如Scott所示,它当然可以用XQuery完成。

答案 3 :(得分:0)

尝试这是最短的方式

let $a := 
<myNode>
  <myElements id="1">
    <myElement key="one">aaa</myElement>
    <myElement key="two" >bbb</myElement>
    <myElement key="three">ccc</myElement>
  </myElements>
  <myElements id="2">
    <myElement key="one">ddd</myElement>
    <myElement key="two" >eee</myElement>
    <myElement key="three">fff</myElement>
  </myElements>
</myNode>

for $e1 in $a
return element {name($e1)}
{
  for $e2 in $e1/*
  return element{name($e2)}{$e2/@*}
}