%dw 1.0
%output application/xml
---
{
address: payload.people.person.address
}
Selectors
DataWeave 1.1 is compatible with Mule Runtime Engine 3.8. MuleSoft recommends against deployments to Mule 3.8. Standard Support for this version ended on November 16, 2018, and Mule 3.8 will reach its End of Life on November 16, 2021, when Extended Support ends. |
The complex structure of Objects and Arrays can be navigated using Selector Expressions. Each selector expression returns either an object, an array, or a simple type. A selector always operates within a given context, which can be a reference to a variable, an object literal, an array literal, or the invocation of a function. As DataWeave processes a selector, a new context is set for further selectors, so you can navigate through the complex structures of arrays and objects by using chains of selectors, who’s depth is limited only by the depth of the current context.
There are 5 types of selector expression:
-
Single Value selector .<key-name>
-
Multi Value selector .*<key-name>
-
Descendants Selector ..<key-name>
-
Indexed Selector [<index>]
-
Attribute Selector .@<attribute-name>
Applying the Single level Explicit Selector, the Descendants Selector, or the Indexed Selector returns the value of the key:value pair that matches the expression.
Note: Each of these selector expressions supports having a '?' appended at the end of the chain. This changes the expression into a query that checks upon the existence of the key. The return type in this case is a boolean true or false.
This document also details how you can access different elements of the incoming Mule Message and environment:
Single Value selector
Value selectors may be applied over an :object
or an :array
.
Over :object
This selector returns the first value whose key matches the expression, that is, payload.name, which returns the value whose key matches name.
Input: JSON
{
"people": {
"size" : 1,
"person": {
"name": "Nial",
"address": {
"street": {
"name": "Italia",
"number": 2164
},
"area": {
"zone": "San Isidro",
"name": "Martinez"
}
}
}
}
}
Output: XML
<?xml version="1.0" encoding="UTF-8"?>
<address>
<street>
<name>Italia</name>
<number>2164</number>
</street>
<area>
<zone>San Isidro</zone>
<name>Martinez</name>
</area>
</address>
Over :array
This selector is applied on each of the elements of the array that are of type :object
and returns an array with all the selected values
%dw 1.0
%output application/json
---
payload.people.person.address.street
Input: JSON
{
"people": [ (1)
{
"person": {
"name": "Nial",
"address": {
"street": {
"name": "Italia",
"number": 2164
},
"area": {
"zone": "San Isidro",
"name": "Martinez"
}
}
}
},
{
"person": {
"name": "Coty",
"address": {
"street": {
"name": "Monroe",
"number": 323
},
"area": {
"zone": "BA",
"name": "Belgrano"
}
}
}
}
]
}
1 | As 'people' is an array, this sets the context for searching across both 'person' instances. The result from this is always an array. |
Output: JSON
[ (1)
{
"name": "Italia",
"number": 2164
},
{
"name": "Monroe",
"number": 323
}
]
1 | As the context is an array, the output is always an array. An array is returned even if there’s a single matching value. |
Alternative syntax
You can also select a single value through the alternate syntax ["<key-name>"]
. For example payload["price"] returns the value whose key matches price. This is valid for both arrays and objects.
%dw 1.0
%output application/json
---
payload["people"]
The main advantage of this syntax is that you can easily replace the name of a key with a variable to create a more dynamic expression.
%dw 1.0
%output application/json
---
payload.items[flowVars.item]
The above example receives a payload that contains a list of items, and a flow variable that indicates which of these items to take from the payload.
Multi Value selector
Multi value selector can either be applied over an :object
or an :array
.
Over :object
This selector returns an array with all the values whose key matches the expression.
%dw 1.0
%output application/json
---
{
users: payload.users.*user
}
Input: XML
<users>
<user>Mariano</user>
<user>Martin</user>
<user>Leandro</user>
</users>
Output: JSON
{
"users": [
"Mariano",
"Martin",
"Leandro"
]
}
Indexed Selector
The index selector returns the element at the specified position, it can be applied over an :array
, an :object
or a :string
Over :array
This selector can be applied to String literals, Arrays and Objects. In the case of Objects, the value of the key:value pair found at the index is returned. The index is zero based.
-
If the index is bigger or equal to 0, it starts counting from the beginning.
-
If the index is negative, it starts counting from the end where -1 is the last element.
%dw 1.0
%output application/json
---
payload.people[1]
Input: JSON
{
"people": [
{
"name": "Nial",
"address": "Martinez"
},
{
"name": "Coty",
"address": "Belgrano"
}
]
}
Output: JSON
{
"name": "Coty",
"address": "Belgrano"
}
When using the Index Selector with a String, the string is broken down into an array, where each character is an index.
%output application/json
---
{
name: "MuleSoft"[0]
}
{
"name": "M"
}
Over :string
The selector picks the character at a given position, treating the string as an array of characters.
-
If the index is bigger or equal to 0, it starts counting from the beginning.
-
If the index is negative, it starts counting from the end.
%dw 1.0
%output application/json
---
{
name: "Emiliano"[0]
}
{
"name": "E"
}
Range selector
Over :array
Range selectors limit the output to only the elements specified by the range on that specific order. This selector allows you to slice an array or even invert it.
%dw 1.0
%output application/json
---
{
slice: [0,1,2][0..1],
last: [0,1,2][-1..0]
}
{
"slice": [
0,
1
],
"last": [
2,
1,
0
]
}
Over :string
The Range selector limits the output to only the elements specified by the range on that specific order, treating the string as an array of characters. This selector allows you to slice a string or even invert it.
%dw 1.0
%output application/json
---
{
slice: "DataWeave"[0..1],
last: "DataWeave"[-1..0]
}
{
"slice": "Da",
"last": "evaeWataD"
}
Attribute Selector Expressions
In order to query for the attributes on an Object, the syntax .@<key-name> is used. If you just use .@ (without <key-name>) it returns an object containing each key:value pair in it.
%dw 1.0
%output application/json
---
{
item: {
type : payload.product.@type,
name : payload.product.brand,
attributes: payload.product.@
}
}
Input: XML
<product id="1" type="tv">
<brand>Samsung</brand>
</product>
Output: JSON
{
"item:" {
"type": "tv",
"name": "Samsung",
"attributes": { (1)
"id": 1,
"type": tv
}
}
}
1 | The third element in this output retrieves an object with all of the attributes in it, in this case both the id and the type. |
%dw 1.0
%output application/json
---
{
item: {
attributes : payload.product.@,
name : payload.product.brand
}
}
{
"item": {
"attributes": {
"id": 1,
"type": "tv"
},
"name": "Samsung"
}
}
Selecting the key value pair
As selectors only return the value of a key:value pair, in order to get both the key and value, you can use a type conversion to object.
%dw 1.0
%output application/xml
---
user: payload.name as :object (1)
1 | Using the as :object transforms the value into an object that contains the key as well as the value. Without this conversion to object, the returned XML body would simply be <user>Mariano</user>. |
Input: JSON
{
"name": "Mariano",
"lastName" : "Doe"
}
Output: XML
<?xml version="1.0" encoding="UTF-8"?>
<user>
<name>Mariano</name>
</user>
Descendants Selector
This selector is applied to the context using the form ..<field-name> and retrieves the values of all matching key:value pairs in the sub-tree under the current context. Regardless of the hierarchical structure these fields are organized in, they are all placed at the same level in the output.
%dw 1.0
%output application/json
---
{
names: payload.people..name (1)
}
Input: JSON
{
"people": {
"person": {
"name": "Nial",
"address": {
"street": {
"name": "Italia",
"number": 2164
},
"area": {
"zone": "San Isidro",
"name": "Martinez"
}
}
}
}
}
Output: JSON
{
"names": [
"Nial",
"Italia",
"Martinez"
]
}
1 | In this example, all of the fields that match the key "name" are placed in a list called "names" regardless of their cardinality in the tree of the input data. |
Selecting all the Descendant Key Value Pairs
%dw 1.0
%output application/xml
---
{
names: payload.people..name as :object(1)
}
1 | The as: object makes the expression return an object rather than an array (which would be returned by default). This implies that each value has a key. Without this conversion, in XML the returned array would be a single long string of characters comprised of all three names merged into one. |
Input: JSON
{
"people": {
"person": {
"name": "Nial",
"address": {
"street": {
"name": "Italia",
"number": 2164
},
"area": {
"zone": "San Isidro",
"name": "Martinez"
}
}
}
}
}
Output: XML
<?xml version="1.0" encoding="UTF-8"?>
<names>
<name>Nial</name>
<name>Italia</name>
<name>Martinez</name>
</names>
Selectors modifiers
There are two selectors modifiers: ? and !. The question mark returns true or false whether the keys are present on the structures. The exclamation mark evaluates the selection and fails if any key is not present.
Key Present
Returns true if the specified key is present in the object.
%dw 1.0
%output application/xml
---
present: payload.name?
Input: JSON
{
"name": "Annie"
}
Output: XML
<?xml version="1.0" encoding="UTF-8"?>
<present>true</present>
In the example above, if a 'name' key does exist in the input, it returns true.
This operation also works with attributes:
%dw 1.0
%output application/json
---
{
item: {
typePresent : payload.product.@type?
}
}
Input: XML
<product id="1" type="tv">
<brand>Samsung</brand>
</product>
Output: JSON
{
"item": {
"typePresent": true
}
}
You can also use this validation operation as part of a filter:
%dw 1.0
%output application/xml
---
users: payload.users.*name[?($ == "Mariano")]
Input: XML
<users>
<name>Mariano</name>
<name>Luis</name>
<name>Mariano</name>
</users>
Output: XML
<?xml version="1.0" encoding="UTF-8"?>
<users>
<name>Mariano</name>
<name>Mariano</name>
</users>
The example above selects key:value pairs with value "Mariano" ⇒ {name: Mariano, name: Mariano}
Assert Present
Returns an exception if any of the specified keys are not found.
%dw 1.0
%output application/xml
---
present: payload.lastName!(1)
1 | Throws the exception "There is no key named 'lastName'". |
Input: JSON
{
"name": "Annie"
}
Output: XML
Exception: "There is no key named 'lastName'"
Reference Elements From an Incoming Mule Message
Often, you want to use the different elements from the Mule Message that arrive at the DataWeave Transformer in your transform. The following sections show you how to reference each of these.
The Payload of a Mule Message
You can take the Payload of the Mule message that reaches the DataWeave transformer and use it in your transform body.
%dw 1.0
%output application/xml
---
{
a: payload
}
You can also refer to sub elements of the payload through the dot syntax payload.user
.
If the metadata for the payload’s inner contents are known to Studio, an autocomplete function helps you out. |
You can optionally also define the payload as an input directive in the header, although this isn’t required.
%dw 1.0
%input payload application/xml
%output application/xml
---
{
a: payload
}
Inbound Properties from a Mule Message
You can take Inbound Properties from the Mule message that arrives to the DataWeave transformer and use them in your transform body. To refer to one of these, simply call it through the matching Mule Expression Language (MEL) expression.
In MEL, there are two supported syntaxes to call for an inbound property:
-
inboundProperties.name
-
inboundProperties['name']
The first method only works if the variable name doesn’t include any periods or spaces. |
%dw 1.0
%output application/xml
---
{
a: inboundProperties.userName
}
If the metadata about these inbound properties is known to Studio, an autocomplete function helps you out. |
You can optionally also define the inbound property as a constant directive in the header, although this isn’t required as you can directly call the property as shown above.
%var inUname = inboundProperties['userName']
Outbound Properties from a Mule Message
You can take any Outbound Properties in the Mule message that arrives to the DataWeave transformer and use it in your transform body. To refer to it, simply call it through the matching Mule Expression Language (MEL) expression.
In MEL, there are two supported syntaxes to call an outbound property:
-
outboundProperties.name
-
outboundProperties['name']
The first method only works if the variable name doesn’t include any periods or spaces. |
%dw 1.0
%output application/xml
---
{
a: outboundProperties.userName
}
If the metadata about these outbound properties is known to Studio, an autocomplete function helps you out. |
You can optionally also define the outbound property as a constant directive in the header, although this isn’t required as you can directly call the property as shown above.
%var outUname = outboundProperties['userName']
Flow Variables from a Mule Message
You can take any Flow Variable in the Mule message that arrives at the DataWeave transformer and use it in your transform body. To refer to it, simply call it through the matching Mule Expression Language (MEL) expression.
In MEL, there are two supported syntaxes to call a flow variable:
-
flowVars.name
-
flowVars['name']
The first method only works if the variable name doesn’t include any periods or spaces. |
%dw 1.0
%output application/xml
---
{
a: flowVars.userName
}
If the metadata about these flow variables is known to Studio, an autocomplete function helps you out. |
You can optionally also define the flow variable as a constant directive in the header, although this isn’t required as you can directly call the variable as shown above.
%var uname = flowVars['userName']
Accessing System and Spring Properties
You can reference any Property (System or Spring) that exists in the server while DataWeave is processing your transformation, to do so use the p('prop_name') function or '${prop_name}'.
%dw 1.0
%output application/xml
---
{
a: p('userName'),
b: '${userName}'
}