Contact Us 1-800-596-4880

Pattern Matching in DataWeave Through match Statements

The match statement behaves like a match or switch statement in other languages, like Java or C++, and routes an input expression to a particular output expression based on some conditions. Before you begin, note that 2.x versions of DataWeave are used by Mule 4 apps. For DataWeave in Mule 3 apps, refer to the DataWeave version 1.2 documentation. For other Mule versions, you can use the version selector in the DataWeave table of contents.

match Statement Syntax:
inputExpression match {
  case <condition> -> <routing expression>
  case <condition> -> <routing expression>
  else -> <default routing expression>
}

As in other languages, the DataWeave match statement provides a compact way to organize multiple, chained if-else statements. A match expression consists of a list of case statements that optionally end with an else statement. Each case statement consists of a conditional selector expression that must evaluate to true or false. This conditional expression corresponds to the condition expressed by an if statement, followed by a corresponding DataWeave routing expression that can include the match statement’s input expression.

Each case statement can be an if statement, or the case statement can use other pattern-matching shortcuts to define the case statement’s condition. If a case statement is false, its routing expression is ignored.

DataWeave supports four different types of patterns for a case statement’s condition:

Each case can be named or unnamed. If the case is named, the name stores the input expression as a local variable that can be used both in that case statement’s conditional expression and in the corresponding routing expression.

match Statement Structure
value match {
  case (<name>:) <condition> -> <routing expression>
  case (<name>:) <condition> -> <routing expression>
  else -> <when none of them matched>
}

As this example shows, the expression returns the results of the first matching case statement:

match Statement Example
%dw 2.0
output application/json
---
"hello world" match {
	case word matches /(hello)\s\w+/ ->  word[1] as String ++ " was matched"
	case literalMatch: "hello world" -> upper(literalMatch)
	case hasOne if( hasOne is Object and hasOne.three? ) -> hasOne.three
	else -> $
}
Output
"hello was matched"

Notice that you can refer to the input expression ("hello world") through each case statement’s local variable name (that is, word or literalMatch), while the else statement can refer to the input expression using the default parameter name $, an unnamed parameter.

To name the input expression in the else statement, you can replace the else statement with a case statement that is always true:

match Statement Example
%dw 2.0
output application/json
---
"hello world" match {
	case word matches  /(hello)\s\w+/ ->  word[1] ++ " was matched"
	case literalMatch: "hello world" -> upper(literalMatch)
	case last if(true) -> last
}

For use cases in which the input is of type String, you can also use the match function in the dw::Core module to test the string against a regex pattern. The function returns an array with the strings that match the entire regex and any capture groups.

For use cases that require a Boolean result based on whether a string matches a regex pattern, you can use the matches function in the dw::Core module instead of using pattern matching or the module’s match function.

Pattern Matching to Literal Values

Matches when the evaluated value equals a simple literal value.

In this example, the first field matches the value in myInput.string and returns a boolean. The second field performs the same match, but it returns an object that contains both a boolean and a reference to the validated value.

DataWeave Script
%dw 2.0
var myInput = {
  "string": "Emiliano"
}
output application/json
---
{
  a: myInput.string match {
    case "Emiliano" -> true
    case "Mariano" -> false
  },
  b: myInput.string match {
    case str: "Emiliano" -> { "matches": true, value: str }
    case str: "Mariano" -> { "matches": false, value: str }
  }
}
Output
{
  "a": true,
  "b": {
    "matches": true,
    "value": "Emiliano"
  }
}

Pattern Matching on Expressions

Matches when a given expression returns true.

In this example, the first field matches the value of myInput.string against two alternatives and conditionally appends a different string to it. The second field evaluates if the value in myInput.number is greater than (>), less than (<), or equal to (==) 3 and returns the corresponding string.

DataWeave Script
%dw 2.0
var myInput = {
  "string": "Emiliano",
  "number": 3.14
}
output application/json
---
{
  a: myInput.string match {
    case str if str == "Mariano" -> str ++ " de Achaval"
    case str if str == "Emiliano" -> str ++ " Lesende"
  },
  b: myInput.number match {
    case num if num == 3 -> "equal"
    case num if num > 3 -> "greater than"
    case num if num < 3 -> "less than"
  }
}
Output
{
  "a": "Emiliano Lesende",
  "b": "greater than"
}

Pattern Matching on the Data Type

Matches when the evaluated value is the specified data type.

In this example, the first field evaluates the data type of myInput.a and returns a string with the corresponding type name. The second field is similar but also returns the value of the myInput.b.

DataWeave Script
%dw 2.0
var myInput =
{
  "a": "Emiliano",
  "b": 3.14
}
output application/json
---
{
  a: myInput.a match {
    case is Object -> 'OBJECT'
    case is String -> 'STRING'
    case is Number -> 'NUMBER'
    case is Boolean -> 'BOOLEAN'
    case is Array -> 'ARRAY'
    case is Null -> 'NULL'
    else -> 'ANOTHER TYPE'
  },
  b: myInput.b match {
    case y is Object -> { 'Type': { 'OBJECT' : y} }
    case y is String -> { 'Type': { 'STRING' : y} }
    case y is Number -> { 'Type': { 'NUMBER' : y} }
    case y is Boolean -> { 'Type': { 'BOOLEAN' : y} }
    case y is Array -> { 'Type': { 'ARRAY' : y} }
    case y is Null -> { 'Type': { 'NULL' : y} }
    else -> { 'Type': { 'ANOTHER TYPE' : myInput.b} }
  }
}
Output
{
  "a": "STRING",
  "b": {
    "Type": {
      "NUMBER": 3.14
    }
  }
}

Pattern Matching on Regular Expressions

Matches when the evaluated value fits a given regular expression (regex), specifically a regex "flavor" supported by Java. In this example, the input variable (myInput) includes an array of strings. The script uses the map function to iterate through the array. It evaluates each element against a Java regex and outputs an object based on matches to the input.

DataWeave Script
%dw 2.0
var myInput = {
  "phones": [
    "+1 (415) 229-2009",
    "(647) 456-7008"
  ]
}
output application/json
---
{
  a: myInput.phones map ($ match {
     case phone matches /\+(\d+)\s\((\d+)\)\s(\d+\-\d+)/ -> { country: phone[1]}
     case phone matches /\((\d+)\)\s(\d+\-\d+)/ -> { area: phone[1], number: phone[2] }
   }),
 b: myInput.phones map ($ match {
   case phone matches /\+(\d+)\s\((\d+)\)\s(\d+\-\d+)/ -> { country: phone[1], area: phone[2], number: phone[3] }
   case phone matches /\((\d+)\)\s(\d+\-\d+)/ -> { area: phone[1], number: phone[2] }
 })
}
Output
{
  "a": [
    {
      "country": "1"
    },
    {
      "area": "647",
      "number": "456-7008"
    }
  ],
  "b": [
    {
      "country": "1",
      "area": "415",
      "number": "229-2009"
    },
    {
      "area": "647",
      "number": "456-7008"
    }
  ]
}

Deconstructors on Collections in DataWeave

DataWeave supports two types of collections: Arrays and Objects. Arrays are a sequence of values, while Objects are a sequence of key-value pairs.

Deconstruction on Arrays

An Array can be seen as a head (the first element of the Array) and a tail (a new Array with the reminder of the elements). For example, in the array [1,2,3,4], 1 is the head and 2,3,4 is the tail.

To match over an array, use the following syntax, where the script gets the first element of an array or returns null if the array is empty:

DataWeave Script
[1,2,3,4] match {
	case [head ~ tail] -> head
	case [] -> null
}

This kind of deconstruction is useful when used with recursive functions.

Example: Build a joinBy Function

This example builds a joinBy function that takes an array of string and returns a string with all the elements of the Array concatenated with the given separator:

DataWeave Script
fun joinBy(elements: Array<String>, separator: String): String =
	elements match {
		case [head ~ tail] -> head ++ separator ++ joinBy(tail, separator) //When head and tail append and recursively
		case [] -> "" //When the array is empty return empty array
	}

Example: Build a Filter Function

This example builds a higher-order filter function:

DataWeave Script
fun filter<T>(elements: Array<T>, predicate: (item:T) -> Boolean): Array<T> =
	elements match {
		case [head ~ tail] ->
			if(predicate(head))
				[head] ++ filter(tail, predicate)
			else
				filter(tail, predicate)
		case [] -> []
	}

Deconstruction on Objects

Objects in DataWeave are similar to Arrays but each element consists of a key and a value. An Object can also be seen as a head (the first key-value pair) and a tail (a new Object with the rest of the key-value pairs).

To match over an object, use the following syntax, where the script gets the first value of an object, which in this case is "Word":

DataWeave Script
{hello: "world", test: true} match {
    case {headKey: headValue ~ tail} -> headValue
    case {} -> null
}