Friends,
I have two inputs, A and B, both JSON.
I need to generate with DataMapper, a single output (custom) also in JSON format.
Example:
My Input A:
{
"name": "John Doe",
"age": "40"
}
My Input B:
{
"country": "Brazil"
"city": "Rio de Janeiro"
}
My Custom Output:
{
"customerName": "John Doe",
"customerAge": "40",
"customerCountry": "Brazil",
"customerCity": "Rio de Janeiro"
}
It can generate this output using the Mule DataMapper? How to?
At the time, I know use only one Input with DataMapper.
You need to take one of the input as the payload and the other as the variable.
My Payload was
{
"name": "John Doe",
"age": "40"
}
My Variable was
{
"country": "Brazil"
"city": "Rio de Janeiro"
}
Please find the below sample that I tested and works.
<flow name="combineFlow">
<http:listener config-ref="HTTP_Listener_Configuration"
path="/testings" doc:name="HTTP" />
<logger message="Coming here " level="INFO" doc:name="Logger" />
<set-variable variableName="mypayload"
value="{"country": "Brazil","city": "Rio de Janeiro"}"
doc:name="Variable" mimeType="application/json" />
<logger level="INFO" doc:name="Logger" />
<dw:transform-message doc:name="Transform Message">
<dw:set-payload><![CDATA[%dw 1.0
%output application/json
---
{
"customerName": payload.name,
"customerAge": payload.age,
"customerCountry": flowVars.mypayload.country,
"customerCity": flowVars.mypayload.city
}]]></dw:set-payload>
</dw:transform-message>
</flow>
Hope this helps
Slightly similar with previous answer: you need to take one input as payload and another one as variable.
Following is the implementation using DataMapper (not DataWeave/Transform Message)
XML:
<flow name="genericFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/dm" doc:name="HTTP" allowedMethods="POST"/>
<set-variable variableName="inputB"
value="#['{"country": "Brazil", "city": "Rio de Janeiro"}']" mimeType="application/json"
doc:name="Input B" />
<data-mapper:transform config-ref="JSON_To_JSON" doc:name="JSON To JSON">
<data-mapper:input-arguments>
<data-mapper:input-argument key="inputBjson">#[new org.json.JSONObject(flowVars.inputB)]</data-mapper:input-argument>
</data-mapper:input-arguments>
</data-mapper:transform>
<echo-component doc:name="Echo" />
</flow>
GRF:
...
<Dictionary>
<Entry id="DictionaryEntry0" input="true" name="inputPayload" output="false" type="object"/>
<Entry id="DictionaryEntry1" input="false" name="outputPayload" output="true" type="object"/>
<Entry dictval.__javaType="org.json.JSONObject" id="DictionaryEntry2" input="true" name="inputBjson" output="false" type="object"/>
</Dictionary>
...
<attr name="melScript"><![CDATA[//MEL
//START -> DO NOT REMOVE
output.__id = input.__id;
//END -> DO NOT REMOVE
output.customerName = input.name;
output.customerAge = input.age;
output.customerCountry = inputArguments.inputBjson.getString("country");
output.customerCity = inputArguments.inputBjson.getString("city");]]></attr>
Notes: input B is registered to DataMapper as Input Argument with Type = Object (MEL only), and its class is: org.json.JSONObject
One input give it as payload and other one use message properties and store the second input values as variable.Now inside data mapper use the variable in input argument field and map it.Simple!! hope it helps.
Related
I used to convert payload to string whenever i need to log the payload on console using the syntax in mule 3 [message.payloadAs(java.lang.String)] and some times used to use object to string converter or object to array converter.
But in mule 4 i don't see any converter as in mule 3 and [message.payloadAs(java.lang.String)] is alos not working.
Please assist me any new syntax of component or consept has come in mule 4 ?
Input
[
{
"firstName": "Ram",
"lastName": "Ram1",
"address": [
{
"street": "a",
"city": "b",
"state": "c"
},
{
"street": "a1",
"city": "b1",
"state": "c1"
}
]
}
Batch Image
Code
<batch:job jobName="Batch_ProcessingBatch_Job" doc:id="2582eccb-720f-499f-99fe-424cab3c9a33" >
<batch:process-records >
<batch:step name="Batch_Step1" doc:id="cb045f6b-edd3-426f-8f28-0d20b301fb6d" >
<logger level="INFO" doc:name="Logger" doc:id="2491184f-e8d7-47b7-bef0-29bafd43247f" message="In Batch_step1........... #[payload]"/>
<batch:aggregator doc:name="Batch Aggregator" doc:id="aa9c1b60-395f-4376-804d-bced200dfb43" size="2">
<set-payload value='#[write(payload, "application/json")]' doc:name="Set Payload" doc:id="9d4b27ee-5692-4a99-a93e-bd7c694f398d" />
<ee:transform doc:name="Transform Message" doc:id="06064422-1352-4ff9-8817-3e87eb1f4264" >
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
output application/json
---
payload map(item,index) -> {
name: item.firstName,
surname: item.lastName
}]]></ee:set-payload>
</ee:message>
</ee:transform>
<logger level="INFO" doc:name="Logger" doc:id="c955490e-fab1-436e-8265-f706a577c9d2" message="In Batch_step1 Aggrigator........... #[payload]" />
</batch:aggregator>
</batch:step>
</batch:process-records>
<batch:on-complete >
<logger level="INFO" doc:name="Logger" doc:id="a3923c90-557b-4955-9c40-afd748719abd" message="#['#####It is oncomplete result####': write(payload, "application/json")]"/>
</batch:on-complete>
</batch:job>
Getting Error
Message : "You called the function 'map' with these arguments:
1: String ("[\n \"{\\n \\\"firstName\\\": \\\"Ram\\\",\\n \\\"lastName\\\": \\\"Ram1\...)
2: Function ((item:Any, index:Any) -> ???)
But it expects arguments of these types:
1: Array
2: Function
4| payload map(item,index) -> {
| ...
7| }
Trace:
at map (line: 4, column: 1)
at main (line: 4, column: 9)" evaluating expression: "%dw 2.0
output application/json
---
payload map(item,index) -> {
name: item.firstName,
surname: item.lastName
}".
Error type : MULE:EXPRESSION
Element : Batch_ProcessingFlow/processors/0/route/0/route/0/aggregator/processors/1 # training-1:Batch Processing.xml:27 (Transform Message)
Element XML : <ee:transform doc:name="Transform Message" doc:id="06064422-1352-4ff9-8817-3e87eb1f4264">
<ee:message>
<ee:set-payload>%dw 2.0
output application/json
---
payload map(item,index) -> {
name: item.firstName,
surname: item.lastName
}</ee:set-payload>
</ee:message>
</ee:transform>
(set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
After quick googling the new way is to use #[message.payload as String] as shown in link.
You can use the payload.^raw syntax for the loggers. It was introduced in mule 4 and can handles cases where string conversion is needed. Typically pairs well with output text/plain format in a logger.
Ref: https://docs.mulesoft.com/mule-runtime/4.3/dataweave-cookbook-extract-data#metadata_selector
NOTE its never a good idea to log entire payloads (that could contain PII etc..) with maybe an exception where you are building a report that you need to log at the end of your batch process which possibly could be the case here...
I am trying to create aperak-edifact file from mule data weaver component.
Here is my piece of code
<edifact-edi:config name="EDIFACT_EDI" delimiterUsage="USE_SPECIFIED_FOR_WRITES" doc:name="EDIFACT EDI" interchangeIdPartner="YYYY" interchangeIdSelf="XXXX">
<edifact-edi:schemas>
<edifact-edi:schema>/edifact/d98b/APERAK.esl</edifact-edi:schema>
</edifact-edi:schemas>
</edifact-edi:config>
<flow name="new1Flow">
<file:inbound-endpoint path="C:\Users\Desktop" responseTimeout="10000" doc:name="File">
<file:filename-regex-filter pattern="aperak.xml" caseSensitive="true"/>
</file:inbound-endpoint>
<dw:transform-message doc:name="Transform Message">
<dw:set-payload><![CDATA[%dw 1.0
%output application/java
---
{
Messages: {
D98B: {
APERAK: [{
Interchange: {
UNB0201: "XXX",
UNB0301: "YYYY"
},
MessageHeader: {
UNH01: "1"
},
Heading: {
"0020_BGM": {
BGM0101: "7"
}
}
}]
}
}
}]]></dw:set-payload>
</dw:transform-message>
<edifact-edi:write config-ref="EDIFACT_EDI" doc:name="EDIFACT EDI"/>
<file:outbound-endpoint path="C:\Users\Desktop" outputPattern="out.json" responseTimeout="10000" doc:name="File"/>
</flow>
Output
UNB+UNOB:4+XXX+YYY+05042016:0948+1'UNH+2+APERAK:D:98B:UN'BGM+7'UNT+3+2'UNZ+1+1'
But the output created is all in one line where I want it to be appeared line by line. So how can I introduce new line for edifact
Any help is appreciated
Expected Output
UNB+UNOB:4+XXX+YYY+05042016:0948+1'
UNH+2+APERAK:D:98B:UN'
BGM+7'
UNT+3+2'UNZ+1+1'
Set the lineEnding configuration attribute of edifact-edi:config to output a CRLF.
How can I do the equivalent of a SQL join in Dataweave? I'm basically implementing a lookup. I have CSV data and JSON data in flow variables. I'm able to use both of them, but I can't figure out how connect them. Let's say the CSV has two columns:
Name,ExternalId
Foo,1
Bar,2
Baz,2
The JSON data is:
{
ExternalEntities: [
{ "Id": 1, "Name": "One", "Description": "Thing One" }
, { "Id": 2, "Name": "Two", "Description": "Thing Two" }
]
}
In the end, I'd like a List<Hashmap> with the following (expressed here in JSON format for convenience.)
[
{ "Name": "Foo", "ExternalName": "One", "ExternalDescription": "Thing One" }
, { "Name": "Bar", "ExternalName": "Two", "ExternalDescription": "Thing Two" }
, { "Name": "Baz", "ExternalName": "Two", "ExternalDescription": "Thing Two" }
]
So here is a sample using the json as the payload and the csv as a lookup table. The first flows parses the json and does a flow lookup passing the 'Id' as the payload. The second flow loads the csv as an array and does a search by the Id passed in. This returns a map of the CSV record found where you can then extract the 'Name' field.
It is possible to do this in one transformer, but for demo sake this was easier. You can also reverse the lookup with some tinkering if you want the csv as your payload and the json as your lookup.
<flow name="lookuptest" processingStrategy="synchronous">
<poll doc:name="Poll">
<logger level="INFO" doc:name="Logger" />
</poll>
<set-payload
value="{ "ExternalEntities": [ { "Id": 1, "Name": "One", "Description": "Thing One" } , { "Id": 2, "Name": "Two", "Description": "Thing Two" } ] }"
doc:name="Set Payload" mimeType="application/json"></set-payload>
<dw:transform-message doc:name="Transform Message">
<dw:input-payload doc:sample="string_2.dwl" />
<dw:set-payload><![CDATA[%dw 1.0
%input payload application/json
%output application/json
---
payload.ExternalEntities map ((value , index) -> {
Name: lookup("NameLookup", [value.Id as :string]).Name
})]]></dw:set-payload>
</dw:transform-message>
<object-to-string-transformer doc:name="Object to String"/>
<logger level="ERROR" message="#[payload]" doc:name="Logger"/>
</flow>
<flow name="NameLookup" processingStrategy="synchronous">
<set-variable value="#[payload[0]]" variableName="ExternalId"
doc:name="Variable" />
<set-payload
value="#[Thread.currentThread().getContextClassLoader().getResourceAsStream('lookuptables/namelookup.csv')]"
mimeType="application/csv" doc:name="Variable" />
<dw:transform-message doc:name="Transform Message">
<dw:input-payload doc:sample="string_2.dwl" />
<dw:set-payload><![CDATA[%dw 1.0
%input payload application/csv
%output application/java
---
(payload[?($.ExternalId == flowVars['ExternalId'])])[0]
]]></dw:set-payload>
</dw:transform-message>
</flow>
Here's a second solution that works, though I accepted #Ryan Carter's answer.
%dw 1.0
%output application/json
---
flowVars.myCsv map (
(row0, i) -> using (lookupElement = (flowVars.jsonLookup.ExternalEntities filter ((obj1) -> row0.ExternalId ~= obj1.Id))[0]) {
Name: row0.Name
, ExternalName: lookupElement.Name
, ExternalDescription: lookupElement.Description
} mapObject ({"$$": $, (StartsWithB:$[0] == "B") when $$ ~= "Name"})
)
I tried to extract json array data using message enricher. But in output I got some object data.How can I fetch properly?
Following is my flow
<flow name="readfileFlow1" doc:name="readfileFlow1">
<file:inbound-endpoint path="Test" moveToDirectory="Backup" responseTimeout="10000" doc:name="File"/>
<enricher source="#[(name in payload.data)]" target="#[flowVars.myMap]" doc:name="Message Enricher">
<json:json-to-object-transformer returnClass="java.util.HashMap" doc:name="JSON to Object"/>
</enricher>
<logger message="#[payload.toString()]" level="INFO" doc:name="Logger"/>
</flow>
When I print in logger then I got following output
INFO 2015-04-29 13:01:20,409 [[readfile].readfileFlow1.stage1.02] org.mule.api.processor.LoggerMessageProcessor: org.mule.transport.file.ReceiverFileInputStream#15bc5cc
How can I extract properly all name
I tried using for each . Using for each I can extract succesfully. But want to use message enricher. How can I do this using message enricher MVEL??
My json data is as follow..
{
"data":[
{
"id" : "1",
"name": "AAA"
},
{
"id" : "5",
"name": "DDD"
},
{
"id" : "6",
"name": "CCC"
},
]
}
I have done this..
silly mistake I made..
Following is my answer
<logger message="#[flowVars.myMap]" level="INFO" doc:name="Logger"/>
This is how you can achieve to extract name and id from your JSON payload .. you will get it in logger
<flow name="readfileFlow1" doc:name="readfileFlow1">
<file:inbound-endpoint path="Test" moveToDirectory="Backup" responseTimeout="10000" doc:name="File"/>
<enricher source="#[message.payload]" target="#[flowVars.myMap]" doc:name="Message Enricher">
<processor-chain doc:name="Processor Chain">
<json:json-to-object-transformer returnClass="java.util.HashMap" doc:name="JSON to Object"/>
<foreach collection="#[payload.data]">
<logger level="INFO" message="Name :- #[payload.name] and Id:- #[payload.id]"/>
</foreach>
</processor-chain>
</enricher>
<logger level="INFO" message="#[flowVars.myMap]"/>
</flow>
One more thing you JSON payload is not valid.. try to remove an extra , at the end .. so your valid JSON file will be :-
{
"data":[
{
"id" : "1",
"name": "AAA"
},
{
"id" : "5",
"name": "DDD"
},
{
"id" : "6",
"name": "CCC"
}
]
}
I'm using Mule 3.4 CE and I have a JSON data coming through HTTP in the following format:
{
"People" : [
{
"Details" :
{
"Name" : "John Smith",
"Email" : "abc#mail.com"
}
},
{
"Details" :
{
"Name" : "Tim Smith",
"Email" : "def#mail.com"
}
},
{
"Details" :
{
"Name" : "Ken Smith",
"Email" : "ghi#mail.com"
}
},
}
I need to extract the emails and lookup the Salesforce contact with these emails and at the same time I want to retain the JSON payload. So my question is how do I extract the emails through MEL? (for e.g. something like "People/Details/*/Email" - I know this is not a valid, but I'm looking for the right syntax.
Edit: I want to extract the emails in one shot rather than indexing (for e.g. People/Details[0].Email, possibly using MEL.
There best way to query json is to transform it to a Map.
<json:json-to-object-transformer returnClass="java.util.HashMap" />
And then query it using MEL like standard MVEL or Java syntax
<logger message="#[payload.People[0].Details.email]" level="INFO" />
If you want to keep the original json payload intact, you can store the map in a variable using an enricher:
<enricher target="#[flowVars.myJsonMap]">
<json:json-to-object-transformer returnClass="java.util.HashMap" />
</enricher>
And query the variable instead of the payload:
<logger message="#[flowVars.myJsonMap.People[0].Details.email]" level="INFO" />
You could also map the json to a custom class using Jackson and change the returnClass attribute to your class.
This MEL cheat sheet detail JSON processing with MEL and also how to handle Maps, arrays etc: http://www.mulesoft.org/documentation/display/current/MEL+Cheat+Sheet
Note: You may come across a #[json:] evaluator, but this is deprecated in favour of the approach above.
UPDATE:
If you want to grab all the emails at once you can use MVEL projections:
<enricher target="#[flowVars.myJsonMap]" source="#[(Details.email in payload.People)]">
<json:json-to-object-transformer returnClass="java.util.HashMap" />
</enricher>
Mvel projections: http://mvel.codehaus.org/MVEL+2.0+Projections+and+Folds
If you want to get the particular email in the details use the below MEL expression.
#[json:People[0]/Details/Email]
If you want to get all the emails, pass the json path of repeatable in ForEach Collections then pass the path to get Email as shown below.
<flow name="parsingjsonFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
<foreach collection="#[json:People]" doc:name="For Each">
<logger message="#[json:/Details/Email]" level="INFO" doc:name="Logger"/>
</foreach>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger message="#[exception.getClass()]" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</flow>