2010-11-18 35 views
3

J'ai ce xml:renommer un élément avec xslt

<pos:getPositionRouter xmlns:pos="positionNS"> 
    <positionID> 
     <code>1</code> 
    </positionID> 
    <parameter>?</parameter> 
</pos:getPositionRouter> 

et je veux renommer l'élément pos:getPositionRouter à x:getPosition en utilisant xslt:

<x:getPosition xmlns:x="newPositionNS"> 
    <positionID> 
     <code>1</code> 
    </positionID> 
    <parameter>?</parameter> 
</x:getPosition> 

C'est le sylesheet je suis venu avec:

Je suis obligé d'utiliser xalan en tant que processeur xslt, et la sortie, malheureusement, est la suivante:
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" /> 

<xsl:param name="old_namespace" /> 
<xsl:param name="old_element_localname" /> 
<xsl:param name="new_namespace" /> 
<xsl:param name="new_element_localname" /> 


<xsl:template match="@*|node()"> 
    <xsl:choose> 
    <xsl:when test="(local-name() = $old_element_localname) and (namespace-uri() = $old_namespace)"> 
    <xsl:element name="{$new_element_localname}" namespace="{$new_namespace}"> 
    <xsl:apply-templates select="@*|node()"/> 
    </xsl:element> 
    </xsl:when> 

    <!-- copy the rest as is --> 
    <xsl:otherwise> 
    <xsl:copy> 
    <xsl:apply-templates select="@*|node()" /> 
    </xsl:copy> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

</xsl:stylesheet> 
<getPosition xmlns="newPositionNS"> 
    <positionID xmlns:pos="positionNS"> 
     <code>1</code> 
    </positionID> 
    <parameter xmlns:pos="positionNS">?</parameter> 
</getPosition> 

L'espace de noms par défaut de l'élément getPosition devient le nouvel espace de noms, mais les éléments de l'enfant doit rester sans espace de noms (xmlns="").

Est-ce que quelqu'un peut comprendre pourquoi?

Merci!

+0

Notez que la sortie souhaitée et votre sortie réelle sont sémantiquement égale: '{newPositionNS} enfants getPosition' sont sous URI d'espace de nom null, ils ont juste URI de l'espace de noms "positionNS" dans la portée (mais non utilisé). –

+0

Bonjour Alejandro, si je comprends bien, les deux sorties ne sont pas sémantiquement égales: le paramètre d'espace de noms par défaut xmlns = "newPositionNS" sur l'élément racine est hérité aux enfants, donc positionID est maintenant dans l'espace de noms newPositionNS, et non dans le "namespace comme il se doit. – Simon

+0

Bonne question, +1. Voir ma réponse pour une solution courte et simple. :) –

Répondre

1

Cette feuille de style:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:param name="old_namespace" select="'positionNS'"/> 
    <xsl:param name="old_element_localname" select="'getPositionRouter'"/> 
    <xsl:param name="new_namespace_prefix" select="'x'"/> 
    <xsl:param name="new_namespace" select="'newPositionNS'"/> 
    <xsl:param name="new_element_localname" select="'getPosition'" /> 
    <xsl:template match="*"> 
     <xsl:choose> 
      <xsl:when test="local-name()=$old_element_localname and 
          namespace-uri()=$old_namespace"> 
       <xsl:element 
        name="{substring(concat($new_namespace_prefix,':'), 
             1 div boolean($new_namespace_prefix))}{ 
          $new_element_localname}" 
        namespace="{$new_namespace}"> 
        <xsl:apply-templates select="@*|node()"/> 
       </xsl:element> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:element name="{name()}"> 
        <xsl:apply-templates select="@*|node()"/> 
       </xsl:element> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
    <xsl:template match="@*"> 
     <xsl:attribute name="{name()}"> 
      <xsl:value-of select="."/> 
     </xsl:attribute> 
    </xsl:template> 
</xsl:stylesheet> 

Sortie:

<x:getPosition xmlns:x="newPositionNS"> 
    <positionID> 
     <code>1</code> 
    </positionID> 
    <parameter>?</parameter> 
</x:getPosition> 

Remarque: Si vous voulez un préfixe spécifique, vous devez l'ajouter à la QName. Si vous souhaitez supprimer dans le champ namespace vous ne devriez pas utiliser xsl:copy dans XSLT 1.0

+0

Génial, merci Alejandro, je ne veux pas vraiment forcer le préfixe d'espace de noms, le 'x' était juste un exemple, mais ça pourrait être n'importe quoi, ce n'est pas important. L'important est que les éléments enfants n'aient pas d'espace de noms. – Simon

+0

@Luca: Vous êtes bienvenu. Vérifiez mon commentaire à vos requêtes. Peut-être que vous devriez signaler un bug dans Xalan. –

0

I. La transformation de le faire sans l'aide de paramètres est vraiment court et simple:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:pos="positionNS" xmlns:x="newPositionNS" > 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="pos:getPositionRouter"> 
    <xsl:element name="x:getPosition"> 
    <xsl:apply-templates/> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="*"> 
    <xsl:element name="{name()}"> 
    <xsl:copy-of select="namespace::*[not(name()='pos')]"/> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:element> 
    <xsl:apply-templates/> 
</xsl:template> 
</xsl:stylesheet> 

lorsqu'il est appliqué au document XML fourni:

<pos:getPositionRouter xmlns:pos="positionNS"> 
    <positionID> 
     <code>1</code> 
    </positionID> 
    <parameter>?</parameter> 
</pos:getPositionRouter> 

le résultat recherché, est produit correct:

<x:getPosition xmlns:x="newPositionNS"> 
    <positionID> 
     <code>1</code>1 
    </positionID> 
    <code>1</code>1 
    <parameter>?</parameter>? 
</x:getPosition> 

II. La transformation paramétrés est un peu plus complexe:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:param name="pOldNamespace" select="'positionNS'"/> 
<xsl:param name="pOldElementLocalname" select="'getPositionRouter'"/> 
<xsl:param name="pNewNamespace" select="'newPositionNS'"/> 
<xsl:param name="pNewElementLocalname" select="'getPosition'"/> 
<xsl:param name="pNewElementPrefix" select="'x'"/> 

<xsl:template match="*"> 
    <xsl:variable name="vReplacing" select= 
    "local-name()=$pOldElementLocalname 
    and 
    namespace-uri()=$pOldNamespace"/> 

    <xsl:variable name="vName"> 
    <xsl:choose> 
    <xsl:when test="$vReplacing"> 
    <xsl:value-of select="concat($pNewElementPrefix, ':', local-name())"/> 
    </xsl:when> 
    <xsl:otherwise><xsl:value-of select="name()"/></xsl:otherwise> 
    </xsl:choose> 
    </xsl:variable> 

    <xsl:variable name="vNamespace"> 
    <xsl:choose> 
    <xsl:when test="$vReplacing"> 
    <xsl:value-of select="$pNewNamespace"/> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:value-of select="namespace-uri()"/> 
    </xsl:otherwise> 
    </xsl:choose> 
    </xsl:variable> 

    <xsl:element name="{$vName}" namespace="{$vNamespace}"> 
    <xsl:copy-of select="namespace::*[not(.=$pOldNamespace)]"/> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:element> 
</xsl:template> 
</xsl:stylesheet> 
+0

@Dimitre: Outre que la paramétrisation était une requête, et la bonne méthode pour supprimer uniquement un espace de noms spécifique, je pense que vous devriez revérifier votre feuille de style: appliquer aux attributs sans règle d'attribut et ' 'typo dans" tout élément "règle. –

+0

@Alejandro: Je sais bien que j'ai manqué des attributs - intentionnellement, car il n'y a pas d'attributs dans le code source. Quant au paramétrage, il ne peut être vu que dans le code fourni, ce que je n'ai pas du tout lu ... Je ne suis pas sûr que le paramétrage soit une exigence. –

+0

+1 J'aime la déclaration de variable pour le nom et l'espace de nom, rend la feuille de style plus lisible. –