2013-08-23 33 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成它自己的文件。将使事情变得更加可测试和模块化。