Dataweave Cookbook

Ask Question / Submit Issue

Recipes:

Everything below is maintained in my Gist: https://gist.github.com/mikeacjones

Recursively appending XML namespaces

data-weave
%dw 2.0

fun appendNamespace(data, nsSelector: (k: Key) -> Namespace | Null) =
  data match {
    case is Array -> data map appendNamespace($, nsSelector)
    case is Object -> data mapObject do {
      var ns0 = nsSelector($$)
      ---
      if (ns0 != null) ns0#"$($$)": appendNamespace($, nsSelector)
      else ($$): appendNamespace($, nsSelector)
    }
    else -> data
}
Example payload:
json
{
  "GetOrderById": {
    "OrderId": 656734
  }
}
Here is a simple use case, mapping all keys to the same namespace.
data-weave
%dw 2.0
import dw::modules::Namespaces //import the function from /src/main/resources/dw/modules/Namespaces.dwl

ns soapenv http://schemas.xmlsoap.org/soap/envelope/
ns tem http://tempuri.org/

output application/xml
---
{
    soapenv#Envelope: {
        soapenv#Header: null,
        soapenv#Body: payload appendNamespace tem
    }
}
Of course, our namespace selector is a function, so we could do something like call a system API via lookup to dynamically pull in a map:
data-weave
%dw 2.0
import dw::modules::Namespaces //import the function from /src/main/resources/dw/modules/Namespaces.dwl

ns soapenv http://schemas.xmlsoap.org/soap/envelope/

var nsMap = lookup('get-namespace-map')
---
{
    soapenv#Envelope: {
        soapenv#Header: null,
        soapenv#Body: payload appendNamespace do {
          var ns0 = nsMap[$]
          ---
          if (ns0 != null) ns0 as Namespace //coerce our JSON structure to a Namespace type
          else null
        }
    }
}

Expanding XML Attributes to JSON

When converting XML to JSON automatically, you lose your attributes. 'Recipe' that converts XML to JSON while preserving attributes, if there are any:
data-weave
%dw 2.0
output application/json

var expandXmlAttrs = (payload) ->
    payload match {
        case is Array -> payload map expandXmlAttrs($)
        case is Object -> payload mapObject {
            (($$): expandXmlAttrs($)) if ($$.@ == null),
            (($$): {
                value: expandXmlAttrs($),
                ($.@)
            }) if ($$.@ != null)
        }
        else -> payload
    }

---
expandXmlAttrs(payload)
Example input:
xml
<EDPPPersonSrch>
   <SrchMsgRqHdr>
    <jXchangeHdr>
     <JxVer>2020</JxVer>
     <AuditUsrId>jxchange</AuditUsrId>
     <AuditWsId>ThirdParty</AuditWsId>
     <ConsumerName>jxchange</ConsumerName>
     <ConsumerProd>soatest</ConsumerProd>
     <Ver_1/>
     <jXLogTrackingId>456</jXLogTrackingId>
     <Ver_2/>
     <InstRtId JHANull="" Rstr="">123456780</InstRtId>
     <InstEnv>Prod</InstEnv>
     <Ver_3/>
     <Ver_4/>
     <Ver_5/>
     <ValidConsmName>ImageCenter Admin</ValidConsmName>
     <ValidConsmProd>ImageCenter</ValidConsmProd>
     <Ver_6/>
    </jXchangeHdr>
    <MaxRec>2</MaxRec>
    <Cursor>2</Cursor>
    <Ver_1/>
    <Ver_2/>
    <Ver_3/>
   </SrchMsgRqHdr>
   <ProdCode JHANull="" Rstr="">jha-imagecenter</ProdCode>
   <LastName JHANull="" Rstr="" SrchType="">Jones</LastName>
   <AcctId JHANull="" Rstr="" SrchType="Positive">70023888848</AcctId>
   <AcctType JHANull="" Rstr="">Savings</AcctType>
   <Custom/>
   <Ver_1/>
  </EDPPPersonSrch>
Example output:
json
{
  "EDPPPersonSrch": {
    "SrchMsgRqHdr": {
      "jXchangeHdr": {
        "JxVer": "2020",
        "AuditUsrId": "jxchange",
        "AuditWsId": "ThirdParty",
        "ConsumerName": "jxchange",
        "ConsumerProd": "soatest",
        "Ver_1": null,
        "jXLogTrackingId": "456",
        "Ver_2": null,
        "InstRtId": {
          "value": "123456780",
          "JHANull": "",
          "Rstr": ""
        },
        "InstEnv": "Prod",
        "Ver_3": null,
        "Ver_4": null,
        "Ver_5": null,
        "ValidConsmName": "ImageCenter Admin",
        "ValidConsmProd": "ImageCenter",
        "Ver_6": null
      },
      "MaxRec": "2",
      "Cursor": "2",
      "Ver_1": null,
      "Ver_2": null,
      "Ver_3": null
    },
    "ProdCode": {
      "value": "jha-imagecenter",
      "JHANull": "",
      "Rstr": ""
    },
    "LastName": {
      "value": "Jones",
      "JHANull": "",
      "Rstr": "",
      "SrchType": ""
    },
    "AcctId": {
      "value": "70023888848",
      "JHANull": "",
      "Rstr": "",
      "SrchType": "Positive"
    },
    "AcctType": {
      "value": "Savings",
      "JHANull": "",
      "Rstr": ""
    },
    "Custom": null,
    "Ver_1": null
  }
}

Bitwise Math

Data-weave doesn't have built in operators for bitwise math. We could implement this in java.. but lets take a look at a simple implementation in data-weave that we can then reuse as a module later.
data-weave
%dw 2.0
import dw::core::Numbers
import dw::core::Strings

fun AND(lo: Number, ro: Number) = do {
    var binary = getBinary(lo, ro)
    ---
    Numbers::fromBinary(binary.left map ($ as Number * binary.right[$$] as Number) reduce ($$++$))
}

fun OR(lo: Number, ro: Number) = do {
    var binary = getBinary(lo, ro)
    ---
    Numbers::fromBinary(binary.left map (if ($ == "1" or binary.right[$$] == "1") "1" else "0") reduce ($$++$))
}

fun XOR(lo: Number, ro: Number) = do {
    var binary = getBinary(lo, ro)
    ---
    Numbers::fromBinary(binary.left map (if ($ == binary.right[$$]) "0" else "1") reduce ($$++$))
}

fun getBinary(lo: Number, ro: Number) = do {
    var loB = Numbers::toBinary(lo)
    var roB = Numbers::toBinary(ro)
    var size = max([sizeOf(loB), sizeOf(roB)]) default 0
    ---
    { 
        left: Strings::leftPad(loB, size, '0') splitBy '',
        right: Strings::leftPad(roB, size, '0') splitBy ''
    }
}
A lot easier to implement than you might think! All we have to do is convert it to binary and then map. Probably not the most efficient method for doing this, but a fun thing to play with. We can then use it to do something like implement the powerSet function below.

Power-set

Need to get the power set? Well here you go! Making use of our previous Bitwise module along with some basic set theory we all learned at some point, we can do this:
data-weave
%dw 2.0

import Bitwise

fun powerSet(set: Array) = do {
    var iterable = (0 to pow(2,sizeOf(set))-1) as Array
    ---
    iterable map (item) -> set filter (Bitwise::AND(item,pow(2,$$)) != 0)
}
Easy peasy!

RFC822 Compliant Email Validation

If the regex is valid in java, its valid in data-weave!
data-weave
%dw 2.0
output application/json
var isValidEmail = (e) -> e matches /(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(?:(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\"(?:[^\\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*\"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[\"()<>@,;:\\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*))*)?;\s*)/
---
isValidEmail("michael.jones@mulesoft.com")