Tomeister
Tomeister

Reputation: 716

Dataweave 2 How to map Object to JSON Arrays of Object

Have a JSON Object which I need to map to an array of objects but can't get the structure right after many tries. Would it be better, if the script gets very complex and damages readability and ease of maintenance, to have this process divided into to scripts instead of a one dataweave 2 script?

Current output:

{
  "batchId": "71f7a8534907940cb1b5",
  "status": "1",
  "products": [
    {
      "materialNumber": "9780429435942",
      "errorMessages": [
        "Failure",
        "Mistake"
      ],
      "materialNumber": "9780429435950",
      "errorMessages": [
        "Exception"
      ]
    }
  ]
}

Desired output:

{
  "batchId": "71f7a8534907940cb1b5",
  "status": "1",
  "products": [
    {
      "materialNumber": "9780429435942",
      "errorMessages": [
        "Failure",
        "Mistake"
      ]
    },
    {
      "materialNumber": "9780429435950",
      "errorMessages": [
        "Exception"
      ]
    }
  ]
}

DW2 script:

%dw 2.0
output application/json
var failedProducts = vars.response.materials filterObject ((product) -> product.status == "1")
---
{
    batchId: vars.batchId,
    status: vars.overallStatus,
    products: [
        failedProducts mapObject (value,key,index) -> {
            materialNumber: value.materialNumber,
            errorMessages: value.messages.*item.*msgText
        }
    ]
}

Source data:

<response>
    <overallStatus>1</overallStatus>
    <materials>
      <item>
        <status>0</status>
        <materialNumber>9781231231231</materialNumber>
        <messages>
          <item>
            <msgText>Success</msgText>
          </item>
        </messages>
      </item>
      <item>
        <status>1</status>
        <materialNumber>9780429435942</materialNumber>
        <messages>
          <item>
            <msgText>Failure</msgText>
          </item>
          <item>
            <msgText>Mistake</msgText>
          </item>
        </messages>
      </item>
      <item>
        <status>1</status>
        <materialNumber>9780429435950</materialNumber>
        <messages>
          <item>
            <msgText>Exception</msgText>
          </item>
        </messages>
      </item>
    </materials>
</response>

Upvotes: 2

Views: 1510

Answers (3)

Thinker-101
Thinker-101

Reputation: 651

%dw 2.0
output application/json
var failedProducts = vars.response.materials filterObject ((value) -> value.status contains  "1")
---
{
    batchId: vars.batchId,
    status: vars.overallStatus,
    products: failedProducts.*item map (value) -> {
            materialNumber: value.materialNumber,
            errorMessages: value.messages.*item.msgText
        }
}

Upvotes: 0

Harshank Bansal
Harshank Bansal

Reputation: 3262

The problem which you are facing is because XML does not natively support arrays. So while reading an XML using dataweave you need to explicitly mention that you want a certain path to be read as an array, which is exactly what you did when you wrote value.messages.*item.*msgText in your dataweave. You just need to do the same thing for the "item" element (which you are calling products).

This is the dataweave you are looking for:

%dw 2.0
output application/json
var failedProducts = vars.response.materials.*item filter ((product) -> product.status == "1")
---
{
    batchId: vars.batchId,
    status: vars.overallStatus,
    products: failedProducts map (value) -> {
            materialNumber: value.materialNumber,
            errorMessages: value.messages.*item.*msgText
        }
 }

Upvotes: 1

user3078986
user3078986

Reputation:

Here's code (different than yours) that give you the desired result:

%dw 2.0
output application/json
var xml = '
<response>
    <overallStatus>1</overallStatus>
    <materials>
      <item>
        <status>0</status>
        <materialNumber>9781231231231</materialNumber>
        <messages>
          <item>
            <msgText>Success</msgText>
          </item>
        </messages>
      </item>
      <item>
        <status>1</status>
        <materialNumber>9780429435942</materialNumber>
        <messages>
          <item>
            <msgText>Failure</msgText>
          </item>
          <item>
            <msgText>Mistake</msgText>
          </item>
        </messages>
      </item>
      <item>
        <status>1</status>
        <materialNumber>9780429435950</materialNumber>
        <messages>
          <item>
            <msgText>Exception</msgText>
          </item>
        </messages>
      </item>
    </materials>
</response>
'
var data = read(xml,"application/xml")
var batchId = "71f7a8534907940cb1b5"
---
{
    batchId: batchId,
    status: data.response.overallStatus,
    products: 
        data.response.materials.*item filter ($.status as Number != 0)
        map {
            materialNumber: $.materialNumber,
            errorMessages: [$.messages.item]
        }
}

I did use DW variables instead of the vars you have.

Upvotes: 1

Related Questions