Technical Articles
EIPinCPI – Message Translator
Previous – Message Broker | Index | Next – Envelope Wrapper
This week, we’ll begin studying Message Transformation patterns and the first one is known as Message Translator.
When do I use this pattern?
I like to think of middleware software as a translator similar to a language translator. A language translator can translate one language into another. For example, word Hello in English is Hola in Spanish or Namaskāra in Marathi or Kon’nichiwa in Japanese.
Similarly, if system A speaks in XML and system B speaks in JSON, middleware software can translate. If system A calls unique identification of a customer as CustomerID and system B calls it KUNNR, middleware software can translate.
When two systems have different ways of representing the data such as JSON, XML, etc. or when two systems have a different data model to represent the same entity, Message Translator pattern can be applied.
Message Translator in CPI
In CPI, we can tackle both kinds of translations. Converters can be used to translate messages from one format into another. Whereas, Mappings can be used to translate messages from one data model to another.
Converter
In essence, CPI supports translating 3 formats: XML, JSON, and CSV. There are 4 converters supported out of the box:
How would you convert JSON to CSV and vice versa? Simply combine the two converters. For converting a message from JSON to CSV, use JSON to XML Converter first and then use XML to CSV Converter. For converting the message from CSV to JSON, use CSV to XML Converter first and then use XML to JSON Converter.
Let’s look at the examples for each of these converters below. I’ll show simple examples to get started. To learn more and dive deep, please go through Help Documentation on each converter linked above or below in the References/Further Readings section.
JSON to XML Converter
Integration Flow
The Integration Flow used for this exercise is simple. It uses the Command Message pattern to Get the Customer ‘ALFKI’ in JSON format using HTTP Receiver Adapter, passes the payload through JSON to XML Converter, and logs the output using Groovy Script.
Configuration of HTTP Receiver Adapter
Tab | Parameter | Value |
Connection | Address | https://services.odata.org/V2/Northwind/Northwind.svc/Customers(‘ALFKI’) |
Connection | Query | $format=json |
Connection | Method | GET |
Connection | Authentication | None |
Configuration of JSON to XML Converter
Tab | Parameter | Value |
Processing | Use Namespace Mapping | Unchecked |
Processing | JSON Prefix Separator | Colon (:) |
Processing | Add XML Root Element | Unchecked |
Input to Converter
{
"d": {
"__metadata": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Customers('ALFKI')",
"type": "NorthwindModel.Customer"
},
"CustomerID": "ALFKI",
"CompanyName": "Alfreds Futterkiste",
"ContactName": "Maria Anders",
"ContactTitle": "Sales Representative",
"Address": "Obere Str. 57",
"City": "Berlin",
"Region": null,
"PostalCode": "12209",
"Country": "Germany",
"Phone": "030-0074321",
"Fax": "030-0076545",
"Orders": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Customers('ALFKI')/Orders"
}
},
"CustomerDemographics": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Customers('ALFKI')/CustomerDemographics"
}
}
}
}
Output from Converter
<d>
<__metadata>
<uri>https://services.odata.org/V2/Northwind/Northwind.svc/Customers('ALFKI')</uri>
<type>NorthwindModel.Customer</type>
</__metadata>
<CustomerID>ALFKI</CustomerID>
<CompanyName>Alfreds Futterkiste</CompanyName>
<ContactName>Maria Anders</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
<Address>Obere Str. 57</Address>
<City>Berlin</City>
<Region/>
<PostalCode>12209</PostalCode>
<Country>Germany</Country>
<Phone>030-0074321</Phone>
<Fax>030-0076545</Fax>
<Orders>
<__deferred>
<uri>https://services.odata.org/V2/Northwind/Northwind.svc/Customers('ALFKI')/Orders</uri>
</__deferred>
</Orders>
<CustomerDemographics>
<__deferred>
<uri>https://services.odata.org/V2/Northwind/Northwind.svc/Customers('ALFKI')/CustomerDemographics</uri>
</__deferred>
</CustomerDemographics>
</d>
CSV to XML Converter
Integration Flow
The Integration Flow uses the Content Modifier to set the CSV input, passes the payload through CSV to XML Converter, and logs the output using Groovy Script.
Configuration of CSV to XML Converter
Tab | Parameter | Value |
Processing | XML Schema | /xsd/Customers.xsd |
Processing | Path to Target Element in XSD | /Customers/Customer |
Processing | Record Marker in CSV | |
Processing | Field Separator in CSV | Comma(,) |
Processing | Exclude First Line Header | Checked |
Processing | Configure CSV Headers to match | CSV Fields Sequence |
Input to Converter
CompanyName,Address,Phone,Region,PostalCode,Country,CustomerID,City,Fax,ContactName,ContactTitle
Alfreds Futterkiste,Obere Str. 57,030-0074321,,12209,Germany,ALFKI,Berlin,030-0076545,Maria Anders,Sales Representative
Output from Converter
<Customers>
<Customer>
<CompanyName>Alfreds Futterkiste</CompanyName>
<Address>Obere Str. 57</Address>
<Phone>030-0074321</Phone>
<Region/>
<PostalCode>12209</PostalCode>
<Country>Germany</Country>
<CustomerID>ALFKI</CustomerID>
<City>Berlin</City>
<Fax>030-0076545</Fax>
<ContactName>Maria Anders</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
</Customer>
</Customers>
XML to CSV Converter
Integration Flow
Similar to Integration flow used for JSON to XML Converter, this Integration Flow uses the Command Message pattern to Get the Customer ‘ALFKI’ in XML format using OData Receiver Adapter, passes the payload through XML to CSV Converter, and logs the output using Groovy Script.
Configuration of OData Receiver Adapter
Tab | Parameter | Value |
Connection | Address | https://services.odata.org/V2/Northwind/Northwind.svc |
Connection | CSRF Protected | Unchecked |
Processing | Operation Details | Read (GET) |
Processing | Resource Path | Customers(‘ALFKI’) |
Configuration of XML to CSV Converter
Tab | Parameter | Value |
Processing | Path to Source Element in XSD | /Customers/Customer |
Processing | Field Separator in CSV | Comma (,) |
Processing | Include Field Name as Headers | Checked |
Processing | Include Parent Element | Unchecked |
Processing | Include Attribute Values | Unchecked |
Input to Converter
<Customers>
<Customer>
<CompanyName>Alfreds Futterkiste</CompanyName>
<Address>Obere Str. 57</Address>
<Phone>030-0074321</Phone>
<Region/>
<PostalCode>12209</PostalCode>
<Country>Germany</Country>
<CustomerID>ALFKI</CustomerID>
<City>Berlin</City>
<Fax>030-0076545</Fax>
<ContactName>Maria Anders</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
</Customer>
</Customers>
Output from Converter
CompanyName,Address,Phone,Region,PostalCode,Country,CustomerID,City,Fax,ContactName,ContactTitle
Alfreds Futterkiste,Obere Str. 57,030-0074321,,12209,Germany,ALFKI,Berlin,030-0076545,Maria Anders,Sales Representative
XML to JSON Converter
Integration Flow
Similar to Integration flow used for JSON to XML Converter, this Integration Flow uses the Command Message pattern to Get the Customer ‘ALFKI’ in XML format using OData Receiver Adapter, passes the payload through XML to JSON Converter, and logs the output using Groovy Script.
Configuration of OData Receiver Adapter
Tab | Parameter | Value |
Connection | Address | https://services.odata.org/V2/Northwind/Northwind.svc |
Connection | CSRF Protected | Unchecked |
Processing | Operation Details | Read (GET) |
Processing | Resource Path | Customers(‘ALFKI’) |
Configuration of XML to JSON Converter
Tab | Parameter | Value |
Processing | Use Namespace Mapping | Unchecked |
Processing | JSON Prefix Separator | Colon (:) |
Processing | JSON Output Encoding | From Header or Property |
Processing | Suppress JSON Root Element | Unchecked |
Processing | Streaming | Unchecked |
Input to Converter
<Customers>
<Customer>
<CompanyName>Alfreds Futterkiste</CompanyName>
<Address>Obere Str. 57</Address>
<Phone>030-0074321</Phone>
<Region/>
<PostalCode>12209</PostalCode>
<Country>Germany</Country>
<CustomerID>ALFKI</CustomerID>
<City>Berlin</City>
<Fax>030-0076545</Fax>
<ContactName>Maria Anders</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
</Customer>
</Customers>
Output from Converter
{
"Customers": {
"Customer": {
"CompanyName": "Alfreds Futterkiste",
"Address": "Obere Str. 57",
"Phone": "030-0074321",
"Region": "",
"PostalCode": "12209",
"Country": "Germany",
"CustomerID": "ALFKI",
"City": "Berlin",
"Fax": "030-0076545",
"ContactName": "Maria Anders",
"ContactTitle": "Sales Representative"
}
}
}
Mapping
CPI supports Message Mapping and XSLT Mapping. Message Mapping uses a visual editor to map the value of a node from a source data model to target data model. Whereas, XSLT mapping, as the name suggests, uses XSLT stylesheets to transform a source XML document into the target XML document.
Message Mapping
A sample message mapping looks like below:
XSLT Mapping
An example of an XSL Stylesheet is like below:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Customers>
<xsl:for-each select="/DEBMAS07/IDOC">
<Customer>
<CompanyName><xsl:value-of select="E1KNA1M/NAME1" /></CompanyName>
<Address>N/A</Address>
<Phone><xsl:value-of select="E1KNA1M/TELF1" /></Phone>
<Region><xsl:value-of select="E1KNA1M/REGIO" /></Region>
<PostalCode><xsl:value-of select="E1KNA1M/PSTLZ" /></PostalCode>
<Country><xsl:value-of select="E1KNA1M/LAND1" /></Country>
<CustomerID><xsl:value-of select="E1KNA1M/KUNNR" /></CustomerID>
<City><xsl:value-of select="E1KNA1M/ORT01" /></City>
<Fax><xsl:value-of select="E1KNA1M/TELFX" /></Fax>
<ContactName><xsl:value-of select="E1KNA1M/E1KNA11/PSON1" /></ContactName>
<ContactTitle><xsl:value-of select="E1KNA1M/E1KNA11/PSOTL" /></ContactTitle>
</Customer>
</xsl:for-each>
</Customers>
</xsl:template>
</xsl:stylesheet>
Example
Input
<?xml version="1.0" encoding="UTF-8"?>
<DEBMAS07>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
<DIRECT>1</DIRECT>
<IDOCTYP>DEBMAS07</IDOCTYP>
<SNDPOR>SNDPOR</SNDPOR>
<SNDPRT>SNDPRT</SNDPRT>
<SNDPRN>SNDPRN</SNDPRN>
<RCVPOR>RCVPOR</RCVPOR>
<RCVPRN>RCVPRN</RCVPRN>
</EDI_DC40>
<E1KNA1M SEGMENT="1">
<KUNNR>ALFKI</KUNNR>
<LAND1>DE</LAND1>
<NAME1>Alfreds Futterkiste</NAME1>
<ORT01>Berlin</ORT01>
<PSTLZ>12209</PSTLZ>
<REGIO></REGIO>
<TELF1>030-0074321</TELF1>
<TELFX>030-0076545</TELFX>
<E1KNA11>
<PSON1>Maria Anders</PSON1>
<PSOTL>Sales Representative</PSOTL>
</E1KNA11>
</E1KNA1M>
</IDOC>
</DEBMAS07>
Please note that the above is simply a created example and is not an actual IDoc XML created from an ECC system.
Output
<Customers>
<Customer>
<CompanyName>Alfreds Futterkiste</CompanyName>
<Address>N/A</Address>
<Phone>030-0074321</Phone>
<Region/>
<PostalCode>12209</PostalCode>
<Country>DE</Country>
<CustomerID>ALFKI</CustomerID>
<City>Berlin</City>
<Fax>030-0076545</Fax>
<ContactName>Maria Anders</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
</Customer>
</Customers>
Daniel has listed the advantages of using XSLT mappings in his blog I *heart* XSLT mappings.
Groovy Mapping
Groovy Mapping is a way of using Groovy Script to transform source payload into target payload. Eng Swee argues that Groovy Mappings are a way to go for mapping in his blog I *heart* Groovy mapping.
Which kind of mapping to use and when?
For understanding Pros and Cons of each type of mappings offered by CPI, read Morten‘s blog Cloud Integration mapping: Your options explained and compared.
Conclusion
Message Translator pattern is applied when two systems use a different format of representing data or different schema to represent the same entity.
References/Further Readings
- Message Translator Pattern in Enterprise Integration Patterns
- Blogs for choosing which mapping to use
- EIPinCPI
- CPI Components
Hope this helps,
Bala
I guess this pattern is one of the most used. You always want to translate or map the structure.