2013-08-23 5 views
2

Мне нужно добавить атрибут к элементу моего ответа XML с помощью XQuery. Возьмите ниже XML в качестве входных данных,Добавить атрибут в элемент существующего XML с помощью Xquery

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

Каждый раз, когда количество атрибутов заголовок сообщения может измениться. Таким образом, запрос должен добавить новый атрибут вместе со всеми существующими атрибутами и вернуть весь документ.

ответ

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: процесс-узел на RootNode

+0

Привет Лорен. Большое спасибо за Ваш ответ. Это сработало для меня! Но еще один запрос. Если я добавлю пространство имен в элементы, то я получаю сообщение об ошибке как «xyz: rootNode не может преобразовать в xs: QName». Я обновил свой вопрос. – DRB

+0

использовал имя-node() вместо имени() и изменил бит кода .. Теперь он работает. Спасибо:) – 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 из в его собственный файл. Будет делать вещи еще более проверенными и модульными.