Search code examples
xmlxsltwso2wso2-integration-studiowso2-esb

How to rename a tag using XSLT


I am trying to rename a tag, using XSLT in WSO2 ESB template.

All my attempts get me the same error: Unable to create an OMElement using XSLT result.

One of the variants I have tried is:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:apply-templates />
    </xsl:template>
    <xsl:param name="response_tag"/>
    <xsl:template match="RESPONSE">
        <xsl:element name="{$response_tag}" >
            <xsl:for-each select="/RESPONSE/*">
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Another is:

<?xml version="1.0" encoding="UTF-8"?>
<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="request_tag"/>
    <xsl:template match="RESPONSE">
        <xsl:element name="{$request_tag}">
            <xsl:apply-templates select="node() | @*" />
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

What am I doing wrong?

PS. The parameter response_tag value is similar to rns:NameOfResponse The namespace (rns) and NameOfResponse could be different every time. The namespace is inside the Envelope tag of the xml, so in the end (if the transformation works), the xml would be valid.

The input will be something like:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:rns="http://www.example.com/example">
   <soapenv:Header/>
   <soapenv:Body>
      <RESPONSE xmlns="http://ws.apache.org/ns/synapse">
         <tag>123</tag>
         <another_tag>20160622134457473</another_tag>
        ...
     </RESPONSE>
   </soapenv:Body>
</soapenv:Envelope>

The result should be:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:rns="http://www.example.com/example">
   <soapenv:Header/>
   <soapenv:Body>
      <rns:NameOfResponse>
         <tag>123</tag>
         <another_tag>20160622134457473</another_tag>
        ...
     </rns:NameOfResponse>
   </soapenv:Body>
</soapenv:Envelope>

PPS. Tried removing the namespace from the response tag - i.e. the response tag looks like: NameOfTag now. Same error.


Solution

  • I am guessing you want to do something like this:

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:syn="http://ws.apache.org/ns/synapse"
    xmlns="http://www.example.com/example"
    exclude-result-prefixes="syn">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:param name="response_tag"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="syn:RESPONSE">
        <xsl:element name="{substring-after($response_tag, ':')}" >
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="syn:*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    </xsl:stylesheet>
    

    Applied to your input example, with a parameter response_tag='rns:NameOfResponse', the result will be:

    <?xml version="1.0" encoding="UTF-8"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
       <soapenv:Header/>
       <soapenv:Body>
          <NameOfResponse xmlns="http://www.example.com/example">
             <tag>123</tag>
             <another_tag>20160622134457473</another_tag>
            ...
         </NameOfResponse>
       </soapenv:Body>
    </soapenv:Envelope>
    

    Please note that the NameOfResponse element declares a default namespace - and this is inherited by its descendants, in the same way as in your input.


    ADDED:

    To get the exact output shown in your question, you can do:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:syn="http://ws.apache.org/ns/synapse"
    exclude-result-prefixes="syn">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:param name="response_tag"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="syn:RESPONSE">
        <xsl:element name="{$response_tag}" namespace="http://www.example.com/example">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="syn:*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    </xsl:stylesheet>
    

    Caveat: I know nothing about WSO2; this is how it's supposed to work in XSLT.