2

我需要使用 XQuery 向我的响应 XML 的元素添加一个属性。将以下 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>

需要一个 Xquery 来添加一个属性newAtt和值newVal并给出结果,

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

每次消息头的属性数量可能会发生变化。因此查询应该添加一个新属性以及所有现有属性并返回整个文档。

4

2 回答 2

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

然后在 RootNode 上调用 foo:process-node

于 2013-08-23T14:28:38.250 回答
1

您总是可以重复使用 XSLT 来处理这些事情。特别是如果您想将代码中的风险降到最低。

eXist 支持 XSL 转换,下面是一个示例,说明如何运行 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 放到它自己的文件中,也可以使用该属性。将使事情变得更加可测试和模块化。

于 2013-10-16T20:35:01.683 回答