I have a JSON payload that I need to convert into an XML. However that JSON payload has many fields starting with '@' which are supposed to be the XML attributes. So when I converted those into XML the '@" is being attached to each xml tag as a field(e.g. <@id>1495161</@id>
). Each field with '@' is supposed to be the XML attribute and should not come as indivial XML filed/tag after the conversion.
Please see my code and output vs the expected output. Notice how all the fields with @ are transformed into xml tag. But I want all these fields with @ to transform into XML attributes.
Sample Request:
{
"trans": {
"@id": "1495144",
"@TPId": "4aec",
"@change": "0",
"@count": "1",
"@dateStamp": "2024-08-02T03:07:48",
"data": {
"@id": "d7D173564C5F14FF2AD08D621C188AF19",
"StateFlag": "0",
"DCC": "B",
"LastName": "MMNGorthy",
"Name": "Scott",
"Structure": "NonProfit",
"BusinessType": "Engineering",
"meams": "AI",
"Count": "0",
"CTier": "000",
"CTCond": "111",
"CTPl": "222",
"DO": "1",
"AuthObject": "0"
}
}
}
Code:
%dw 2.0
output application/xml
ns ns0 http://Test.Sample.Data/1.0
---
ns0#trans: payload.trans
output from my code:
<?xml version='1.0' encoding='UTF-8'?>
<ns0:trans xmlns:ns0="http://Test.Sample.Data/1.0">
<@id>1495144</@id>
<@TPId>4aec</@TPId>
<@change>0</@change>
<@count>1</@count>
<@dateStamp>2024-08-02T03:07:48</@dateStamp>
<data>
<@id>d7D173564C5F14FF2AD08D621C188AF19</@id>
<StateFlag>0</StateFlag>
<DCC>B</DCC>
<LastName>MMNGorthy</LastName>
<Name>Scott</Name>
<Structure>NonProfit</Structure>
<BusinessType>Engineering</BusinessType>
<meams>AI</meams>
<Count>0</Count>
<CTier>000</CTier>
<CTCond>111</CTCond>
<CTPl>222</CTPl>
<DO>1</DO>
<AuthObject>0</AuthObject>
</data>
</ns0:trans>
Expected output:
<?xml version='1.0' encoding='UTF-8'?>
<ns0:trans xmlns:ns0="http://Test.Sample.data/1.0" id="1495144" TPId='4aec' change='0' count='1' dateStamp="2024-08-02T03:07:48">
<data id="FF2AD08D621">
<StateFlag>0</StateFlag>
<DCC>B</DCC>
<LastName>MMNGorthy</LastName>
<Name>Scott</Name>
<Structure>NonProfit</Structure>
<BusinessType>Engineering</BusinessType>
<meams>AI</meams>
<Count>0</Count>
<CTier>000</CTier>
<CTCond>111</CTCond>
<CTPl>222</CTPl>
<DO>1</DO>
<AuthObject>0</AuthObject>
</data>
</ns0:trans>
To add an attribute, you need to define them as:
xmlElem @(att1: val1, att2: val2): xmlValue
Notice that the value inside the @()
is not an object but the deconstructed version of the object. For example, if you have:
var jsonObject = {att1: val1, att2: val2}
You cannot directly write:
xmlElem @(jsonObject): xmlValue
Instead, you need to deconstruct it using ()
:
xmlElem @((jsonObject)): xmlValue
Now, for your use case, you need to make the output dynamic. You can use the following transformation. Most of the functions are self explanatory.
%dw 2.0
output application/xml
ns ns0 http://Test.Sample.Data/1.0
fun getAttributes(jsonObject: Object) =
jsonObject
filterObject ($$ startsWith "@")
mapObject ((value, key) -> (key[1 to -1]): value) //remove first char from key i.e. @
fun getNonAttributes(jsonObject: Object) =
jsonObject
filterObject !($$ startsWith "@")
fun fromJsonToXml(json) =
json mapObject ((value, key) ->
if(value is Object) (key) @((getAttributes(value))): fromJsonToXml(getNonAttributes(value)) // Attributes are applied using `@( (getAttributes(value)) )`. Notice how the function call is further wrapped around `()` to deconstruct the output
else (key): value
)
---
// following is to add namespace
fromJsonToXml(payload)
then ((resultWithoutNS) ->
ns0#trans @((resultWithoutNS.trans.@)): resultWithoutNS.trans
)