使用xslt重命名元素

时间:2010-11-18 15:35:43

标签: xml xslt parameters xml-namespaces

我有这个xml:

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

我想使用xslt将元素pos:getPositionRouter重命名为x:getPosition

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

这是我提出的sylesheet:

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

我被迫使用xalan作为xslt处理器,输出不幸的是:

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

getPosition元素的默认命名空间成为新的命名空间,但子元素应保持不带命名空间(xmlns="")。

有人能理解为什么吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

此样式表:

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

输出:

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

注意:如果您需要特定的前缀,则应将其添加到QName。如果要删除范围内的命名空间,则不应在XSLT 1.0中使用xsl:copy

答案 1 :(得分:0)

<强>予。不使用参数进行转换非常简短:

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

应用于提供的XML文档

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

产生了想要的正确结果

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

II。 参数化转换稍微复杂一点

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