0

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.

aled
  • 21,330
  • 3
  • 27
  • 34
codey_08
  • 249
  • 1
  • 11
  • Could you please post the fault payload in XML format? Thank you! – olamiral Apr 05 '22 at 08:37
  • In the fault payload, you could get fault message from /Envelope/Body/Fault/faultstring path. – codey_08 Apr 05 '22 at 11:10
  • The output is inconsistent with the input. Where does "TPCL" comes from? And the script is using input from variables, not the payload. You need to clarify those things. – aled Apr 05 '22 at 18:01
  • Remember that XPR has no meaning in Mule. It is just a name you use for the extension of your script files. It doesn't add any value to the question and can cause confusions. – aled Apr 05 '22 at 18:14

2 Answers2

4

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>
aled
  • 21,330
  • 3
  • 27
  • 34
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>
sudhish_s
  • 573
  • 2
  • 5
  • That XML does not appear to be the expected input. – aled Apr 06 '22 at 15:18
  • @aled Where do you see the discrepancy? I have updated the answer with the output. – sudhish_s Apr 06 '22 at 15:46
  • @aled, I see the difference. Message is not a separate field. – sudhish_s Apr 06 '22 at 15:52
  • I mean that the input you are using is not really the input from the question. You could just generate it inside your script since it is constant. You are taking the real input from `vars.faultPayload`. – aled Apr 06 '22 at 19:06
  • and another input from`vars.ratingModule`. What's in that variable? – aled Apr 06 '22 at 21:43
  • I did that because of the existing Mule 3 script that he has shared. That script uses the faultPayload and ratingModule from the flowVars, which would be vars in Mule4. So I kept the same functionality as the existing script. The script also does update only the first array element. If that is the case, the actual input payload is required to provide more accurate solution – sudhish_s Apr 06 '22 at 23:06
  • I was just noting that they are additional inputs that should be described. – aled Apr 07 '22 at 01:33