Welcome back to our deep dive into MuleSoft integration! If you read Part I, you know that DataWeave is the absolute engine that keeps your data flowing smoothly between systems. However, real-world integration isn't always simple mapping; sometimes, it gets messy.
In Part II of this series, we are tackling the tricky stuff. We are talking about extracting hidden XML metadata, conditionally updating payloads based on their type, and flattening complex structures into clean CSVs. Whether you are a beginner looking to level up or a senior developer needing a quick snippet, these 10 scenarios cover the "Input vs. Output" challenges you face daily.
Let’s get your hands dirty with the code.
1. Extracting XML Metadata
Sometimes the data you need isn't in the body; it's hidden in the XML declaration headers. Here is how you can extract specific encoding and media type attributes from an XML input using DataWeave selectors.
Input:
<?xml version='1.0' encoding='UTF-8'?><menusList><menus><menu><id>file</id><value>File</value><popup><menuitem><value>New</value><onclick>CreateNewDoc()</onclick></menuitem><menuitem><value>Open</value><onclick>OpenDoc()</onclick></menuitem><menuitem><value>Close</value><onclick>CloseDoc()</onclick></menuitem></popup></menu></menus></menusList>
Target Output:
{
"encoding": "UTF-8",
"mediaType": "application/xml"
}
Solution 1: Using Selectors
This method uses the selector syntax to grab metadata directly.
%dw 2.0
output application/json
---
{
"encoding": payload.^encoding,
"mediaType": payload.^mediaType
}
Solution 2: Raw Data Approach
Alternatively, you can access the raw data object.
%dw 2.0
output application/json
---
payload.^ - "raw"
2. Conditional Updates
The update operator is incredibly powerful, but what if your input structure isn't consistent? In this scenario, we update a value only if the payload acts like an object, allowing the script to handle both Array and Object inputs dynamically.
Input 1 (Array):
[{"menusList": {"menus": {"name" : "sai"}}}]
Input 2 (Object):
{"menusList": {"menus": {"name" : "sai"}}}
Target Output (Scenario 2):
{"menusList": "this is an object"}
Solution 1: Type Check
We use typeOf to check the data structure explicitly.
%dw 2.0
output application/json
---
if(typeOf(payload) ~= "Object")
payload update {
case .menusList -> "this is an object"
}
else payload
Solution 2: Pattern Matching
A more elegant solution using pattern matching within the update case.
%dw 2.0
output application/json
---
payload update {
case mLit at .menusList if(payload is Object)-> "this is an object"
}
3. Dynamic Key-Value Swapping
This is a fun challenge often seen in data restructuring. We need to turn values into keys and keys into values, effectively flattening the structure into a single array of objects without using mapObject.
Input:
{
"id": "file",
"value": "File",
"id": "file",
"value": "File"
}
Target Output:
[
{"file": "id"},
{"File": "value"},
{"file": "id"},
{"File": "value"}
]
Solution 1: Mapping Keys and Values
%dw 2.0
output application/json
var keys = keysOf(payload)
var values = valuesOf(payload)
---
keys map(
(values[$$]) : $
)
Solution 2: Using Pluck
The pluck operator is perfect for iterating over objects to produce arrays.
%dw 2.0
output application/json
---
payload pluck(
($):$$
)
4. Flattening JSON to CSV
Nested objects (like an address block inside a user profile) usually break standard CSV exports. Here is how to flatten the structure to ensure a clean, single-row CSV output.
Input:
[
{"id": 123,"name": "sample name","address": {"pin": 534460,"place": "ap","ph": 9848022338}},
{"id": 1,"name": "sample name2","address": {"pin": 123,"place": "ts","ph": 98765453459}}
]
Target Output:
id,name,pin,place,ph
123,sample name,534460,ap,9848022338
1,sample name2,123,ts,98765453459
Solution 1: Merge and Filter
This approach merges the nested object with the parent and filters out nulls.
%dw 2.0
output application/csv
import * from dw::core::Objects
---
payload map(
$ match {
case y is Object -> ($ - "address") mergeWith $.address
else -> null
} filterObject !($$ ~= null)
)
Solution 2: Direct Concatenation
A simpler way using the concatenation operator ++.
%dw 2.0
output application/csv
---
payload map(
$ - "address" ++ $.address
)
5. Handling Duplicates
Data quality is huge in integration. Here are four ways to isolate only the duplicate values from an array.
Input:
[1,2,3,4,5,6,7,1,2,7]
Target Output:
[1,2,7]
Solution 1: GroupBy
%dw 2.0
output application/json
---
payload groupBy ($) filterObject ((value, key, index) -> sizeOf(value)>1) pluck($[0])
Solution 2: Skip Nulls
We use the skipNullOn directive to keep the output clean.
%dw 2.0
output application/json skipNullOn="everywhere"
---
payload groupBy ($) pluck(
if(sizeOf($)>1)$[0] else null
)
Solution 3: Filter and Distinct
%dw 2.0
output application/json
fun duplicateCheck(in) = (
sizeOf(payload filter($ ~= in))>1
)
---
payload filter (duplicateCheck($)) distinctBy ($)
Solution 4: Using Find
%dw 2.0
output application/json
---
payload filter(
sizeOf(payload find $)>1
) distinctBy($)
6. Finding Non-Duplicate (Unique) Values
Conversely, sometimes you need to find the items that appear exactly once, effectively filtering out any repeated noise.
Input:
[1,2,3,4,5,6,7,1,2,7]
Target Output:
[3,4,5,6]
Solution 1: IsEmpty Check
%dw 2.0
output application/json
---
(payload groupBy $ pluck(
("":$[0])if(sizeOf($)==1)
)filter(!isEmpty($))).""
Solution 2: Conditional Pluck
%dw 2.0
output application/json skipNullOn="everywhere"
---
payload groupBy ($) pluck(
if(sizeOf($)<=1) $[0] else null
)
Solution 3: Custom Function
%dw 2.0
output application/json
fun duplicateCheck(in) = (
sizeOf(payload filter($ ~= in))<=1
)
---
payload filter (duplicateCheck($)) distinctBy ($)
Solution 4: Using Find
%dw 2.0
output application/json
---
payload filter(
sizeOf(payload find $)<=1
) distinctBy($)
Solution 5: GroupBy and FilterObject
%dw 2.0
output application/json
---
payload groupBy ($) filterObject ((value, key, index) -> sizeOf(value)<=1) pluck($[0])
7. Reformatting and Shifting Keys
In this scenario, we clean up sparse objects and shift keys (e.g., from pi1 to pi0) to create a cleaner, sequential output.
Input:
[
{"pi1": "jawan", "pi2": "", "pi3": "", "pi4": "wazir"},
{"pi1": "", "pi2": "nawaz", "pi3": "", "pi4": "wazir"},
{"pi1": "", "pi2": "", "pi3": "", "pi4": "wazir"}
]
Target Output:
[
{"pi0": "jawan", "pi1": "wazir", "pi2": "", "pi3": ""},
{"pi0": "nawaz", "pi1": "wazir", "pi2": "", "pi3": ""},
{"pi0": "wazir", "pi1": "", "pi2": "", "pi3": ""}
]
Solution 1: Map and Filter
%dw 2.0
output application/json
import * from dw::core::Strings
---
payload map using(item = ($ pluck $)filter(!isEmpty($)))(
$ mapObject {
("pi"++$$$) : item[$$$] default ""
}
)
Solution 2: Using OrderBy
%dw 2.0
output application/json
---
payload map ((item, index) ->
(item orderBy -sizeOf($)) mapObject(
("pi" ++ $$$) : $
)
)
8. Merging Parallel Arrays
This is a classic Salesforce or database integration scenario. You receive separate arrays for IDs and Record Types, and you need to "zip" them into a single list of objects.
Input:
{
"workTypeID": ["08q4W000000xcHWQAY","08q4W000000xcHWQAY","08q4W000000xcHWQAY","08q4W000000xcHWQAY"],
"accountID": ["0014W00002p2Ui0QAE","0014W00002ohJsWQAU","0014W00002oraWRQAY","0014W00002orO6qQAE"],
"recordTypeID": ["0124W000001d2huQAA","0124W000001d2huQAA","0124W000001d2huQAA","0124W000001d2huQAA"]
}
Target Output:
[
{"workTypeID": "08q4W000000xcHWQAY", "accountID": "0014W00002p2Ui0QAE", "recordTypeID": "0124W000001d2huQAA"},
{"workTypeID": "08q4W000000xcHWQAY", "accountID": "0014W00002ohJsWQAU", "recordTypeID": "0124W000001d2huQAA"},
...
]
Solution 1: Standard Map
%dw 2.0
output application/json
---
payload.workTypeID map{
workTypeID : $,
accountID: payload.accountID[$$],
recordTypeID : payload.recordTypeID[$$]
}
Solution 2: Count-based Map
%dw 2.0
output application/json
var itemCount = 1 to sizeOf((payload orderBy ((value, key) -> -sizeOf(value)))[0])
---
itemCount map(
{
workTypeID : payload.workTypeID[$$],
accountID : payload.accountID[$$],
recordTypeID : payload.recordTypeID[$$]
}
)
9. Filtering and Grouping Students
Here we need to group data by student ID and return only the subjects where they passed, filtering out any failures.
Input:
[
{ "student": "s1", "maths": "pass", "sciences": "fail", "english": "pass" },
...
]
Target Output:
[
{ "s1": [ "pass", "pass" ] },
...
]
Solution 1: GroupBy and Pluck
%dw 2.0
output application/json
---
payload groupBy ($.student) pluck $ map(
($.student[0]): {($)} pluck $ filter($ ~= "pass")
)
Solution 2: FlatMap
%dw 2.0
output application/json
---
payload groupBy ($.student) pluck(
($$) : $ flatMap(valuesOf($ - "student")) filter($ ~= "pass")
)
Solution 3: ValuesOf
%dw 2.0
output application/json
---
payload map(
($.student) : valuesOf($ - "student") filter($ ~= "pass")
)
10. Consolidating Split Records
Finally, we have a scenario where a single entity (like "sai") is split across multiple objects containing different fields. We need to merge them into one complete record based on their ID.
Input:
[
{ "sid": 123, "sfname": "sai" },
{ "sid": 123, "slname": "kumar", "snum": 9087654132 }
]
Target Output:
[
{ "sid": 123, "sfname": "sai", "slname": "kumar", "snum": 9087654132 }
]
Solution 1: GroupBy and DistinctBy
%dw 2.0
output application/json
---
payload groupBy $.sid pluck $ map(
{($)} distinctBy ((item, index) -> item)
)
Solution 2: Custom Function
%dw 2.0
output application/json
fun getValues(id) = (
{(payload filter($.sid ~= id))} - "sid" distinctBy ($)
)
---
payload map(
{sid : $.sid} ++ (getValues($.sid) default {})
) distinctBy ($)
Solution 3: Concise Grouping
%dw 2.0
output application/json
---
payload groupBy ($.sid) pluck({($)} distinctBy ($))
Hopefully, these examples help you navigate the complexities of DataWeave transformations!