Question

Question: I am trying to add a uuid as a new element to incoming xml message. I can see that added as I am logging the result, but mule adds its namespace and the java util uuid namespace to the result which, causes another service where I route this message, NOT recognize it as it has a namespace which it doesn't know about.

Is there a way to configure the xslt transformer to achieve what I am trying to do here? Any other suggestions that could be an alternative?

Goal is to have xslt generate a uuid and tag on to the incoming message and pass it to a service end point. Appreciate all the help in this regard.

Mule Config:

<mule xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml"
  xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking"
  xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core"
  xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
  xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.4.1"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:billing="http://mycompany.com/billing"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd
http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd">

  <mulexml:xslt-transformer name="xslt"
    doc:name="XSLT">
    <mulexml:xslt-text>
      <xsl:stylesheet version="2.0" xmlns:uuid="java:java.util.UUID">
        <xsl:variable name="uid" select="uuid:randomUUID()" />
        <xsl:template match="/">
          <xsl:apply-templates />
        </xsl:template>

        <xsl:template match="node()|@*">
          <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
          </xsl:copy>
        </xsl:template>

        <xsl:template match="Request">
          <Request>
            <xsl:apply-templates select="node()|@*" />
            <RequestId>
              <xsl:value-of select="$uid" />
            </RequestId>
          </Request>
        </xsl:template>
      </xsl:stylesheet>
    </mulexml:xslt-text>
  </mulexml:xslt-transformer>

  <flow name="rsi_invoiceFlow1" doc:name="rsi_invoiceFlow1">
    <http:inbound-endpoint exchange-pattern="request-response"
      address="${listener.hostname}:${listener.port}/${listener.path.invoice.rsi}"
      doc:name="HTTP" transformer-refs="xslt" />


    <logger message="#[message.payloadAs(java.lang.String)]" level="ERROR"
      doc:name="Logger" />

    <http:outbound-endpoint exchange-pattern="request-response"
      method="POST" address="${destination.dev2.url}/" doc:name="HTTP"
      doc:description="The '/' at the end of the URL is required on the RSI outbound call" />
  </flow>
</mule>

Incoming XML:

<?xml version="1.0" encoding="UTF-8"?>
<billing:RQ xmlns:billing="http://mycompany.com/billing">
  <Request>
    <CallingHostOrWeblogicInstance>SOAPUI</CallingHostOrWeblogicInstance>
  </Request>

Output:

<?xml version="1.0" encoding="UTF-8"?>
<billing:RQ xmlns:billing="http://mycompany.com/billing">
<Request xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:uuid="java:java.util.UUID"><CallingHostOrWeblogicInstance xmlns="">SOAPUI</CallingHostOrWeblogicInstance>
<RequestId>bff3e1d6-ecdd-41ae-8807-ec04085a2b54</RequestId>
</Request>
Was it helpful?

Solution 2

Do not embed your XSL in the Mule configuration itself but instead store in a standalone file. You'll avoid namespace pollution and it's a best practice.

OTHER TIPS

XSLT creates new elements that don't have a specified namespace in the default namespace that's in effect.

In your case the default namespace is declared as xmlns="http://www.mulesoft.org/schema/mule/core", consequently the <Request> element you output will be in that namespace.

One way would be to avoid the default namespace completely. Instead use a prefix xmlns:mule="http://www.mulesoft.org/schema/mule/core" and then <mule:mule>, <mule:flow>, <mule:logger> etc. Use m: if you find mule: too long.

That's probably the cleanest approach. You're using a multitude of other namespaces already anyway, being explicit about that one won't hurt.

Another variant would be to reset the default namespace to empty in the XSLT declaration:

<xsl:stylesheet 
   version="2.0" 
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:uuid="java:java.util.UUID" 
   xmlns=""
>
  <!-- ... -->
</xsl:stylesheet>

You could also use <xsl:copy> instead of explicitly creating a new <Request> - but then you would still have the same problem with <RequestId>. <RequestId xmlns=""> would work around this but it's rather ugly, especially if it's not the only element you create.

If you don't want to externalize the XSLT (as David suggests), I'd recommend the "no default namespace" approach.

Use xmlns="" on the xsl:stylesheet element to reset the default namespace.

Use exclude-result-prefixes in the xsl:stylesheet element to avoid the other mule namespaces leaking into the stylesheet.

(You could also use XML 1.1 "namespace undeclarations", which were invented for this kind of purpose, but I wouldn't do that: XML 1.1 isn't widely-enough supported to make the technique robust.)

I tried all 3 suggestions and I think separating the transformation from the flow config works best for my situation as it offers the cleanest and decoupled approach to solving this.

Thank you all for your replies.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top