Playing with XML Namespaces in Mule 4 Dataweave

 Today, the world is full of REST APIs which use JSON as a major message type. But we have a lot of applications and APIs in the middleware world which rely on XML message structures. XML messages are a bit more complex than JSON messages, as in XML messages namespaces play a vital role. A miss in the namespace can lead to errors that are sometimes unseen to normal eyes. In this blog, we will discuss various ways by which we can handle the transformation of XML messages with or without namespaces in Mule 4 using Dataweave.

  1. Transforming XML messages without namespaces
  2. Transforming XML messages with namespaces 

1. Transforming XML messages without namespaces

This conversion is pretty simple, all we need to consider is XPath and do the mapping accordingly. This is similar to the JSON data transformation Let's take an example of 2 XMLs, wherein both input and output XMLs don't have namespaces. The output we need to specify is application/xml.

INPUT:

<InputRoot>
    <contact>
        <firstName>Test</firstName>
        <lastName>Data</lastName>
        <address>
            <street1>Street1</street1>
            <street2>Street2</street2>
            <city>City</city>
            <state>State</state>
            <country>Country</country>
        </address>
    </contact>
</InputRoot>

Suppose we want to extract the value of country from the above XML message. All we need to do is traverse to the node as we do in the case of JSON transformations i.e. (Assuming data is in the payload variable) payload.InputRoot.contact.address.country . Below is the dataweave file for the transformation transforming the data to a different XML format.

DATAWEAVE:

%dw 2.0
output application/xml 
---
OutputRoot:{
    Contact:{
        Name: payload.InputRoot.contact.firstName ++ payload.InputRoot.contact.lastName,
        Address :{
            Street: payload.InputRoot.contact.address.street1 ++ payload.InputRoot.contact.address.street2 , 
            City: payload.InputRoot.contact.address.city,
            State:payload.InputRoot.contact.address.state
        }
    }
}

OUTPUT:

<OutputRoot>
  <Contact>
    <Name>TestData</Name>
    <Address>
      <Street>Street1Street2</Street>
      <City>City</City>
      <State>State</State>
    </Address>
  </Contact>
</OutputRoot>

Above is the output for the dataweave file.

2. Transforming XML messages with namespaces.

Namespaces are really important for various systems to understand the element and its data. As the same element name with a different namespace corresponds to 2 different meanings. For example element name in an XML message with a namespace corresponding to the account namespaceis different from the element name corresponding to the contact namespace. So the business meaning of an element differs and so does the representation. An element belonging to a particular namespace will have a target namespace denoted by xmlns attribute. In some cases, namespaces are declared as attributes of elements and are referenced as prefixes like:
<acc:name xmlns:acc="http://deciphermiddleware.in/ns/account"> or 
<cont:name xmlns:cont="http://deciphermiddleware.in/ns/contact">.

Let's take the below example:

INPUT:

<InputRoot xmlns="http://deciphermiddleware.in/ns/sample/data">
    <cont:contact xmlns:cont="http://deciphermiddleware.in/ns/sample/contact">
        <cont:firstName>Test</cont:firstName>
        <cont:lastName>Data</cont:lastName>
        <cont:address xmlns:add="http://deciphermiddleware.in/ns/sample/address">
            <add:street1>Street1</add:street1>
            <add:street2>Street2</add:street2>
            <add:city>City</add:city>
            <add:state>State</add:state>
            <add:country>Country</add:country>
        </cont:address>
    </cont:contact>
</InputRoot>

Now, in the above case, we have multiple namespaces. To deal with such scenarios we need to declare namespaces in the Dataweave file.

We can declare the namespace in the following way.
%dw 2.0
output application/xml
ns ns0 http://deciphermiddleware.in/ns/sample/data
ns cont http://deciphermiddleware.in/ns/sample/contact
ns add http://deciphermiddleware.in/ns/sample/address

In dataweave, an element with namespace will be denoted by ns#Element (ns denotes namespace prefix as declared, Element is the name of node or element of XML and, # acts as separator) 

Suppose we need to extract data of the country, now dataweave expression for the same will be "payload.ns0#InputRoot.cont#contact.cont#address.add#country"

Combining the above parameters, below is a sample dataweave file that will output the XML message generated from the above sample input XML, having different namespaces.

DATAWEAVE:

%dw 2.0
output application/xml
ns ns0 http://deciphermiddleware.in/ns/sample/data
ns cont http://deciphermiddleware.in/ns/sample/contact
ns add http://deciphermiddleware.in/ns/sample/address
ns ns1 http://deciphermiddleware.in/ns/sample/data1
ns cont1 http://deciphermiddleware.in/ns/sample/contact1
ns add1 http://deciphermiddleware.in/ns/sample/address1
---
ns1#OutputRoot:{
    cont1#Contact:{
        cont1#Name: payload.ns0#InputRoot.cont#contact.cont#firstName ++ payload.ns0#InputRoot.cont#contact.cont#lastName,
        add1#Address :{
            add1#Street: payload.ns0#InputRoot.cont#contact.cont#address.add#street1 ++ payload.ns0#InputRoot.cont#contact.cont#address.add#street2 , 
            add1#City: payload.ns0#InputRoot.cont#contact.cont#address.add#city,
            add1#State:payload.ns0#InputRoot.cont#contact.cont#address.add#state,
            add1#Country:payload.ns0#InputRoot.cont#contact.cont#address.add#country
        }
    }
}

Below is the output for the above dataweave.

OUTPUT:

<ns1:OutputRoot xmlns:ns1="http://deciphermiddleware.in/ns/sample/data1">
  <cont1:Contact xmlns:cont1="http://deciphermiddleware.in/ns/sample/contact1">
    <cont1:Name>TestData</cont1:Name>
    <add1:Address xmlns:add1="http://deciphermiddleware.in/ns/sample/address1">
      <add1:Street>Street1Street2</add1:Street>
      <add1:City>City</add1:City>
      <add1:State>State</add1:State>
      <add1:Country>Country</add1:Country>
    </add1:Address>
  </cont1:Contact>
</ns1:OutputRoot>

References:

1. https://docs.mulesoft.com/dataweave/2.3/dataweave-cookbook-include-xml-namespaces

Please share your valuable feedback 😊😊😊



Comments

Popular posts from this blog

DateTime formatting using xp20:format-dateTime ()

Create Delimited String from XML Nodes and Vice Versa in SOA 12c

Import and Export MDS artifacts in SOA 12c