'How to iterate over the fault message in Mule 4

In my case, I tried to convert the below Mule Expression Language (MEL) script to DataWeave 2.0.

MEL script on Mule 3:

import java.util.Iterator;
import org.dom4j.*;
import java.util.logging.Logger;
import java.util.*;

faultstring = xpath3('/Envelope/Body/Fault/faultstring',payload).replaceFirst("rating failed:","");
faults = faultstring.split("rating failed:");

appNode = domPayload.selectSingleNode("/DTOApplication[1]");

for (fault : faults) {
appNode.addElement('ValidationError')
.addAttribute("TypeCd","Validation")
.addAttribute("Name","Rate Service Error")
.addAttribute("Msg","Rating Service Error (" + flowVars.ratingModule + "). Message: " + fault.trim())
.addAttribute("SubTypeCd","ERROR");
}

The logic is to append the fault message payload to the dompayload (it's nothing but an input request).

I was able to append the single child node for the returned fault message:

<?xml version="1.0" encoding="UTF-8"?>
<DTOApplication id="Application-1660258480-1493174910">
    <ValidationError TypeCd="Validation" Name="Rate Service Error" Msg="Rate Service Error (TPCL)" Message=", Policy.Class='424490C' not in list , Policy.Industry='WHOL' not in list " SubTypeCd="ERROR"/>
</DTOApplication>

Expected output :

<?xml version="1.0" encoding="UTF-8"?>
<DTOApplication id="Application-1660258480-1493174910">
    <ValidationError TypeCd="Validation" Name="Rate Service Error" Msg="Rating Service Error (TPCL). Message: Policy.Class='424490C' not in list" SubTypeCd="ERROR"/>
    <ValidationError TypeCd="Validation" Name="Rate Service Error" Msg="Rating Service Error (TPCL). Message: Policy.Industry='WHOL' not in list" SubTypeCd="ERROR"/>
</DTOApplication>

I tried DataWeave 2.0 :

%dw 2.0
var errormessage = (vars.fault replace "rating failed:" with ", ")
var ratingModule= vars.faultPayload.Envelope.Body.Fault.faultstring 
output application/xml  writeDeclaration=false
---
payload mapObject ((value, key, index) ->
  (key): value ++ {
    ValidationError @(TypeCd: "Validation", Name:"Rate Service Error" ,Msg: "Rate Service Error (" ++ ratingModule ++ ")" , Message: errormessage, SubTypeCd: "ERROR"): null
  }
)

Fault payload :

{Envelope={Body={rateResponse=null, Fault={faultcode=FcgiSvc.16.rateHASH.service.exception, faultstring=rating failed:Policy.Class='424490C' not in list rating failed:Policy.Industry='WHOL' not in list }}}}

I want to do something equivalent to for (fault : faults) in DataWeave 2.0.



Solution 1:[1]

DataWeave is a functional language and does not has a for or foreach concept. You need to transform whatever input using functions like map, mapObject, reduce, etc. to achieve the same result.

In this case you want to iterate over `payload.Envelope.Body.Fault.faultstring' however it is a string. It can not be iterated directly. First you need to split the string by some separator substring so we get an array of elements. We can split faultstring using "rating failed:" as the separator, then map each string to a key-pair which will be used as an element, then reduce to concatenate all the key-pairs into a single object.

%dw 2.0
output application/xml
var fault=payload.Envelope.Body.Fault
var errormessage = (fault.faultstring splitBy "rating failed:") filter sizeOf($) > 0
---
{ 
    DTOApplication: (errormessage map {ValidationError @(TypeCd: "Validation", Name:"Rate Service Error" ,Msg: "Rate Service Error (TCPL).",  Message: $, SubTypeCd: "ERROR"): null })
        reduce ($$ ++ $)
}

Output:

<DTOApplication>
  <ValidationError TypeCd="Validation" Name="Rate Service Error" Msg="Rate Service Error (TCPL)." Message="Policy.Class='424490C' not in list " SubTypeCd="ERROR"/>
  <ValidationError TypeCd="Validation" Name="Rate Service Error" Msg="Rate Service Error (TCPL)." Message="Policy.Industry='WHOL' not in list" SubTypeCd="ERROR"/>
</DTOApplication>

Solution 2:[2]

I assume the input payload is something like below

<?xml version="1.0" encoding="UTF-8"?>
<DTOApplication id="Application-1660258480-1493174910">
</DTOApplication>

Assuming the above payload, I used the update operator. For more detail, please check this cookbook

%dw 2.0
output application/xml

var faultstring = (vars.faultPayload.Envelope.Body.Fault.faultstring replace "rating failed:" with ",") default ""

var faults = faultstring[1 to -1] splitBy ","
---
payload update  {
    case .DTOApplication -> ($ default {}) ++ {
            (faults map ((item) -> {
                        ValidationError @(
                                TypeCd: "Validation", 
                                Name:"Rate Service Error",
                                Msg: "Rate Service Error (" ++ vars.ratingModule ++ ")"  ++ " Message: " ++ trim(item) replace ":" with "=", 
                                SubTypeCd: "ERROR"
                            ): null
            }))
    }
}

Output

<?xml version='1.0' encoding='UTF-8'?>
<DTOApplication id="Application-1660258480-1493174910">
  <ValidationError TypeCd="Validation" Name="Rate Service Error" Msg="Rate Service Error (TPCL) Message= Policy.Class='424490C' not in list" SubTypeCd="ERROR"/>
  <ValidationError TypeCd="Validation" Name="Rate Service Error" Msg="Rate Service Error (TPCL) Message= Policy.Industry='WHOL' not in list" SubTypeCd="ERROR"/>
</DTOApplication>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2