2013-08-23 184 views
2

我需要使用XQuery將屬性添加到我的響應XML元素中。 採取以下XML作爲輸入,使用Xquery將屬性添加到現有XML中的元素

<xyz:RootNode xmlns:abc="url1" xmlns:xyz="url2"> 
    <abc:OtherNodes/> 
    <abc:messageHeader att1="val1" att2="val2"> 
     <abc:childNodes/> 
    </abc:messageHeader> 
    <abc:OtherNodes/> 
</xyz:RootNode> 

需要的是增加一個屬性newAtt與值的newval和得到的結果作爲一個XQuery,

<xyz:RootNode xmlns:abc="url1" xmlns:xyz="url2"> 
    <abc:OtherNodes/> 
    <abc:messageHeader att1="val1" att2="val2" newAtt="newVal"> 
     <abc:childNodes/> 
    </abc:messageHeader> 
    <abc:OtherNodes> 
</xyz:RootNode> 

每次屬性數的郵件頭可能會改變。所以查詢應該添加一個新屬性以及所有現有屬性並返回整個文檔。

回答

2

嘗試以下操作:

xquery version "3.0"; 

module namespace foo="http://exist-db.org/apps/ns/foo"; 

declare function foo:process-node($node as node()?, $model as map()) { 
    if ($node) then 
    typeswitch($node) 
     case text() return $node 
     case element(messageHeader) return foo:messageHeader($node, $model) 
     default return element { $node/name() } 
           { $node/@*, foo:recurse($node, $model) } 

    else() 
}; 

declare function foo:recurse($node as node()?, $model as map()) as item()* { 
    if ($node) 
    then 
     for $cnode in $node/node() 
     return foo:process-node($cnode, $model) 
    else() 
}; 

declare function foo:messageHeader($node as node(), $model as map()) { 
element { $node/name() } 
     { $node/@*, 
      attribute { 'newAtt' } { 'newVal' }, 
      foo:recurse($node, $model) 
     } 
}; 

你再調用foo:工藝節點上的根節點

+0

嗨羅蘭。非常感謝您的回覆。它爲我工作!但還有一個問題。如果我添加命名空間到元素,那麼我得到一個錯誤消息爲「xyz:rootNode不能轉換爲xs:QName」。我更新了我的問題。 – DRB

+0

使用節點名稱()而不是名稱()並更改了代碼位。現在它的工作。謝謝:) – DRB

1

您可以隨時重新使用輪子是有這樣的事情,XSLT。特別是如果你想盡量減少代碼中的風險。

eXist supports XSL Transformations,這裏是如何運行的XSLT轉換,做你想要的工作的例子:

xquery version "3.0"; 

declare function local:add-attribute($input as node()?, $attributeName as xs:string, $attributeValue as xs:string?) { 
    let $xslt := <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:template xmlns:abc="url1" match="abc:messageHeader"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*"/> 
      <xsl:attribute name="{$attributeName}">{$attributeValue}</xsl:attribute> 
      <xsl:apply-templates select="node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
return transform:transform($input, $xslt,()) 
}; 

let $input := <xyz:RootNode xmlns:abc="url1" xmlns:xyz="url2"> 
    <abc:OtherNodes/> 
    <abc:messageHeader att1="val1" att2="val2"> 
     <abc:childNodes/> 
    </abc:messageHeader> 
    <abc:OtherNodes/> 
</xyz:RootNode> 

return local:add-attribute($input, "hey", "bam") 

您也可以使用$parameters屬性,如果你想出來把你的XSLT成它自己的文件。將使事情變得更加可測試和模塊化。