4

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.

Community
  • 1
  • 1
Maria Ivanova
  • 1,146
  • 10
  • 19
  • Most likely, the contents of $request_tag is not a valid XML element name. – michael.hor257k Jun 22 '16 at 09:11
  • Could it be because it contains a namespace? – Maria Ivanova Jun 22 '16 at 09:23
  • A text string cannot contain a namespace. What exactly is the parameter? And what is the expected result (please add this to your question)? – michael.hor257k Jun 22 '16 at 09:27
  • Are you sure that is output you want? In the input XML, `RESPONSE` and all its descendants (`tag`, `another tag`, ...) are in the same namespace. In your output, `NameOfResponse`is in the new namespace, and its descendants are in no namespace. I seriously doubt you want that. – michael.hor257k Jun 22 '16 at 12:42
  • Unfortunately, this is exactly what I want. However, I still don't understand why it gives an error even without namespace. I fiddled a bit with an online xslt tester and I got the result without namespace. With namespace I could only get it if I had it in the xslt schema. But considering it is different every time - I don't know if it is possible to provide it dynamically. Still, even without it - it still doesn't work in wso2esb. I generated the input with PayloadFactory - wasn't able to achieve that with it either. So I put the RESPONSE tag myself - in order to be able to rename it – Maria Ivanova Jun 22 '16 at 12:55
  • I have added another stylesheet to my answer that will produce that result exactly. – michael.hor257k Jun 22 '16 at 13:06
  • "*The namespace is inside the Envelope tag of the xml,*" Is the `rns:` prefix there constant, or can it change too? – michael.hor257k Jun 22 '16 at 13:31
  • It can change. That's the problem. – Maria Ivanova Jun 22 '16 at 13:32

2 Answers2

3

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.

michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • This almost solves the puzzle. However, there is one tiny issue - I can't put the stylesheet/namespace in the xslt schema - it needs to be generated dynamically. Perhaps I should look for an option generating the whole XSLT schema dynamically. – Maria Ivanova Jun 22 '16 at 13:13
  • I finally solved it - with the help of you both. It now produces the desired effect. I just added another param - for the namespace. – Maria Ivanova Jun 22 '16 at 13:40
  • 1
    Ok, then. Just for reference, you can extract the namespace from the input using ``. Then you can get the prefix as `name($ns)`. – michael.hor257k Jun 22 '16 at 13:50
0

Send this payload :

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <RESPONSE>
         <tag>123</tag>
         <another_tag>20160622134457473</another_tag>
     </RESPONSE>
   </soapenv:Body>
</soapenv:Envelope>

To this proxy :

<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse" name="TestSOF" transports="http" statistics="disable" trace="disable" startOnLoad="true">
    <target>
        <inSequence>
            <property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>
            <property name="RequestTagNamespace" value="http://wso2.com"/>
            <property name="RequestTagName" value="NameOfResponse"/>
            <xslt key="SOFXSL">
                <property name="request_tag_namespace" expression="get-property('RequestTagNamespace')"/>
                <property name="request_tag" expression="get-property('RequestTagName')"/>
            </xslt>
            <log level="full"/>
        </inSequence>
    </target>
    <description/>
</proxy>

With this xsl stylesheet in local entries :

<?xml version="1.0" encoding="UTF-8"?>
<localEntry xmlns="http://ws.apache.org/ns/synapse" key="SOFXSL">
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
        <xsl:param name="request_tag_namespace"/>
        <xsl:param name="request_tag"/>
        <xsl:template match="RESPONSE">
            <xsl:element name="myns:{$request_tag}" namespace="{$request_tag_namespace}">
                <xsl:apply-templates/>
            </xsl:element>
        </xsl:template>
        <xsl:template match="@*|*|comment()">
            <xsl:copy>
                <xsl:apply-templates select="@*|*|text()|comment()|processing-instruction()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
   <description/>
</localEntry>

And you will get this result :

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
      <myns:tagname xmlns:myns="http://tagnamespace">
         <tag>123</tag>
         <another_tag>20160622134457473</another_tag>
     </myns:tagname>
   </soapenv:Body>
</soapenv:Envelope>
Jean-Michel
  • 5,926
  • 1
  • 13
  • 19
  • "*This is because the result of your XSLT is 'nothing'*" You don't know that without seeing the input. And anyway this would not cause an error. – michael.hor257k Jun 22 '16 at 09:13
  • This is exactly the error I encounter in WSO2 ESB in that case – Jean-Michel Jun 22 '16 at 09:16
  • The RESPONSE element does not have a namespace. However, the new name of the element does. – Maria Ivanova Jun 22 '16 at 09:24
  • 1
    @MariaDeleva "*The RESPONSE element does not have a namespace.*" I am afraid you are mistaken about that. It doesn't have a *prefix* - but it most certainly is in a namespace. – michael.hor257k Jun 22 '16 at 13:08
  • Thank you for the clarification, Michael. I didn't know that. – Maria Ivanova Jun 22 '16 at 13:18
  • Jean-Michel, `myns` is part of the request_tag value. But if not declared in the xls:stylesheet of the xslt schema, it gives error: Undeclared prefix in element name: ret. And, unfortunately, I can't put it there, as it is different with every request. And I do have it in the input, in the Envelope tag. – Maria Ivanova Jun 22 '16 at 13:32