开发者

rename an element with xslt

I have this xml:

<pos:getPositionRouter xmlns:pos="positionNS">
   <positionID>
      <code>1</code>
   </positionID>
   <parame开发者_开发百科ter>?</parameter>
</pos:getPositionRouter>

and I want to rename the element pos:getPositionRouter to x:getPosition using xslt:

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

This is the sylesheet I came up with:

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

I am forced to use xalan as xslt processor, and the output, unfortunately is this:

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

The default namespace of the getPosition element becomes the new namespace, but the child elements should remain without namespace (xmlns="").

Can someone understand why?

Thank you!


This stylesheet:

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

Output:

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

Note: If you want an specific prefix you should add it to the QName. If you want to remove in-scope namespace you shouldn't use xsl:copy in XSLT 1.0


I. The transformation to do this without using parameters is really short and 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>

when applied to the provided XML document:

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

the wanted, correct result is produced:

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

II. The parameterized transformation is just a little bit more complex:

<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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜