Contact Us 1-800-596-4880

DataWeave Examples

Introduction

Below are a series of examples that demonstrate various data transformation approaches expressed in DataWeave. DataWeave code is typically written inside the Transform Message component, which is accessible in Anypoint Studio.

To step through basic DataWeave use cases and exercises in actual Mule applications, see the DataWeave Quickstart Guide.
The DataWeave code shown in the examples is understood in the context of input/output metadata. The tabs below can be toggled to see the metadata structures that DataWeave leverages to get the transformations done.

Basic Transformation

This basic transformation shows you how you can easily map fields from input to output without requiring any special operations other than transforming XML to JSON. It also changes the order and names of some of the fields.

Note that this transform only deals with a single instance of the "order" data structure at a time. If you want to deal with a collection of several orders coming in a single Mule message, you’d have to resort to the map operator to sort through them, shown in the next example.

The DataWeave Quickstart Guide walks you this same transformation, showing you how you can create it automatically via the drag-and-drop UI. It then goes into tweaking the code to make it more interesting.

Example Transformation

DataWeave
%dw 1.0
%output application/json
---
{
        address1: payload.order.buyer.address,
        city: payload.order.buyer.city,
        country: payload.order.buyer.nationality,
        email: payload.order.buyer.email,
        name: payload.order.buyer.name,
        postalCode: payload.order.buyer.postCode,
        stateOrProvince: payload.order.buyer.state
}

Input: XML

Input
<?xml version='1.0' encoding='UTF-8'?>
<order>
  <product>
    <price>5</price>
    <model>MuleSoft Connect 2016</model>
  </product>
  <item_amount>3</item_amount>
  <payment>
    <payment-type>credit-card</payment-type>
    <currency>USD</currency>
    <installments>1</installments>
  </payment>
  <buyer>
    <email>mike@hotmail.com</email>
    <name>Michael</name>
    <address>Koala Boulevard 314</address>
    <city>San Diego</city>
    <state>CA</state>
    <postCode>1345</postCode>
    <nationality>USA</nationality>
  </buyer>
  <shop>main branch</shop>
  <salesperson>Mathew Chow</salesperson>
</order>

Output: JSON

Output
{
  "address1": "Koala Boulevard 314",
  "city": "San Diego",
  "country": "USA",
  "email": "mike@hotmail.com",
  "name": "Michael",
  "postalCode": "1345",
  "stateOrProvince": "CA"
}

Using the map Operator

Follow along to see how to use the map operator. The as operator is also featured in this example. Take an XML list of books and use DataWeave to output a JSON version of the book list. It goes through each <book> element from the XML input, simply using the map operator.

You can ensure the transformation generates the correct type for each element by using the as operator (used for type coercion - see an as operator example).

Since JSON cannot accept duplicate keys, elements that are duplicated in the input, show the first of the keys on the output side.

Example Transformation

DataWeave
%dw 1.0
%output application/json
---
items: payload.books map {
      type: "book",
      price: $.price as :number,
      properties: {
        title: $.title,
        author: $.author,
        year: $.year as :number
      }
}

Input: JSON

Input
{
    "books": [
      {
        "-category": "cooking",
        "title": {
          "-lang": "en",
          "#text": "Everyday Italian"
        },
        "author": "Giada De Laurentiis",
        "year": "2005",
        "price": "30.00"
      },
      {
        "-category": "children",
        "title": {
          "-lang": "en",
          "#text": "Harry Potter"
        },
        "author": "J K. Rowling",
        "year": "2005",
        "price": "29.99"
      },
      {
        "-category": "web",
        "title": {
          "-lang": "en",
          "#text": "XQuery Kick Start"
        },
        "author": [
          "James McGovern",
          "Per Bothner",
          "Kurt Cagle",
          "James Linn",
          "Vaidyanathan Nagarajan"
        ],
        "year": "2003",
        "price": "49.99"
      },
      {
        "-category": "web",
        "-cover": "paperback",
        "title": {
          "-lang": "en",
          "#text": "Learning XML"
        },
        "author": "Erik T. Ray",
        "year": "2003",
        "price": "39.95"
      }
    ]
}

Output: JSON

Output
{
  "items": [
    {
      "type": "book",
      "price": 30.00,
      "properties": {
        "title": {
          "-lang": "en",
          "#text": "Everyday Italian"
        },
        "author": "Giada De Laurentiis",
        "year": 2005
      }
    },
    {
      "type": "book",
      "price": 29.99,
      "properties": {
        "title": {
          "-lang": "en",
          "#text": "Harry Potter"
        },
        "author": "J K. Rowling",
        "year": 2005
      }
    },
    {
      "type": "book",
      "price": 49.99,
      "properties": {
        "title": {
          "-lang": "en",
          "#text": "XQuery Kick Start"
        },
        "author": [
          "James McGovern",
          "Per Bothner",
          "Kurt Cagle",
          "James Linn",
          "Vaidyanathan Nagarajan"
        ],
        "year": 2003
      }
    },
    {
      "type": "book",
      "price": 39.95,
      "properties": {
        "title": {
          "-lang": "en",
          "#text": "Learning XML"
        },
        "author": "Erik T. Ray",
        "year": 2003
      }
    }
  ]
}

Remove Fields

In this example, the input contains sensitive information that should be removed. The transform replicates the inbound structure but uses a simple remove operator to take away specific key:value pairs.

The example goes through the whole set of elements in the input using the map operator.

Example Transformation

DataWeave
%dw 1.0
%output application/xml
---
users: {
      (payload.users map {
        user: {
        personal_information: $.personal_information - "ssn",
        login_information: $.login_information - "password"
        }
      })
}

Input: XML

Input
<users>
    <user>
        <personal_information>
            <first_name>Emiliano</first_name>
            <middle_name>Romoaldo</middle_name>
            <last_name>Lesende</last_name>
            <ssn>001-08-84382</ssn>
        </personal_information>
        <login_information>
            <username>3miliano</username>
            <password>mypassword1234</password>
        </login_information>
    </user>
    <user>
        <personal_information>
            <first_name>Mariano</first_name>
            <middle_name>Toribio</middle_name>
            <last_name>de Achaval</last_name>
            <ssn>002-05-34738</ssn>
        </personal_information>
        <login_information>
            <username>machaval</username>
            <password>mypassword4321</password>
        </login_information>
    </user>
</users>

Output: XML

Output
<?xml version="1.0" encoding="UTF-8"?>
<users>
  <user>
    <personal_information>
      <first_name>Emiliano</first_name>
      <middle_name>Romoaldo</middle_name>
      <last_name>Lesende</last_name>
    </personal_information>
    <login_information>
      <username>3miliano</username>
    </login_information>
  </user>
  <user>
    <personal_information>
      <first_name>Mariano</first_name>
      <middle_name>Toribio</middle_name>
      <last_name>de Achaval</last_name>
    </personal_information>
    <login_information>
      <username>machaval</username>
    </login_information>
  </user>
</users>

Replace Values

In this example, the input contains the same sensitive information as in the previous one, but instead of entirely removing the key:value pairs that contain it, the values are replaced with the string. The transform replicates the inbound structure but uses a simple when operator to replace values when specific keys occur.

The example goes through the whole set of elements in the input using the map operator.

Example Transformation

DataWeave
%dw 1.0
%output application/xml
---
users: { (payload.users map {
    user: {
       personal_information: $.personal_information mapObject {
            ($$): $ unless $$ ~= "ssn" otherwise "****"
       },
       login_information: $.login_information mapObject {
          ($$): $ unless $$ ~= "password" otherwise "****"
       }
     }
}) }

Input: XML

Input
<users>
    <user>
        <personal_information>
            <first_name>Emiliano</first_name>
            <middle_name>Romoaldo</middle_name>
            <last_name>Lesende</last_name>
            <ssn>001-08-84382</ssn>
        </personal_information>
        <login_information>
            <username>3miliano</username>
            <password>mypassword1234</password>
        </login_information>
    </user>
    <user>
        <personal_information>
            <first_name>Mariano</first_name>
            <middle_name>Toribio</middle_name>
            <last_name>de Achaval</last_name>
            <ssn>002-05-34738</ssn>
        </personal_information>
        <login_information>
            <username>machaval</username>
            <password>mypassword4321</password>
        </login_information>
    </user>
</users>

Output: XML

Output
<?xml version="1.0" encoding="UTF-8"?>
<users>
  <user>
    <personal_information>
      <first_name>Emiliano</first_name>
      <middle_name>Romoaldo</middle_name>
      <last_name>Lesende</last_name>
      <ssn>****</ssn>
    </personal_information>
    <login_information>
      <username>3miliano</username>
      <password>****</password>
    </login_information>
  </user>
  <user>
    <personal_information>
      <first_name>Mariano</first_name>
      <middle_name>Toribio</middle_name>
      <last_name>de Achaval</last_name>
      <ssn>****</ssn>
    </personal_information>
    <login_information>
      <username>machaval</username>
      <password>****</password>
    </login_information>
  </user>
</users>

Target an Attribute

This example shows you how to transform a JSON array of objects to XML. Each object represents a book and its attributes.

The map operator carries out the same steps for each element in the input array. Through the use of @, attributes are injected into the XML.

See Attribute selector expressions on how to select XML attributes in DataWeave.

Example Transformation

DataWeave
%dw 1.0
%output application/xml
---
{
  bookstore: { (payload map {
      book : {
      title @(lang: "en"): $.item.properties.title,
      year: $.item.properties.year,
      price: $.item.price,
      ($.item.properties.author map
      author @(loc: "US"): $)
    }
  }) }
}

Input: JSON

Input
[
  {
    "item": {
      "type": "book",
      "price": 30,
      "properties": {
        "title": "Everyday Italian",
        "author": [
          "Giada De Laurentiis"
        ],
        "year": 2005
      }
    }
  },
  {
    "item": {
      "type": "book",
      "price": 29.99,
      "properties": {
        "title": "Harry Potter",
        "author": [
          "J K. Rowling"
        ],
        "year": 2005
      }
    }
  },
  {
    "item": {
      "type": "book",
      "price": 49.99,
      "properties": {
        "title": "XQuery Kick Start",
        "author": [
          "James McGovern",
          "Per Bothner",
          "Kurt Cagle",
          "James Linn",
          "Vaidyanathan Nagarajan"
        ],
        "year": 2003
      }
    }
  },
  {
    "item": {
      "type": "book",
      "price": 39.95,
      "properties": {
        "title": "Learning XML",
        "author": [
          "Erik T. Ray"
        ],
        "year": 2003
      }
    }
  }
]

Output: XML

Output
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book>
    <title lang="en">Everyday Italian</title>
    <year>2005</year>
    <price>30</price>
    <author loc="US">Giada De Laurentiis</author>
  </book>
  <book>
    <title lang="en">Harry Potter</title>
    <year>2005</year>
    <price>29.99</price>
    <author loc="US">J K. Rowling</author>
  </book>
  <book>
    <title lang="en">XQuery Kick Start</title>
    <year>2003</year>
    <price>49.99</price>
    <author loc="US">James McGovern</author>
    <author loc="US">Per Bothner</author>
    <author loc="US">Kurt Cagle</author>
    <author loc="US">James Linn</author>
    <author loc="US">Vaidyanathan Nagarajan</author>
  </book>
  <book>
    <title lang="en">Learning XML</title>
    <year>2003</year>
    <price>39.95</price>
    <author loc="US">Erik T. Ray</author>
  </book>
</bookstore>

Adding Optional Fields Based on a Condition

When mapping something to an XML format, you may want to add certain tags based on a condition. The mapping below only inserts the 'insurance' tag when it’s present in the input.

The example goes through the whole set of elements in the input using a map operator. It also uses the when operator to only select instances that include the field 'insurance'.

Example Transformation

DataWeave
%dw 1.0
%output application/xml
---
users: {
  (payload map {
        user: {
          name: $.name,
          (insurance: $.insurance) when $.insurance?
        }
    })
}

Input: JSON

Input
[
  {
    "name" : "Julian",
    "gender" : "Male",
    "age" : 41,
    "insurance": "Osde"
  },
  {
    "name" : "Mariano",
    "gender" : "Male",
    "age" : 33
  }
]

Output: XML

Output
<?xml version='1.0' encoding='US-ASCII'?>
<users>
  <user>
    <name>Julian</name>
    <insurance>Osde</insurance>
  </user>
  <user>
    <name>Mariano</name>
  </user>
</users>

Rename Keys When These Exist

This example takes in a JSON object that contains several fields. Most of them must be kept identical, except for a couple that optionally might appear in the payload, and if so should be renamed. Instead of referencing each field individually, this example renames two fields in particular and handles the rest without any changes.

The example goes through the whole set of elements in the input using a mapObject operator. Note that it differs from the map operation in that map object processes both key and value of its input, rather than just the keys. It also uses the when operator together with an and to pick out the specific keys that need to change, and an example use of the as operator to coerce its type to string.

Example Transformation

DataWeave
%dw 1.0
%output application/json
---
payload.flights map (flight) -> {
(flight mapObject (value, key) -> {
    (emptySeats: value) when key as :string == 'availableSeats',
    (airline: value) when key as :string == 'airlineName',
    ((key):value) when (key as :string !='availableSeats') and (key as :string != 'airlineName')
  })
}

Input: JSON

Input
{
  "flights":[
  {
  "availableSeats":45,
  "airlineName":"Ryan Air",
  "aircraftBrand":"Boeing",
  "aircraftType":"737",
  "departureDate":"12/14/2017",
  "origin":"BCN",
  "destination":"FCO"
  },
  {
  "availableSeats":15,
  "airlineName":"Ryan Air",
  "aircraftBrand":"Boeing",
  "aircraftType":"747",
  "departureDate":"08/03/2017",
  "origin":"FCO",
  "destination":"DFW"
  }]
}

Output: JSON

Output
[
  {
    "emptySeats": 45,
    "airline": "Ryan Air",
    "aircraftBrand": "Boeing",
    "aircraftType": "737",
    "departureDate": "12/14/2017",
    "origin": "BCN",
    "destination": "FCO"
  },
  {
    "emptySeats": 15,
    "airline": "Ryan Air",
    "aircraftBrand": "Boeing",
    "aircraftType": "747",
    "departureDate": "08/03/2017",
    "origin": "FCO",
    "destination": "DFW"
  }
]

Using Constant Directives

This example converts an XML input to a JSON output that is structured differently and that contains URL links that are built from concatenating input content defining a few constant directives in The DataWeave Header. The transform also creates a few fields that are conditional and are only present in the output when they exist in the input.

Example Transformation

DataWeave
%dw 1.0
%output application/json
%var baseUrl="http://alainn-cosmetics.cloudhub.io/api/v1.0/"
%var urlPage="http://alainn-cosmetics.cloudhub.io/api/v1.0/items"
%var pageIndex=0
%var requestedPageSize=4
%var fullUrl="http://alainn-cosmetics.cloudhub.io/api/v1.0/items"
---
using (pageSize = payload.getItemsResponse.PageInfo.pageSize) {
     links: [
        {
            href: fullUrl,
            rel : "self"
        },
        {
            href: urlPage ++ "?pageIndex=" ++ (pageIndex + pageSize) ++ "&pageSize=" ++ requestedPageSize,
            rel: "next"
        },
        ({
            href: urlPage ++ "?pageIndex=" ++ (pageIndex - pageSize) ++ "&pageSize=" ++ requestedPageSize,
            rel: "prev"
        }) when (pageIndex > 0)
     ],
     collection: {
        size: pageSize,
        items: payload.getItemsResponse.*Item map {
            id: $.id,
            type: $.type,
            name: $.name,
            (summary: $.summary) when $.summary?,
            (brand: $.brand) when $.brand?,
            links: ($.images.*image map {
                href: trim $,
                rel: $.@type
            }) + {
                href: baseUrl ++ "/" ++ $.id,
                rel: "self"
            }
        }
     }
}

Input: XML

Input
<ns0:getItemsResponse xmlns:ns0="http://www.alainn.com/SOA/message/1.0">
    <ns0:PageInfo>
        <pageIndex>0</pageIndex>
        <pageSize>20</pageSize>
    </ns0:PageInfo>
    <ns1:Item xmlns:ns1="http://www.alainn.com/SOA/model/1.0">
        <id>B0015BYNRO</id>
        <type>Oils</type>
        <name>Now Foods LANOLIN PURE</name>
        <images>
            <image type="SwatchImage">http://ecx.images-amazon.com/images/I/11Qoe774Q4L._SL30_.jpg
            </image>
        </images>
    </ns1:Item>
    <ns1:Item xmlns:ns1="http://www.alainn.com/SOA/model/1.0">
        <id>B002K8AD02</id>
        <type>Bubble Bath</type>
        <name>Deep Steep Honey Bubble Bath</name>
        <summary>Disclaimer: This website is for informational purposes only.
            Always check the actual product label in your possession for the most
            accurate ingredient information due to product changes or upgrades
            that may not yet be reflected on our web site. These statements made
            in this website have not been evaluated by the Food and Drug
            Administration. The products offered are not intended to diagnose,
            treat
        </summary>
        <images>
            <image type="SwatchImage">http://ecx.images-amazon.com/images/I/216ytnMOeXL._SL30_.jpg
            </image>
        </images>
    </ns1:Item>
    <ns1:Item xmlns:ns1="http://www.alainn.com/SOA/model/1.0">
        <id>B000I206JK</id>
        <type>Oils</type>
        <name>Now Foods Castor Oil</name>
        <summary>One of the finest natural skin emollients available</summary>
        <images>
            <image type="SwatchImage">http://ecx.images-amazon.com/images/I/21Yz8q-yQoL._SL30_.jpg
            </image>
        </images>
    </ns1:Item>
    <ns1:Item xmlns:ns1="http://www.alainn.com/SOA/model/1.0">
        <id>B003Y5XF2S</id>
        <type>Chemical Hair Dyes</type>
        <name>Manic Panic Semi-Permanent Color Cream</name>
        <summary>Ready to use, no mixing required</summary>
        <images>
            <image type="SwatchImage">http://ecx.images-amazon.com/images/I/51A2FuX27dL._SL30_.jpg
            </image>
        </images>
    </ns1:Item>
    <ns1:Item xmlns:ns1="http://www.alainn.com/SOA/model/1.0">
        <id>B0016BELU2</id>
        <type>Chemical Hair Dyes</type>
        <name>Herbatint Herbatint Permanent Chestnut (4n)</name>
        <images>
            <image type="SwatchImage">http://ecx.images-amazon.com/images/I/21woUiM0BdL._SL30_.jpg
            </image>
        </images>
    </ns1:Item>
</ns0:getItemsResponse>

Output: JSON

Output
{
  "links": [
    {
      "href": "http:\/\/alainn-cosmetics.cloudhub.io\/api\/v1.0\/items",
      "rel": "self"
    },
    {
      "href": "http:\/\/alainn-cosmetics.cloudhub.io\/api\/v1.0\/items?pageIndex=20&pageSize=4",
      "rel": "next"
    }
  ],
  "collection": {
    "size": "20",
    "items": [
      {
        "id": "B0015BYNRO",
        "type": "Oils",
        "name": "Now Foods LANOLIN PURE",
        "links": [
          {
            "href": "http:\/\/ecx.images-amazon.com\/images\/I\/11Qoe774Q4L._SL30_.jpg",
            "rel": "SwatchImage"
          },
          {
            "href": "http:\/\/alainn-cosmetics.cloudhub.io\/api\/v1.0\/\/B0015BYNRO",
            "rel": "self"
          }
        ]
      },
      {
        "id": "B002K8AD02",
        "type": "Bubble Bath",
        "name": "Deep Steep Honey Bubble Bath",
        "summary": "Disclaimer: This website is for informational purposes only.\n            Always check the actual product label in your possession for the most\n            accurate ingredient information due to product changes or upgrades\n            that may not yet be reflected on our web site. These statements made\n            in this website have not been evaluated by the Food and Drug\n            Administration. The products offered are not intended to diagnose,\n            treat\n        ",
        "links": [
          {
            "href": "http:\/\/ecx.images-amazon.com\/images\/I\/216ytnMOeXL._SL30_.jpg",
            "rel": "SwatchImage"
          },
          {
            "href": "http:\/\/alainn-cosmetics.cloudhub.io\/api\/v1.0\/\/B002K8AD02",
            "rel": "self"
          }
        ]
      },
      {
        "id": "B000I206JK",
        "type": "Oils",
        "name": "Now Foods Castor Oil",
        "summary": "One of the finest natural skin emollients available",
        "links": [
          {
            "href": "http:\/\/ecx.images-amazon.com\/images\/I\/21Yz8q-yQoL._SL30_.jpg",
            "rel": "SwatchImage"
          },
          {
            "href": "http:\/\/alainn-cosmetics.cloudhub.io\/api\/v1.0\/\/B000I206JK",
            "rel": "self"
          }
        ]
      },
      {
        "id": "B003Y5XF2S",
        "type": "Chemical Hair Dyes",
        "name": "Manic Panic Semi-Permanent Color Cream",
        "summary": "Ready to use, no mixing required",
        "links": [
          {
            "href": "http:\/\/ecx.images-amazon.com\/images\/I\/51A2FuX27dL._SL30_.jpg",
            "rel": "SwatchImage"
          },
          {
            "href": "http:\/\/alainn-cosmetics.cloudhub.io\/api\/v1.0\/\/B003Y5XF2S",
            "rel": "self"
          }
        ]
      },
      {
        "id": "B0016BELU2",
        "type": "Chemical Hair Dyes",
        "name": "Herbatint Herbatint Permanent Chestnut (4n)",
        "links": [
          {
            "href": "http:\/\/ecx.images-amazon.com\/images\/I\/21woUiM0BdL._SL30_.jpg",
            "rel": "SwatchImage"
          },
          {
            "href": "http:\/\/alainn-cosmetics.cloudhub.io\/api\/v1.0\/\/B0016BELU2",
            "rel": "self"
          }
        ]
      }
    ]
  }
}

Perform Basic Math

This example takes an XML input and parses it into a different XML arrangement. After a single <header> element is copied, a map operation carries out the same steps for each 'item': several fields are passed on without any changes, then the discount and subtotal fields are calculated with references to constants defined in the header directives of the transform. A single set of subtotal, tax and total elements are created by performing a reduce operation over all of the items in the "items" array, performing calculations that sometimes involve constants defined in the header. The as operator is also used to coerce to a number and then performs basic math on these numbers.

Example Transformation

DataWeave
%dw 1.0
%output application/xml
%var tax=0.085
%var discount=0.05
---
invoice: {
    header: payload.invoice.header,
    items: { (payload.invoice.items.*item map {
        item @(index: $$ + 1): {
            description: $.description,
            quantity: $.quantity,
            unit_price: $.unit_price,
            discount: (discount * 100) as :string { format: "##" } ++ "%",
            subtotal: $.unit_price * $.quantity * (1 - discount)
        }
    }) },
    totals: using (subtotal = payload.invoice.items reduce ((item, sum1 = 0) -> sum1 + (item.unit_price * item.quantity * (1 - discount)))) {
        subtotal: subtotal,
        tax: (tax * 100) as :string { format: "##.#" } ++ "%",
        total: subtotal * (1 + tax)
    }
}

Input: XML

Input
<invoice>
    <header>
        <customer_name>ACME, Inc.</customer_name>
        <customer_state>CA</customer_state>
    </header>
    <items>
        <item>
            <description>Product 1</description>
            <quantity>2</quantity>
            <unit_price>10</unit_price>
        </item>
        <item>
            <description>Product 2</description>
            <quantity>1</quantity>
            <unit_price>30</unit_price>
        </item>
    </items>
</invoice>

Output: XML

Output
<?xml version="1.0" encoding="UTF-8"?>
<invoice>
  <header>
    <customer_name>ACME, Inc.</customer_name>
    <customer_state>CA</customer_state>
  </header>
  <items>
    <item index="1">
      <description>Product 1</description>
      <quantity>2</quantity>
      <unit_price>10</unit_price>
      <discount>5%</discount>
      <subtotal>20</subtotal>
    </item>
    <item index="2">
      <description>Product 2</description>
      <quantity>1</quantity>
      <unit_price>30</unit_price>
      <discount>5%</discount>
      <subtotal>30</subtotal>
    </item>
  </items>
  <totals>
    <subtotal>47.5</subtotal>
    <tax>8.5%</tax>
    <total>51.5375</total>
  </totals>
</invoice>

Group By

This example takes in an XML file that is grouped separating two types of elements: teachers and students, the transform uses the Group By operation to make it into an XML where the top level grouping is "class". Within each class, the students and teachers that are registered in it are listed.

The example goes through the whole set of elements in the input using both a map object operation and a map operation. Note that they differ in that map object processes both key and value of its input, rather than just the keys. It also uses the filter operation to only show the attendees that have the class subject listed as a hobby. As each student may have multiple hobbies, the Multi value selector is used to refer to them all.

Example Transformation

DataWeave
%dw 1.0
%output application/dw
---
classrooms: payload.school.teachers groupBy $.subject mapObject ((teacherGroup, subject) -> {
    class: {
      name: subject,
      teachers: { (teacherGroup map {
        teacher:{
            name: $.name,
            lastName: $.lastName
        }
      }) },
      attendees: { (payload.school.students filter ($.*hobby contains subject) map {
        attendee: {
          name: $.name,
          lastName: $.lastName
        }
      }) }
    }
})

Input: XML

Input
<school>
    <teachers>
        <teacher>
            <name>Mariano</name>
            <lastName>De Achaval</lastName>
            <subject>DW</subject>
        </teacher>
        <teacher>
            <name>Emiliano</name>
            <lastName>Lesende</lastName>
            <subject>DW</subject>
        </teacher>
        <teacher>
            <name>Leandro</name>
            <lastName>Shokida</lastName>
            <subject>Scala</subject>
        </teacher>
    </teachers>
    <students>
        <student>
            <name>Peter</name>
            <lastName>Parker</lastName>
            <hobby>DW</hobby>
            <hobby>Scala</hobby>
        </student>
        <student>
            <name>Homer</name>
            <lastName>Simpson</lastName>
            <hobby>Scala</hobby>
        </student>
    </students>
</school>

Output: JSON

Output
{
  "classrooms": {
    "class": {
      "name": "DW",
      "teachers": [
        {
          "teacher": {
            "name": [
              "Mariano"
            ],
            "lastName": [
              "De Achaval"
            ]
          }
        },
        {
          "teacher": {
            "name": [
              "Emiliano"
            ],
            "lastName": [
              "Lesende"
            ]
          }
        }
      ],
      "attendees": [
        {
          "attendee": {
            "name": [
              "Peter"
            ],
            "lastName": [
              "Parker"
            ]
          }
        }
      ]
    },
    "class": {
      "name": "Scala",
      "teachers": [
        {
          "teacher": {
            "name": [
              "Leandro"
            ],
            "lastName": [
              "Shokida"
            ]
          }
        }
      ],
      "attendees": [
        {
          "attendee": {
            "name": [
              "Peter"
            ],
            "lastName": [
              "Parker"
            ]
          }
        },
        {
          "attendee": {
            "name": [
              "Homer"
            ],
            "lastName": [
              "Simpson"
            ]
          }
        }
      ]
    }
  }
}

Multiple Inputs

In this example, there are three different input JSON files, these three all arrive in one single Mule message, occupying the payload and two flow variables. The payload contains an array of book objects, one flow variable has a set of currency exchange rates, and the other one a query. The transform filters the first input using the conditions passed in the third input, then performs a map to deal with each remaining object separately. Within this map, it defines two variables: it and props. Through the use of @, attributes are added into the XML tags. A second map operation inside the first one calculates the price of each book for each of the currencies provided in the second input. Another map operation displays each element in the author array as a separate <author></author> tag.

See flow variables for how to access flow variables from the input and Attribute selector expressions for how to access XML attributes in DataWeave.

Example Transformation

DataWeave
%dw 1.0
%output application/xml
---
books: {
  (payload filter $.item.properties.year > flowVars.filterParameter.publishedAfter map using (it = $.item, props = $.item.properties) {
    book @(year: props.year): {
      (flowVars.exchangeRate.USD map {
        price @(currency: $.currency): $.ratio * it.price
      }),
      title: props.title,
      authors: { (props.author map {
        author: $
      }) }
    }
  })
}

Inputs

Input 1

Input 1 - Payload
[
  {
    "item": {
      "type": "book",
      "price": 30,
      "properties": {
        "title": "Everyday Italian",
        "author": [
          "Giada De Laurentiis"
        ],
        "year": 2005
      }
    }
  },
  {
    "item": {
      "type": "book",
      "price": 29.99,
      "properties": {
        "title": "Harry Potter",
        "author": [
          "J K. Rowling"
        ],
        "year": 2005
      }
    }
  },
  {
    "item": {
      "type": "book",
      "price": 49.99,
      "properties": {
        "title": "XQuery Kick Start",
        "author": [
          "James McGovern",
          "Per Bothner",
          "Kurt Cagle",
          "James Linn",
          "Kurt Cagle",
          "Vaidyanathan Nagarajan"
        ],
        "year": 2003
      }
    }
  },
  {
    "item": {
      "type": "book",
      "price": 39.95,
      "properties": {
        "title": "Learning XML",
        "author": [
          "Erik T. Ray"
        ],
        "year": 2003
      }
    }
  }
]

Input 2

Input 2 - FlowVariable exchangeRate
{
  "USD": [
    {"currency": "EUR", "ratio":0.92},
    {"currency": "ARS", "ratio":8.76},
    {"currency": "GBP", "ratio":0.66}
  ]
}

Input 3

Input 3 - FlowVariable filterParamenter
{
  "publishedAfter": 2004
}

Output: XML

Output
<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book year="2005">
    <price currency="EUR">27.6</price>
    <price currency="ARS">262.8</price>
    <price currency="GBP">19.8</price>
    <title>Everyday Italian</title>
    <authors>
      <author>Giada De Laurentiis</author>
    </authors>
  </book>
  <book year="2005">
    <price currency="EUR">27.5908</price>
    <price currency="ARS">262.7124</price>
    <price currency="GBP">19.7934</price>
    <title>Harry Potter</title>
    <authors>
      <author>J K. Rowling</author>
    </authors>
  </book>
</books>

Merging Inputs

This example deals with an input that contains a collection of payloads, all grouped as a single Mule event. This kind of input can be produced by having a scatter-gather component in your flow before the transform component.

The first item that makes up the payload contains an array of "price" objects, uniquely identified by a book id, the second item that makes up the payload contains an array of "author" objects, also identified by a book id. This DataWeave transformation merges the two arrays into one, with author and price data by book. book id is used to match these.

Example Transformation

DataWeave
%dw 1.0
%output application/java
---

 payload[0] map using (id = $.bookId) {
 	bookId:		$.bookId,
 	title:		$.title,
 	year: 		$.year,
 	isbn:	 	$.isbn,
 	price: 		$.price,
 	(payload[1] filter ($.*bookId contains id)  map {
 		author:$.author
     })
  }

Inputs

Input 1

Input 1 - Payload[0]
[
  { "bookId":"101",
    "title":"world history",
    "year":"2017",
    "isbn":"11111",
    "price":"19.99"
  },
  {
    "bookId":"202",
    "title":"the great outdoors",
    "year":"2016",
    "isbn":"22222",
    "price":"15.99"
  }
]

Input 2

Input 2 - Payload[1]
[
  {
    "bookId":"101",
    "author":"john doe"
  },
  {
    "bookId":"202",
    "author":"jane doe"
  }
]

Output: JSON

Output
[
  {
    "bookId": "101",
    "title": "world history",
    "year": "2017",
    "isbn": "11111",
    "price": "19.99",
    "author": "john doe"
  },
  {
    "bookId": "202",
    "title": "the great outdoors",
    "year": "2016",
    "isbn": "22222",
    "price": "15.99",
    "author": "jane doe"
  }
]
The sample data section of the Transform message component doesn’t allow you to provide it a collection of multiple payloads as a sample. The only way to test this example is running it.

Remove XML Attributes

As a more advanced use case, you may want to remove specific attributes from within an XML tag that are known to contain sensitive data.

The example defines a function in the dataweave header and then calls it on the body. It goes through the whole set of elements in the input using a mapObject operator. Note that it differs from the map operation in that map object processes both key and value of its input, rather than just the keys. It also uses the when and otherwise operators to pick out only instances where an XML attribute exists, and to do nothing otherwise. It also uses the match operator.

See Attribute selector expressions for how to access XML attributes in DataWeave.

Example Transformation

DataWeave
%dw 1.0
%output application/dw
%var removeAttribute = (element,attrName) ->
element mapObject {
  ($$) @((($$.@ - attrName) when $$.@? otherwise {} ) ) : $ match {
    :object -> removeAttribute($, attrName),
    default -> $
  }
}
---

removeAttribute(payload, "password")

Input: XML

Input
<users>
  <user username="Julian" password="1234"/>
  <user username="Mariano" password="4321"/>
</users>

Output: JSON

Output
{
  users @(): {
    user @(
      username: "Julian"
    ): "",
    user @(
      username: "Mariano"
    ): ""
  }
}

Output self-closing XML tags

When producing an output in XML, DataWeave by default outputs every value as enclosed between an opening and a closing tag:

  <parentElement>
    <emptyElement1>15</emptyElement1>
    <emptyElement2>1</emptyElement2>
    <emptyElement3>8</emptyElement3>
  </parentElement>

In case you have empty fields that don’t hold any values within, you might find that you instead want to output a single tag that self-closes. You can set the DW output directive so that your transform generates an output that follows this style for each case. You configure this by setting the inlineCloseOn property to "empty".

Example Transformation

DataWeave
%dw 1.0
%output application/xml inlineCloseOn="empty"
---
payload

Input: JSON

Input
{
  "customer": {
    "userName": "John Doe",
    "password":{},
    "status":"active",
    "lastLogin":{}
  }
}

Output: XML

Output
<?xml version='1.0' encoding='UTF-8'?>
<customer>
  <userName>John Doe</userName>
  <password/>
  <status>active</status>
  <lastLogin/>
</customer>
See more XML reader and writer properties on DataWeave formats.

Configure CSV Reader

DataWeave supports CSV inputs and outputs, by configuring the reader and writer properties, you can adapt it to different conventions regarding separations, line breaks, etc. Other formats also allow for this kind of configuration. See To Define Input and Output Structure of a Transformation for how to do this on the UI, or look at the DataWeave XML Reference for the required XML syntax. You can also see a full reference of the reader properties available with CSV format on DataWeave formats.

Reader properties are set as part of the XML dw:transform-message component, whilst writer properties are specified in the DataWeave code itself, as part of the output directive. You can see a full reference to the writer properties available with CSV format on DataWeave formats.

This example takes a CSV file that is formatted in a certain way (with ; as a separator) and outputs another CSV file that is formatted differently (with , as a separator, and all values quoted).

Example Transformation

XML
<dw:transform-message metadata:id="ab7c919b-c57c-47da-a1e7-207a7e571341" doc:name="Transform Message">
     <dw:input-payload mimeType="application/csv" doc:sample="sample_data/list_csv.csv">
         <dw:reader-property name="header" value="false"/>
         <dw:reader-property name="separator" value=";"/>
     </dw:input-payload>
     <dw:set-payload>
       <![CDATA[
%dw 1.0
%output application/csv separator = "," , header = false, quoteValues = true
---
payload
      ]]>
    </dw:set-payload>
</dw:transform-message>

Note that the code above includes not just the DW transformation, but the XML of the Transform Message component that contains it, to display the reader properties configured in it.

Input: CSV

Input
name;address;phone
George Harrisson; 1234 Abbey Road, London; 12341123
David Gilmour; 3434 Diamond st., Dark side of the moon; 12341234
Steven Wilson; 13/16 Raven st., Somewhere but not Here; 1234567

Output: CSV

Output
"name","address","phone"
"George Harrisson"," 1234 Abbey Road, London"," 12341123"
"David Gilmour"," 3434 Diamond st., Dark side of the moon"," 12341234"
"Steven Wilson"," 13/16 Raven st., Somewhere but not Here"," 1234567"

Parse Dates with Different Separators

Suppose that you want to include a date field that admits using different characters as separators between the elements of the date, and want DataWeave to be able to parse them as if they all were the same. For this example, imagine that you want to accept these three formats:

  • 26-JUL-2016

  • 26/JUL/2016

  • 26.JUL.2016

To do this, you can normalize the input with the replace operator so that they all match a single pattern, and then turn the resulting string to a date with coerce to date.

To improve the clarity in your code, you can easily abstract the normalizing of your string into custom a function, declaring it only once on your DW header, and then using it as many times as necessary by simply referencing this function.

Example Transformation

This is what the function for this example would look like:

DataWeave
%function normalize(date) date replace "/" with "-" replace "." with "-"

You can declare this function on the header of a DW script and then simply call it from anywhere in the DW body. The example below shows the full DataWeave transform for doing this:

DataWeave
%dw 1.0
%output text/xml
%function normalize(date) date replace "/" with "-" replace "." with "-"
---
{
dates : {
date1: normalize("26-JUL-16") as :date {format: "d-MMM-yy"} as :string {format: "yyyy-MM-dd"},
date2: normalize("26/JUL/16") as :date {format: "d-MMM-yy"} as :string {format: "yyyy-MM-dd"},
date3: normalize("26.JUL.16") as :date {format: "d-MMM-yy"} as :string {format: "yyyy-MM-dd"}
  }
}

This example only deals with dates that use different separator characters, for a more advanced use case that deals with different date patterns, see Conditional Date Parsing

Conditional Date Parsing

Suppose that you want to include a date field that admits different formats, and want DataWeave to be able to parse each accordingly. For this example, imagine that you want to accept these three formats:

  • Sun, 06 Nov 1994 08:49:37 GMT = E, d LLL u H:m:s O

  • Sun Nov 6 08:49:37 1994 = cccc, d-LLL-u H:m:s O

  • Sunday, 06-Nov-94 08:49:37 GMT = E LLL d H:m:s u

Start out by writing a regular expression to match each of them:

  • Sun, 06 Nov 1994 08:49:37 GMT = /^[A-z][A-z][A-z],/

  • Sun Nov 6 08:49:37 1994 = /^[A-z][A-z][A-z]\s/

  • Sunday, 06-Nov-94 08:49:37 GMT = This will be the default

You can use these regular expressions in a DW function that first evaluates a string to see which regular expression it matches, and then converts it through the the corresponding operation. This function should do the following:

  1. Take the input string as argument

  2. Match it with regular expressions in order to determine which format it’s in

  3. Run the coerce to date operator with the corresponding properties

  4. Return a date time object

Example Transformation

This is what the function looks like:

DataWeave
%var parseDate = (dateStr) -> dateStr as :localdatetime {format: "E, d LLL u H:m:s O"} when (dateStr contains /^[A-z][A-z][A-z],/) otherwise (dateStr as :localdatetime {format: "E LLL d H:m:s u"} when (dateStr contains /^[A-z][A-z][A-z]\s/) otherwise dateStr as :localdatetime {format: "cccc, d-LLL-u H:m:s O"})

You can declare this function on the header of a DW script and then simply call it from anywhere in the DW body like so:

DataWeave
%dw 1.0
%output application/json
%var parseDate = (dateStr) -> dateStr as :localdatetime {format: "E, d LLL u H:m:s O"} when (dateStr contains /^[A-z][A-z][A-z],/) otherwise (dateStr as :localdatetime {format: "E LLL d H:m:s u"} when (dateStr contains /^[A-z][A-z][A-z]\s/) otherwise dateStr as :localdatetime {format: "cccc, d-LLL-u H:m:s O"})
---
date: parseDate(payload.dateString)

Create Mule Config

This example use of DataWeave does not take any input—​rather, it simply creates an XML structure out of hard-coded instructions, which reference several external sources using certain namespace directives. What you end up with is a set of XML tags mirroring the structure of a Mule application XML file, including attributes that go inside these tags through the use of @.

See Attribute selector expressions for how to access XML attributes in DataWeave.

DataWeave Code

Example Transformation

DataWeave
%dw 1.0
%output application/xml encoding="UTF-8"
%namespace http http://www.mulesoft.org/schema/mule/http
%namespace as2 http://www.mulesoft.org/schema/mule/as2
%namespace spring http://www.springframework.org/schema/beans
%namespace doc http://www.mulesoft.org/schema/mule/documentation
%namespace sftp http://www.mulesoft.org/schema/mule/sftp
---

mule: {

  http#connector @(name:"HTTP_HTTPS",
                                  cookieSpec:"netscape",
                                  alidateConnections:"true",
                                sendBufferSize:"0",
                                receiveBufferSize:"0",
                                receiveBacklog:"0",
                                clientSoTimeout:"10000",
                                serverSoTimeout:"10000",
                                    socketSoLinger:"0",
                                doc#name:"HTTP-HTTPS"
  ): {},

  http#endpoint @(exchange-pattern:"request-response",
                                host:"localhost",
                                    port:"\${http.port}",
                                connector-ref:"HTTP_HTTPS",
                                method:"POST",
                                    name:"http-receive-endpoint",
                                doc#name:"HTTP"
  ): {},

  http#endpoint @(exchange-pattern:"request-response",
                                host:"btsci-dev.cloudapp.net",
                                    port:"80",
                                connector-ref:"HTTP_HTTPS",
                                method:"POST",
                                name:"http-send-endpoint",
                                    doc#name:"HTTP",
                                path:"as2tests/scenario1/BTSHTTPReceive.dll"
  ): {},

  as2#config @(name:"receive-as2-config",
                                 httpEndpointRef:"http-receive-endpoint",
                                     doc#name:"AS2"
  ): {},

  as2#config @(name:"send-as2-config",
                                httpEndpointRef:"http-send-endpoint",
                                    doc#name:"AS2"
  ): {},


  flow @(name:"receive-flow"): {

            as2#receive @(config-ref:"receive-as2-config",
                                  doc#name:"Receive EDI over AS2",
                                            keyStorePassword:"passw0rd",
                                  keyStorePath:"myPartner.p12"): {},
            sftp#outbound-endpoint @(exchange-pattern:"one-way",
                                            host:"dev.modusintegration.com",
                                  port:"22",
                                  responseTimeout:"10000",
                                            doc#name:"Save EDI doc",
                                  password:"pa\$\$w0rd",
                                  path:"/mule/inbox",
                                            user:"guest"): {}
  },

  flow @(name:"send-flow"):{
          sftp#inbound-endpoint @(host:"dev.modusintegration.com",
                            port:"22",
                    responseTimeout:"10000",
                    doc#name:"Read EDI doc",
                    password:"\$pa\$\$w0rd",
                            path:"/mule/outbox",
                    user:"guest"  ):{},

    as2#send @(config-ref:"send-as2-config",
                      as2From:"myPartner",
                            as2To:"myCompany",
                      doc#name:"Send EDI over AS2",
                      encrypt:"true",
                            keyStorePassword:"passw0rd",
                      keyStorePath:"myPartner.p12",
                      sign:"true"):{}
  }

}

Output: XML

Output
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:as2="http://www.mulesoft.org/schema/mule/as2"
      xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
      xmlns:sftp="http://www.mulesoft.org/schema/mule/sftp">
    <http:connector name="HTTP_HTTPS" cookieSpec="netscape" alidateConnections="true" sendBufferSize="0" receiveBufferSize="0" receiveBacklog="0" clientSoTimeout="10000" serverSoTimeout="10000" socketSoLinger="0" doc:name="HTTP-HTTPS"></http:connector>
    <http:endpoint exchange-pattern="request-response" host="localhost" port="${http.port}" connector-ref="HTTP_HTTPS" method="POST" name="http-receive-endpoint" doc:name="HTTP"></http:endpoint>
    <http:endpoint exchange-pattern="request-response" host="btsci-dev.cloudapp.net" port="80" connector-ref="HTTP_HTTPS" method="POST" name="http-send-endpoint" doc:name="HTTP" path="as2tests/scenario1/BTSHTTPReceive.dll"></http:endpoint>
    <as2:config name="receive-as2-config" httpEndpointRef="http-receive-endpoint" doc:name="AS2"></as2:config>
    <as2:config name="send-as2-config" httpEndpointRef="http-send-endpoint" doc:name="AS2"></as2:config>
    <flow name="receive-flow">
        <as2:receive config-ref="receive-as2-config" doc:name="Receive EDI over AS2" keyStorePassword="passw0rd" keyStorePath="myPartner.p12"></as2:receive>
        <sftp:outbound-endpoint exchange-pattern="one-way" host="dev.modusintegration.com" port="22" responseTimeout="10000" doc:name="Save EDI doc" password="pa$$w0rd" path="/mule/inbox" user="guest"></sftp:outbound-endpoint>
    </flow>
    <flow name="send-flow">
        <sftp:inbound-endpoint host="dev.modusintegration.com" port="22" responseTimeout="10000" doc:name="Read EDI doc" password="$pa$$w0rd" path="/mule/outbox" user="guest"></sftp:inbound-endpoint>
        <as2:send config-ref="send-as2-config" as2From="myPartner" as2To="myCompany" doc:name="Send EDI over AS2" encrypt="true" keyStorePassword="passw0rd" keyStorePath="myPartner.p12" sign="true"></as2:send>
    </flow>
</mule>

Create Mule POM

This example does not take any input in, it simply creates an XML output out of hard-coded instruction. It references several external sources through namespace directives and defines a version as a constant in the header, that is then referenced in the body. It creates a set of XML tags that replicate the structure of a Mule POM file, including attributes inside these tags that are added through the use of @ and references to a variable.

See Attribute selector expressions for how to access XML attributes in DataWeave.

Example Transformation

DataWeave

DataWeave
%dw 1.0
%output application/xml
%namespace xsi http://www.w3.org/2001/XMLSchema-instance
%var modelVersion = "4.0.0"
---
{
    project: {

      modelVersion: modelVersion,
    groupId: "com.mycompany",
    version: "1.0.0-SNAPSHOT",
    packaging: "mule",
    name: "Mavenito",

    properties: {
        "project.build.sourceEncoding": "UTF-8",
      "project.reporting.outputEncoding": "UTF-8",
      "mule.version": "3.6.0",
      "mule.tools.version": "1.0"
    },

    build: {
        plugins: {
          plugin: {
            groupId: "org.mule.tools.maven",
          artifactId: "mule-app-maven-plugin",
          version: "\${mule.tools.version}",
          extensions: true,
          configuration: {
                        copyToAppsDirectory: true
          }
        },
        plugin: {
          artifactId: "maven-assembly-plugin",
                    version: "2.2.1",
                  configuration: {
                            descriptorRefs: {
                                descriptorRef: "project"
                }
             }
        },
        plugin: {
          groupId: "org.mojohaus",
                     artifactId: "build-helper-maven-plugin",
                    version:1.7,
                    executions: {
                            execution: {
                                id: "add-resource",
                                phase: "generate-resources",
                                goals: {
                                    goal: "add-resource"
                                },
                                configuration: {
                                        resources: {
                                            resource: {
                                                directory: "src/main/app/"
                                            },
                                            resource: {
                                                directory: "mappings/"
                      }
                                    }
                                }
                            },
                    configuration: {
                            resources: {
                 resource: {
                         directory: "src/main/api/"
                                    }
              }
          }
        }
      },
      plugin: {
        groupId: "org.apache.maven.plugins",
        artifactId: "maven-dependency-plugin",
        version: "2.4",
        executions: {
              execution: {
                  id: "copy-clover-plugins",
              phase: "validate",
              goals: {
                  goal: "copy"
              },
              configuration: {
                 overWriteReleases: true,
                 overWriteSnapshots: true,
                 overWriteIfNewer: true,
                 stripVersion: true,
                 outputDirectory: "\${project.build.testOutputDirectory}"
              },
              artifactItems: {
                                artifactItem: {
                           groupId: "com.cloveretl",
                        artifactId: "cloveretl-engine",
                                        version: "\${mule.version}",
                                        type: "zip"
                    }
                 }
              }
        }
      },
      plugin: {
          artifactId: "maven-antrun-plugin",
                version: "1.7",
        executions: {
               execution: {
                        phase: "compile",
                        configuration: {
                            tasks: {
                                    unzip @(dest: "\${project.build.testOutputDirectory}",
                          src: "\${project.build.testOutputDirectory}/cloveretl-engine.zip"): {}
                        }
           },
           goals: {
                            goal: "run"
           }
         }
           }
      }
    }
  },

  dependencies: {
    dependency: {
        groupId: "com.mulesoft.muleesb",
      artifactId: "mule-core-ee",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "com.mulesoft.muleesb.modules",
      artifactId: "mule-module-spring-config-ee",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "org.mule.transports",
      artifactId: "mule-transport-file",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "org.mule.transports",
      artifactId: "mule-transport-http",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "com.mulesoft.muleesb.transports",
      artifactId: "mule-transport-jdbc-ee",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "com.mulesoft.muleesb.transports",
      artifactId: "mule-transport-jms-ee",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "org.mule.transports",
      artifactId: "mule-transport-vm",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "org.mule.modules",
      artifactId: "mule-module-scripting",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "org.mule.modules",
      artifactId: "mule-module-xml",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "org.mule.tests",
      artifactId: "mule-tests-functional",
      version: "\${mule.version}",
      scope: "provided"
    },
    dependency: {
        groupId: "com.cloveretl",
      artifactId: "cloveretl-engine",
      version: "\${mule.version}",
      scope: "provided"
    }
    },

  repositories: {
      repository: {
        id: "Central",
      name: "Central",
      url: "http://repo1.maven.org/maven2/",
      layout: "default"
    },
    repository: {
        id: "mulesoft-releases",
      name: "MuleSoft Releases Repository",
      url: "http://repository.mulesoft.org/releases/",
      layout: "default"
    },
    repository: {
        id: "mulesoft-snapshots",
      name: "MuleSoft Snapshots Repository",
      url: "http://repository.mulesoft.org/snapshots/",
      layout: "default"
    }
  },


  pluginRepositories: {
    pluginRepository: {
                id: "mulesoft-release",
                name: "mulesoft release repository",
                layout: "default",
        url: "http://repository.mulesoft.org/releases/",
                 snapshots: {
                enabled: false
                }
    }
  }

 }
}

Output: XML

Output
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany</groupId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>mule</packaging>
  <name>Mavenito</name>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <mule.version>3.6.0</mule.version>
    <mule.tools.version>1.0</mule.tools.version>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.mule.tools.maven</groupId>
        <artifactId>mule-app-maven-plugin</artifactId>
        <version>${mule.tools.version}</version>
        <extensions>true</extensions>
        <configuration>
          <copyToAppsDirectory>true</copyToAppsDirectory>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2.1</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>project</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.mojohaus</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <version>1.7</version>
        <executions>
          <execution>
            <id>add-resource</id>
            <phase>generate-resources</phase>
            <goals>
              <goal>add-resource</goal>
            </goals>
            <configuration>
              <resources>
                <resource>
                  <directory>src/main/app/</directory>
                </resource>
                <resource>
                  <directory>mappings/</directory>
                </resource>
              </resources>
            </configuration>
          </execution>
          <configuration>
            <resources>
              <resource>
                <directory>src/main/api/</directory>
              </resource>
            </resources>
          </configuration>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.4</version>
        <executions>
          <execution>
            <id>copy-clover-plugins</id>
            <phase>validate</phase>
            <goals>
              <goal>copy</goal>
            </goals>
            <configuration>
              <overWriteReleases>true</overWriteReleases>
              <overWriteSnapshots>true</overWriteSnapshots>
              <overWriteIfNewer>true</overWriteIfNewer>
              <stripVersion>true</stripVersion>
              <outputDirectory>${project.build.testOutputDirectory}</outputDirectory>
            </configuration>
            <artifactItems>
              <artifactItem>
                <groupId>com.cloveretl</groupId>
                <artifactId>cloveretl-engine</artifactId>
                <version>${mule.version}</version>
                <type>zip</type>
              </artifactItem>
            </artifactItems>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.7</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <configuration>
              <tasks>
                <unzip dest="${project.build.testOutputDirectory}" src="${project.build.testOutputDirectory}/cloveretl-engine.zip"></unzip>
              </tasks>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>com.mulesoft.muleesb</groupId>
      <artifactId>mule-core-ee</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.mulesoft.muleesb.modules</groupId>
      <artifactId>mule-module-spring-config-ee</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mule.transports</groupId>
      <artifactId>mule-transport-file</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mule.transports</groupId>
      <artifactId>mule-transport-http</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.mulesoft.muleesb.transports</groupId>
      <artifactId>mule-transport-jdbc-ee</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.mulesoft.muleesb.transports</groupId>
      <artifactId>mule-transport-jms-ee</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mule.transports</groupId>
      <artifactId>mule-transport-vm</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mule.modules</groupId>
      <artifactId>mule-module-scripting</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mule.modules</groupId>
      <artifactId>mule-module-xml</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mule.tests</groupId>
      <artifactId>mule-tests-functional</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.cloveretl</groupId>
      <artifactId>cloveretl-engine</artifactId>
      <version>${mule.version}</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <id>Central</id>
      <name>Central</name>
      <url>http://repo1.maven.org/maven2/</url>
      <layout>default</layout>
    </repository>
    <repository>
      <id>mulesoft-releases</id>
      <name>MuleSoft Releases Repository</name>
      <url>http://repository.mulesoft.org/releases/</url>
      <layout>default</layout>
    </repository>
    <repository>
      <id>mulesoft-snapshots</id>
      <name>MuleSoft Snapshots Repository</name>
      <url>http://repository.mulesoft.org/snapshots/</url>
      <layout>default</layout>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <id>mulesoft-release</id>
      <name>mulesoft release repository</name>
      <layout>default</layout>
      <url>http://repository.mulesoft.org/releases/</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </pluginRepository>
  </pluginRepositories>
</project>

Pass Functions as Arguments

The following example makes all "keys" lower case. The DataWeave header defines a function that receives another function as an argument and then calls that function in the body, applying itself to the keys and not the values it processes. The function that is sent as an argument is a simple one that uses the lower operator to set the specified text to lower case.

The example goes through the whole set of elements in the input using a mapObject operator. It also uses the when and otherwise operators to pick out only instances when an XML attribute exists, and do nothing otherwise. It also uses the match operator.

See Attribute selector expressions on how to access XML attributes in DataWeave.

Example Transformation

DataWeave
%dw 1.0
%output application/xml
%function mapKeys(element, func)
  element match {
    obj is :object -> obj mapObject {
      "$(func($$))" @(($$.@ when $.@? otherwise {}) ): mapKeys($, func)
    },
    default -> element
  }
---
mapKeys(payload, ((key) ->(lower key)))

Input: XML

Input
<CATALOG>
  <CD>
    <TITLE name="foo">Empire Burlesque</TITLE>
    <ARTIST>Bob Dylan</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Columbia</COMPANY>
    <PRICE>10.90</PRICE>
    <YEAR>1985</YEAR>
  </CD>
  <CD>
    <TITLE>Hide your heart</TITLE>
    <ARTIST>Bonnie Tyler</ARTIST>
    <COUNTRY>UK</COUNTRY>
    <COMPANY>CBS Records</COMPANY>
    <PRICE>9.90</PRICE>
    <YEAR>1988</YEAR>
  </CD>
</CATALOG>

Output: XML

Output
<?xml version='1.0' encoding='US-ASCII'?>
<catalog>
  <cd>
    <title name="foo">Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <country>USA</country>
    <company>Columbia</company>
    <price>10.90</price>
    <year>1985</year>
  </cd>
  <cd>
    <title>Hide your heart</title>
    <artist>Bonnie Tyler</artist>
    <country>UK</country>
    <company>CBS Records</company>
    <price>9.90</price>
    <year>1988</year>
  </cd>
</catalog>

Dynamic Mapping Based on a Definition

Based on a mapping definition, stored for instance in a DB table, you can dynamically execute a transformation. Here you have two inputs, one coming in via the payload, the other from a flowVariable called mapping.

  • The whole set of elements in the input is mapped using a map operator.

  • The example also uses the default operator.

Note that for this example to work, on the payload input you must set the reader configuration so that the 'nullValueOn' attribute is "empty". See To Define Input and Output Structure of a Transformation.

Example Transformation

DataWeave
%dw 1.0
%output application/json
%var applyMapping = (input, mappingsDef) ->
{
  (mappingsDef map ((mappingDef) -> {
  (mappingDef.target) : input[mappingDef.source] default mappingDef.default
  }))
}
---
payload.sfdc_users.*sfdc_user map ((user) -> applyMapping(user, mapping))

Inputs

Input - Payload
<sfdc_users>
    <sfdc_user>
      <sfdc_name>Mariano</sfdc_name>
      <sfdc_last_name>Achaval</sfdc_last_name>
      <sfdc_employee>true</sfdc_employee>
    </sfdc_user>
    <sfdc_user>
      <sfdc_name>Julian</sfdc_name>
      <sfdc_last_name>Esevich</sfdc_last_name>
      <sfdc_employee>true</sfdc_employee>
    </sfdc_user>
    <sfdc_user>
      <sfdc_name>Leandro</sfdc_name>
      <sfdc_last_name>Shokida</sfdc_last_name>
    </sfdc_user>
</sfdc_users>
Input - flowVariable Mapping
[
  {
    "source": "sfdc_name",
    "target": "name",
    "default": "---"
  },
  {
    "source": "sfdc_last_name",
    "target": "lastName",
    "default": "---"
  },
  {
    "source": "sfdc_employee",
    "target": "user",
    "default": true
  }
]

Output: JSON

Output
[
  {
    "name": "---",
    "lastName": "---",
    "user": true
  }
]

Conditional list reduction via a function

When presented with nested lists of data, you often need to flatten the data for a simplified output, extracting only the values required. Here you have a set of JSON data that returns a nested set of interests for a user and within are further nested sets. Certain values from the nested sets tags and contenttypes are needed to be extracted, with a conditional check to ensure contenttypes is present.

  • The whole set of elements in the input is mapped using a map operator.

  • This example uses the reduce operator.

  • This example also uses the when operator to conditionally display the last field.

  • This example also uses the splitBy operator to parse the input.

  • Finally this example takes advantage of the ability to define a function for re-use.

Example Transformation

DataWeave
%dw 1.0
%output application/json
%function reduceMapFor(data) data reduce (($$ splitBy ":")[0] ++ "," ++ ($ splitBy ":")[0])
---
payload.results map
	{
		email: $.profile.email,
		name: $.profile.firstName,
	 	tags: reduceMapFor($.data.interests.tags[0]),
	 	(contenttypes: reduceMapFor($.data.interests.contenttypes[0]))  when (sizeOf $.data.interests.contenttypes[0]) > 0
	}

Input: JSON

Input - Payload

{
  "results": [
    {
      "profile": {
        "firstName": "john",
        "lastName": "doe",
        "email": "johndoe@demo.com"
      },
      "data": {
        "interests": [
          {
            "language": "English",
            "tags": [
              "digital-strategy:Digital Strategy",
              "innovation:Innovation"
            ],
            "contenttypes": []
          }
        ]
      }
    },
    {
      "profile": {
        "firstName": "jane",
        "lastName": "doe",
        "email": "janedoe@demo.com"
      },
      "data": {
        "interests": [
          {
            "language": "English",
            "tags": [
              "tax-reform:Tax Reform",
              "retail-health:Retail Health"
            ],
            "contenttypes": [
              "News",
              "Analysis",
              "Case studies",
              "Press releases"
            ]
          }
        ]
      }
    }
  ],
  "objectsCount": 2,
  "totalCount": 2,
  "statusCode": 200,
  "errorCode": 0,
  "statusReason": "OK"
}

Output: JSON

Output
[
  {
    "email": "johndoe@demo.com",
    "name": "john",
    "tags": "digital-strategy,innovation"
  },
  {
    "email": "janedoe@demo.com",
    "name": "jane",
    "tags": "tax-reform,retail-health",
    "contenttypes": "News,Analysis,Case studies,Press releases"
  }
]