creating an XML attribute from var in dataweave 2.0 - mule

I have a JSON input:
{
abc: "",
def: "hello"
}
I want to make this blank element as nillable in XML i.e. . I am using the below dataweave code:
%dw 2,0
output application/xml skipNullOn="everywhere"
var makeNil= (in) ->
in match {
case is Array -> in map makeNil($)
case is Object -> in mapObject (
if ( ($) == "")
($$) #(xsi#'nil':true): {}
else ($$): makeNil($)
)
else -> in
}
---
makeNil(payload)
I am not able to create an attribute using #(xsi#'nil':true) for key($$). Please help me

Solving the errors that I mentioned in my comment, adding a root element works. Remember that XML unlike JSON requires a root element.
%dw 2.0
output application/xml skipNullOn="everywhere"
ns xsi http://www.w3.org/2001/XMLSchema-instance
var makeNil= (in) ->
in match {
case is Array -> in map makeNil($)
case is Object -> in mapObject (
if ( ($) == "")
($$) #(xsi#'nil':true): {}
else ($$): makeNil($)
)
else -> in
}
---
top: makeNil(payload)
input:
{
"abc": "",
"def": "hello"
}
output:
<?xml version='1.0' encoding='UTF-8'?>
<top>
<abc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<def>hello</def>
</top>

Related

Extracting a subset of JSON key-value pairs as an Object from a Parent JSON Object in dataweave 2.0 Mule 4

I have a dataweave challenge which I couldn't figure out without making it complicated.
Input JSON payload
{
"Name" : "Mr.wolf",
"Age" : 26,
"Region" : "USA",
"SubRegion": "Pacific"
}
Output needed
{
"Name" : "Mr.wolf",
"Age" : 26
}
Here is a catch. I am not allowed to use the above shown output format structure in the transform message, or either remove the keys using "-" operation.
So basically, we shouldn't use the below dwl.
%dw 2.0
output application/json
---
(payload - "Region" - "SubRegion")
or
%dw 2.0
output application/json
---
{
"Name" : payload.Name,
"Age" : payload.Age
}
How can we achieve the required output by using Lambdas, Reduce, mapObject, functions or any other operation of choice, other than the restricted methods/usage shown above.
Any solution provided is much appreciated.
is this what you are looking for?
%dw 2.0
output application/json
---
payload filterObject ((value, key,index) -> (index <2 ))
Sounds like filterObject could work for you. Documentation
payload filterObject ((value, key) -> (key ~= "Name" or key ~= "Age"))
Another rendition of the same approach.
%dw 2.0
output application/json
---
payload mapObject {
(($$) : $) if (($$) ~= "Name" or ($$) ~= "Age")
}
The other rendition being:
%dw 2.0
output application/json
---
payload mapObject {
(($$) : $) if (($$$) < 2)
}

Mule DWL - Flatten json hierarchical elements

I have json payload as below:
Attributes:{
Contact:{
Address:{
PersonName:"John",
Line1:"sdsds",
Line2:"sdsdsd",
SubAddress:{
PersonName:"John",
Line1:"ggghg",
Line2:"xzxzxzx"
}
},
Phone:{
Home:"2323232323",
Office:"4545454545"
}
},
Id:"2343434",
order:"3343434"
}
I want to flatten the hierarchy to below output
Attributes:{
Contact.Address.PersonName:"John",
Contact.Address.Line1:"sdsds",
Contact.Address.Line2:"sdsdsd",
Contact.Address.SubAddress.PersonName:"John",
Contact.Address.SubAddress.Line1:"ggghg",
Contact.Address.SubAddress.Line2:"xzxzxzx",
Contact.Phone.Home:"2323232323",
Contact.Phone.Office:"4545454545",
Id:"2343434",
order:"3343434"
}
Attributes element can have any number of complex elements like the "Address" and "Contact". We will not know the key value of the complex elements at the point of coding. DWL should be able to produce a single level output. Want generic solution for this flattening using dw1 in Mule 3. Please help.
Below scripts recursively goes over the payload and construct single key-valued
pair object
%dw 1.0
%output application/json
%var payload = {"Attributes":{"Contact":{"Address":{"SubAddress":[{"PersonName1":"John","Line1":"ggghg","Line2":"xzxzxzx"},{"PersonName":"Jar","Line1":"ggghg","Line2":"xzxzxzx"}]},"Phone":{"Home":"2323232323","Office":"4545454545"}},"Id":"2343434","order":"3343434"}}
%function constructKeys(oldKeys, newKey) oldKeys ++ '.' ++ newKey
%function writeData(json ,output, keys) json match {
case is :null -> null,
case is :array -> {(json map ((item, index) -> writeData(item, output, keys ++ index)))},
case is :object -> {((json pluck $$) map writeData(json[$],output,constructKeys(keys,$)))},
default -> output ++ {(keys[1 to -1]): json }
}
---
Attributes: writeData(payload.Attributes,{}, '')

Mulesoft Dataweave Converting the key of a mapObject to lower case

Assume the following json with KEY1 and KEY2 in caps. KEY1 and KEY2 needs to be converted to lower case
{
"KEY1": {
"subkey1": "subval1",
"subkey2": "subval2"
},
"KEY2": {
"subkey1": "subval1",
"subkey2": "subval2"
}
}
this needs to be converted to the following json using data weave.
{
"key1": {
"subkey1": "subval1",
"subkey2": "subval2"
},
"key2": {
"subkey1": "subval1",
"subkey2": "subval2"
}
}
I tried the following DW syntax, but it did not work
result : payload mapObject (
lower '$$':$
)
The DW you tried should work if you wrap the expression in parenthesis. This ensures that the lower operator is applied to each of the keys first and then that value is used in the map. So for your example:
%dw 1.0
%output application/json
---
{
result : payload mapObject (
(lower '$$') : $
)
}
Interestingly enough, I get an error (mismatched input ':' expecting ')') in my Transform Message using this DW syntax but I am able to run the project without complaints from Anypoint Studio and the DW runs fine. It also works in MEL with the following:
#[dw("{result : payload mapObject ( (lower '$$' ) : $)}", 'application/json')]
Hope that helps!
You can use the below method to resolve the issue.
%dw 2.0
output application/json
---
{ result: payload mapObject (
(lower ('$$')): $
)
}
In addition if need to lower case also a values then its will be like:
%dw 1.0
%output application/json
---
{
result : payload mapObject (
(lower $$) : (lower $)
)
}

Create json array using dataweave

If I have xml like so....
<Root>
<Authority>Water</Authority>
<Sanctions>
<Sanction>
<SanctionCode>11</SanctionCode>
<SanctionDesc>First Sanction</SanctionDesc>
</Sanction>
<Sanction>
<SanctionCode>11</SanctionCode>
<SanctionDesc>Second Sanction</SanctionDesc>
</Sanction>
</Sanctions>
</Root>
Using DataWeave how can I create a json array of Santions using only the SanctionDesc?
I've tried this but it's not right...
%dw 1.0
%output application/json
---
records: payload.Root map {
Authority: $.Authority,
sanctions: $.Sanctions.Sanction map [$.SanctionDesc]
}
I want my output to look like this...
{
"records": [{
"Authority": "Water",
"sanctions": ["First Sanction", "Second Sanction"]
}]
}
Try this
%dw 1.0
%output application/json
---
records: {
Authority: payload.Root.Authority,
sanctions: payload.Root.Sanctions..SanctionDesc
}
Or
%dw 1.0
%output application/json
---
records: {
Authority: payload.Root.Authority,
sanctions: payload.Root.Sanctions.*Sanction map $.SanctionDesc
}
Hope this helps.
Understading the map operator is the key when picking and choosing elements from input payload. Map operator goes through all the array elements on the left hand side and we can pick the values from on right hand side, Giving example from Mulesoft portal
%dw 1.0
%output application/json
users: ["john", "peter", "matt"] map ((firstName, position) -> position ++ ":" ++ upper firstName)
Output:
{
"users": [
"0:JOHN",
"1:PETER",
"2:MATT"
]
}
See link below:
https://docs.mulesoft.com/mule-user-guide/v/3.8/dataweave-operators#map

Dataweave Error for Null nodes

I have done coding in dataweava as
%dw 1.0
%input payload application/xml
%output application/xml skipNullOn="everywhere"
---
{((payload.*Order default []) map {
Order:{
Channel:$.#EnterpriseCode,
Code:$.#OrderNo,
Status:$.#Status,
OrderLines: {
(($.OrderLines.*OrderLine default []) map {
OrderLine:{
EntryNumber:"abc",
Status:$.#Status,
(($.OrderStatuses.*OrderStatus default []) map {
ShipDate:$.#StatusDate
})
}})}
}
}
)
}
But its giving error when assigning input as
<?xml version="1.0" encoding="UTF-8"?>
<Order EnterpriseCode="111" OrderNo="222" Status="Scheduled">
<OrderLines>
<OrderLine PrimeLineNo="2" Status="Shipped" OrderedQty="1000">
</OrderLine>
</OrderLines>
</Order>
Any suggestions here? I have tried default [] but its not working. When assigning null node its giving error. I have tried filter as filter ($ != '')
XML input example:
<?xml version="1.0" encoding="UTF-8"?>
<Order EnterpriseCode="111" OrderNo="222" Status="Scheduled">
<OrderLines>
<OrderLine PrimeLineNo="2" Status="Shipped" OrderedQty="1000">
<OrderStatuses>
<OrderStatus StatusDate="statusDate"></OrderStatus>
<OrderStatus StatusDate="statusDate"></OrderStatus>
</OrderStatuses>
</OrderLine>
<OrderLine PrimeLineNo="3" Status="Shipped3" OrderedQty="10003" ></OrderLine>
</OrderLines>
</Order>
Note: In your example there are spaces between OrderLine open tag and close tag, you have to fix it:
<OrderLine PrimeLineNo="3" Status="Shipped3" OrderedQty="10003" ></OrderLine>
Dataweave script:
%input payload application/xml
%output application/xml skipNullOn="everywhere"
---
{
((payload.*Order default []) map {
Order:{
Channel:$.#EnterpriseCode,
Code:$.#OrderNo,
Status:$.#Status,
OrderLines: {
(($.OrderLines.*OrderLine default []) map {
OrderLine:{
EntryNumber:"abc",
Status:$.#Status,
(($.OrderStatuses.*OrderStatus default []) map ((key,pos) -> {
ShipDate:key.#StatusDate
}) when $!='' otherwise {})
}
})
}
}
})
}
You can't map a value if it doesn't exist, so you have to use "when/otherwise" to verify the existence of the elements.
Try this:
This should solve your issue. (Unless not/otherwise) or (when/otherwise), any combination can be used as per your requirement. "Unless not" is recommended if ShipDate is present in most cases, else replace "unless not" with "when".
%dw 1.0
%input payload application/xml
%output application/xml skipNullOn="everywhere"
---
{
(
(payload.*Order default []) map {
Order: {
Channel:$.#EnterpriseCode,
Code:$.#OrderNo,
Status:$.#Status,
OrderLines: {
(
($.OrderLines.*OrderLine default []) map ({
OrderLine: {
EntryNumber:"abc",
Status:$.#Status,
(
($.OrderStatuses.*OrderStatus) map {
ShipDate:$.#StatusDate
}
)
}
}) unless not $.OrderLines.*OrderLine.OrderStatuses? otherwise {
OrderLine: {
EntryNumber:"abc",
Status:$.#Status
}
}
)
}
}
}
)
}
Try following approaches:
use "SkipNullOn" %output application/xml skipNullOn="everywhere"
You can use when condition as shown below yourField: "null" when
payload.yourField == null otherwise payload.yourField
Giving below the structure definition of Mule Message Object has
Message
Inbound Property
Outbound Property
Payload
Variable
Flow Variable
Session Variable
Attachment
Exception Payload
When a connector of a flow (listening on a port) receives the payload its called Inbound endpoint.
When in a flow we have a connectore placed in the middle and send a payload its called Oubound endpoint. Here the all the outbound properties sent to the Http Outbound flow become Inbound Properties within that flow.
For detailed explanation see the link below.
https://docs.mulesoft.com/mule-user-guide/v/3.8/mule-message-structure.