2013-08-23 6 views
2

Je dois ajouter un attribut à un élément de ma réponse XML en utilisant XQuery. Prenez le XML ci-dessous en entrée,Ajouter un attribut à un élément dans un fichier XML existant à l'aide de 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> 

Besoin d'un Xquery qui ajoutent un autre attribut newatt avec la valeur newVal et donner le résultat que,

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

Chaque fois que le nombre d'attributs de l'en-tête du message peut changer. La requête doit donc ajouter un nouvel attribut avec tous les attributs existants et renvoyer le document entier.

Répondre

2

les opérations suivantes:

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

Vous appelez alors foo: processus nœud sur le RootNode

+0

Bonjour Loren. Merci beaucoup pour votre réponse. Cela a fonctionné pour moi! Mais une autre requête. Si j'ajoute un espace de noms aux éléments, alors je reçois un message d'erreur comme "xyz: rootNode ne peut pas convertir en xs: QName". J'ai mis à jour ma question. – DRB

+0

utilisé node-name() au lieu de name() et changé le bit de code .. Il fonctionne maintenant. Je vous remercie:) – DRB

1

Vous pouvez toujours réutiliser la roue qui est là pour de telles choses, XSLT. Surtout si vous voulez minimiser les risques dans votre code.

eXist supports XSL Transformations et voici un exemple de la façon d'exécuter une transformation XSLT qui fait le travail que vous voulez:

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

Vous pouvez également utiliser l'attribut $parameters si vous voulez apporter votre XSLT sur en son propre fichier. Rendre les choses encore plus testables et modulaires.

Questions connexes