2011-03-01 95 views
1

我試圖創建一個xquery表達式,將返回選定的節點,但不會返回他們的子節點。這可能是最好的例子。我有以下MYNODE節點:XQuery,選擇節點,但省略返回子節點

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

我感興趣返回<myElements>節點,但沒有降低。我期望的回報將如下所示:

<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中使用嗎?

+1

問得好,+1。查看我的答案獲取完整,簡短且容易的XSLT解決方案:) – 2011-03-01 19:44:49

+0

您可以閱讀Michael Kay關於XQuery方法在http://en.wikibooks中發佈的答案中顯示的內容。org/wiki/Talk:XQuery/Typeswitch_Transformations – 2011-03-01 19:55:29

回答

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

+0

+1我同意XSLT是一種更適合這種任務的技術。 – 2011-03-01 19:56:45

2

的XQuery的子節點只返回頂級節點,它是不歸還他們的孩子。但是返回的節點仍然連接到他們的子節點,無論顯示結果的代碼是選擇在實際選擇的節點下顯示完整的子樹。

理解您的問題的第一步是要意識到您不希望您查詢從源文檔中選擇節點,您希望它通過擁有不同的子節點來構建與原始節點不同的新節點。

這意味着它是您想要生成與原始結果文檔相同的結果文檔的其中一個查詢,但只需稍作更改。正如Dimitre所說,XSLT在這一類問題上比XQuery好得多。但正如斯科特所示,它當然可以用XQuery來完成。

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/@*} 
}