Contact Free trial Login

Pattern Matching in DataWeave Through match Statements

The match function 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.

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

As in other languages, the DataWeave match function provides 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 function’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, literalMatch, or hasOne), while the else statement can refer to the input expression using the default parameter name $, an unnamed parameter.

If you want 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
"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 where you simply need a Boolean result based on whether a value matches or not, you can use the matches function instead of using pattern matching.

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 payload.string and returns a Boolean. The second field performs the same match, but returns an object that contains both a boolean and a reference to the validated value.

Transform
%dw 2.0
output application/json
---
{
  a: payload.string match {
    case "Emiliano" -> true
    case "Mariano" -> false
  },
  b: payload.string match {
    case str: "Emiliano" -> { "matches": true, value: str }
    case str: "Mariano" -> { "matches": false, value: str }
  }
}
Input
{
  "string": "Emiliano"
}
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 payload.string against two alternatives and conditionally appends a different string to it. The second field evaluates if the value in payload.number is "greater", "less than", or "equal" to 3 and returns the corresponding string.

Transform
%dw 2.0
output application/json
---
{
  a: payload.string match {
    case str if str == "Mariano" -> str ++ " de Achaval"
    case str if str == "Emiliano" -> str ++ " Lesende"
  },
  b: payload.number match {
    case num if num == 3 -> "equal"
    case num if num > 3 -> "greater than"
    case num if num < 3 -> "less than"
  }
}
Input
{
  "string": "Emiliano",
  "number": 3.14
}
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 type of payload.a and returns a string with the corresponding type name. The second field is similar but also returns the value of the payload.b.

Transform
%dw 2.0
output application/json
---
{
  a: payload.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: payload.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' : payload.b} }
  }
}
Input
{
  "a": "Emiliano",
  "b": 3.14
}
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 payload 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.

Transform
%dw 2.0
output application/json
---
{
  a: payload.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: payload.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] }
 })
}
Input
{
  "phones": [
    "+1 (415) 229-2009",
    "(647) 456-7008"
  ]
}
Output
{
  "a": [
    {
      "country": "1"
    },
    {
      "area": "647",
      "number": "456-7008"
    }
  ],
  "b": [
    {
      "country": "1",
      "area": "415",
      "number": "229-2009"
    },
    {
      "area": "647",
      "number": "456-7008"
    }
  ]
}