Xml 选择节点但忽略返回子节点的XQuery

Xml 选择节点但忽略返回子节点的XQuery,xml,xslt,xpath,xquery,Xml,Xslt,Xpath,Xquery,我正在尝试创建一个xquery表达式,该表达式将返回选定的节点,但不会返回其子节点。这可能最好用一个例子来说明。我有以下myNode: <myNode> <myElements id="1"> <myElement key="one">aaa</myElement> <myElement key="two" >bbb</myElement> <myElement key="three">

我正在尝试创建一个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>

我找错树了吗?这在XPath/XQuery中可能吗?

试试这个递归算法

    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)
xquery版本“1.0”;
将函数local:passthru($x as node())声明为node()*{for$z in$x/node()返回local:recurseReplace($z)};
声明函数local:recurseReplace($x作为节点()){
打字开关($x)
(:基于条件的更改:)
case元素(myElements)返回
(:忽略任何更改:)
case text()返回$x
case comment()返回注释{“更改的注释”}
case element()返回元素{fn:node name($x)}{for$a in$x/attribute()
返回$a,本地:passthru($x)}
默认返回()
};
让$doc:=
aaa
bbb
ccc
ddd
eee
fff
返回本地:递归替换($doc)

对于这类任务,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>
<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>

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

<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>
<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>

aaa
bbb
ccc
ddd
eee
fff
生成所需的正确结果:

<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>
<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的子节点重写的标识规则

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

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


这意味着这是一种查询,您希望生成与原始文档相同但有一些小更改的结果文档。正如Dimitre所说,XSLT在这类问题上比XQuery好得多。但是,正如Scott所示,使用XQuery当然可以做到这一点。

试试这是最短的方法

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/@*}
}
let$a:=
aaa
bbb
ccc
ddd
eee
fff
在$a中的$e1
返回元素{name($e1)}
{
对于$e1中的$e2/*
返回元素{name($e2)}{$e2/@*}
}

问得好,+1。请参阅我的答案,以获得完整、简短且简单的XSLT解决方案:)您可以阅读Michael Kay在+1中发布的答案中对XQuery方法的看法。我同意XSLT是一种更适合此类任务的技术。