Home > Mobile >  Mulesoft Dataweave 2.0 Issue trying to transform JSON to XML payload with attributes
Mulesoft Dataweave 2.0 Issue trying to transform JSON to XML payload with attributes

Time:05-13

I am relatively new to Dataweave and I’m trying to resolve a transform issue when mapping a JSON to XML payload with attributes. All I have right now is a Transform message with output application/xml.

I need to be able to accept several different large JSON payloads. I won’t know ahead of time what the structure is of each but I need to map the attributes in a certain way.

Here is an example snippet of what my Input looks like:

"HomeLineBusiness": { 
    "Dwell": {
         "@LocationRef": "e3654502-524f-4834-b872-272d77a84f1b",
         "@id": "c263e3e1-750b-4562-81c3-deb6eee6f1c5",
         "PrincipalUnitAtRiskInd": "1",
         "PolicyTypeCd": "03",
    }
}

This is what is being returned currently after transform:

<HomeLineBusiness>
        <Dwell>
                <@LocationRef>e3654502-524f-4834-b872-272d77a84f1b</@LocationRef>
                <@id>c263e3e1-750b-4562-81c3-deb6eee6f1c5</@id>
                <PrincipalUnitAtRiskInd>1</PrincipalUnitAtRiskInd>
                <PolicyTypeCd>03</PolicyTypeCd>
        </Dwell>
</HomeLineBusiness>

This is how I need it transformed:

<HomeLineBusiness>
        <Dwell LocationRef="e3654502-524f-4834-b872-272d77a84f1b" id="c263e3e1-750b-4562-81c3-deb6eee6f1c5">
                <PrincipalUnitAtRiskInd>1</PrincipalUnitAtRiskInd>
                <PolicyTypeCd>03</PolicyTypeCd>
        </Dwell>
</HomeLineBusiness>

Any tag that comes in starting with @ needs to mapped as an attribute . I don’t know if I can do a replace structure or if there is some other recommend approach.

Thank you

CodePudding user response:

While aled's solution is mostly correct. There is a small bug with it when it comes to Arrays. It will repeat the key of the Array as well along with its elements.

%dw 2.0
output application/xml

fun getAttributeNode(object) = 
    object 
        filterObject ($$ as String startsWith "@") 
        mapObject ((value, key) -> {
            ((key as String replace /^@/ with "") : value)
        })
        
fun getNonAttributeNode(object) = 
    object
       filterObject (not ($$ as String startsWith "@"))
       mapObject ((value, key) -> 
         if(value is Object) getElementNode((key): value)
         else if(value is Array) (key): {(value map getElementNode($))}
         else (key): value
       )

fun getElementNode(object) = 
        object mapObject ($$) @((getAttributeNode($))) : getNonAttributeNode($)
---
getElementNode(payload)

I tried it with this Payload

{
  "HomeLineBusiness": {
    "Dwell": {
      "@LocationRef": "e3654502-524f-4834-b872-272d77a84f1b",
      "@id": "c263e3e1-750b-4562-81c3-deb6eee6f1c5",
      "PrincipalUnitAtRiskInd": "1",
      "PolicyTypeCd": "03",
      "SomeNestedObjectWithAttributes": {
        "@NestedAttribute1": "NestedAttribute1",
        "@NestedAttribute2": "NestedAttribute2",
        "NestedString": "Some string value"
      },
      "SomeNestedObjectWithoutAttributes": {
        "NestedString": "Some string value"
      },
      "SomeArray": [
        {
          "ArrayElementOne": {
            "@AttributeOfArrayOne": "AttributeValueOfArrayOne",
            "@AttributeOfArrayTwo": "AttributeValueOfArrayTwo",
            "StringInArrayOne": "String value of Array One"
          }
        },
        {
          "ArrayElementTwo": {
            "@AttributeOfArrayTwo": "AttributeValueOfArrayTwo",
            "@AttributeOfArrayTwo": "AttributeValueOfArrayTwo",
            "StringInArrayTwo": "String value of Array Two"
          }
        }
      ]
    }
  }
}

And getting this output

<?xml version='1.0' encoding='UTF-8'?>
<HomeLineBusiness>
  <Dwell LocationRef="e3654502-524f-4834-b872-272d77a84f1b" id="c263e3e1-750b-4562-81c3-deb6eee6f1c5">
    <PrincipalUnitAtRiskInd>1</PrincipalUnitAtRiskInd>
    <PolicyTypeCd>03</PolicyTypeCd>
    <SomeNestedObjectWithAttributes NestedAttribute1="NestedAttribute1" NestedAttribute2="NestedAttribute2">
      <NestedString>Some string value</NestedString>
    </SomeNestedObjectWithAttributes>
    <SomeNestedObjectWithoutAttributes>
      <NestedString>Some string value</NestedString>
    </SomeNestedObjectWithoutAttributes>
    <SomeArray>
      <ArrayElementOne AttributeOfArrayOne="AttributeValueOfArrayOne" AttributeOfArrayTwo="AttributeValueOfArrayTwo">
        <StringInArrayOne>String value of Array One</StringInArrayOne>
      </ArrayElementOne>
    </SomeArray>
    <SomeArray>
      <ArrayElementTwo AttributeOfArrayTwo="AttributeValueOfArrayTwo" AttributeOfArrayTwo="AttributeValueOfArrayTwo">
        <StringInArrayTwo>String value of Array Two</StringInArrayTwo>
      </ArrayElementTwo>
    </SomeArray>
  </Dwell>
</HomeLineBusiness>

CodePudding user response:

Using pattern matching you can use filterObject() and mapObject to select which values to transform to elements and which to convert to attributes. The condition is if the key starts with the @ character. I create a function to simplify extracting what we want as attributes from the list. This results in an object that can be directly used to set the attributes at the right level using the @((...)) construct (ie @((getAttributes($)))).

Using a recursive function to drive the transformation allows it to be dynamic and work with structures of several levels, including arrays.

%dw 2.0
output application/xml
fun getAttributes(x)=
        x match {
        case is Object -> x filterObject ($$ as String startsWith "@") 
                     mapObject ((value, key, index) -> (key[1 to -1] ): value)
        else -> $
  }
fun convertToAttributes(x)=                   
    x match  {
        case is Object -> x filterObject !($$ as String startsWith "@")
                            mapObject ($$) @((getAttributes($))): convertToAttributes($)
        case is Array -> x map convertToAttributes($)
        else -> $
  }
---
convertToAttributes(payload)

Input:

{
    "HomeLineBusiness": { 
        "Dwell": {
            "@LocationRef": "e3654502-524f-4834-b872-272d77a84f1b",
            "@id": "c263e3e1-750b-4562-81c3-deb6eee6f1c5",
            "PrincipalUnitAtRiskInd": "1",
            "PolicyTypeCd": "03"
        }
    }
}

Output:

<?xml version='1.0' encoding='UTF-8'?>
<HomeLineBusiness>
  <Dwell LocationRef="e3654502-524f-4834-b872-272d77a84f1b" id="c263e3e1-750b-4562-81c3-deb6eee6f1c5">
    <PrincipalUnitAtRiskInd>1</PrincipalUnitAtRiskInd>
    <PolicyTypeCd>03</PolicyTypeCd>
  </Dwell>
</HomeLineBusiness>
  • Related