Prudhvi B
Prudhvi B

Reputation: 154

Mule 4: Dataweave2.0 : how to pass path as property to fetch data

Can dw2.0 read path from yaml property file?

for example say input is

{
  "head": {
    "country": "US",
    "body": {
      "USStates": {
        "stateName": "California",
        "stateCode": "CL"
      }
    }
  }
}

I have to fetch stateCode value from above request. Based on country name, the path changes every time (like ChinaStates,IndiaStates etc)

So is there a way to pass input path as parameter to Data weave? We are using yaml properties. I tried below code, its resulting in null value

%dw 2.0
output application/json
---
if(p("countryName." ++ (payload.head.country as String)) != null)
          payload.p("countryName." ++ (payload.head.country))
else "not in scope"
     

and in yaml it declared as below

countryName:
  US : head.body.USStates.stateCode
  INDIA : head.body.IndiaStates.stateCode

I even tried passing path from payload then it was taking as string. please suggest

Upvotes: 1

Views: 1814

Answers (3)

user3078986
user3078986

Reputation:

Try this:

I did use a variable for the path instead of reading it from the YAML config for the sake of simplicity.

%dw 2.0
output application/json
var data = {
  "head": {
    "country": "US",
    "body": {
      "USStates": {
        "stateName": "California",
        "stateCode": "CL"
      }
    }
  }
}

var path = "head.body.USStates.stateCode"

---
path splitBy /\./ reduce (e,acc=data) -> acc[e]

Edit: if you need an explanation, just ask and I 'll re-edit later on with all the details. No time right now :).

Edit1: Have a look at this answer for an explanation of reduce.

Upvotes: 5

Michael Jones
Michael Jones

Reputation: 1910

Is the stateName and stateCode piece consistent? If so you could do something like this:

%dw 2.0
output application/json
---
{
    country: payload.head.country,
    stateName: payload.head.body[0].stateName,
    stateCode: payload.head.body[0].stateCode
}

Output:

{
  "country": "US",
  "stateName": "California",
  "stateCode": "CL"
}

But yes, you can address it like this:

payload.head.body[p('countryName.$(payload.head.country)')].stateCode should also work, though more complicated than necessary.

Edit:

I see based on your answer why this wouldn't necessarily work. George's answer is correct, but I thought I'd throw this in as well since it is a slightly more complete function for doing this:

%dw 2.0
output application/json

fun getField(payload: Any, field: String) = do {
    var path = field splitBy '.' reduce((pathPart, path=[]) ->
        if (pathPart contains '[') do {
            var pieces = pathPart splitBy '['
            ---
            pieces reduce((piece,subPath=path) -> 
                if (piece contains ']') subPath << (piece replace ']' with '') as Number
                else subPath << piece
            )
        }
        else path << pathPart
    )
    ---
    getField(payload, path)
}

fun getField(payload: Any, field: Array) =
    if (sizeOf(log('field',field)) == 1) payload[field[0]]
    else getField(payload[field[0]], field[1 to -1])

Using this function you would do:

%dw 2.0
output application/json
---
getField(payload, p('country.$(payload.head.country)'))

This is a get field by path function.

screenshot of dwlang.fun with code

Upvotes: 2

aled
aled

Reputation: 25699

It looks like the structure is too complex for the builtin selectors. I don't think you can use the DataWeave single-value selector (the dot '.') inside a dynamic expression in that way. If you leave only the attribute name in the property it will work. I recommend to simplify the data if possible.

Example:

Property countrName.US: "USStates"

and the expression:

  payload.head.body[p("countrName.US")].stateCode

Otherwise if you absolutely need a path expression see George's answers.

Upvotes: 1

Related Questions