Maps
Transform messages between formats using XSLT 3.0 with full XPath 3.1 support — XML, JSON, CSV, and flat files, all from a single mapping language.
A map is the transformation step that sits between two message shapes. It accepts a payload in one format, runs an XSLT 3.0 stylesheet against it, and emits a new payload — usually carrying a different message type. Maps are scoped to an Application and run from a hookpoint on a port; they never run on their own.
Saxon HE 12.9 provides the engine; the XSLT 3.0 / XPath 3.1 function library covers XML, JSON, CSV, and flat text out of the box. There is no compile step — saving a map deploys it.
Maps in Art2link ESB define the transformation logic between source and destination message formats. A map takes an incoming message — XML, JSON, or flat text — and produces a structured output in whatever format the destination system requires.
Maps are authored as XSLT stylesheets using the built-in code editor. XSLT 3.0 provides native support for XML, JSON, CSV, and plain text transformations, making it the ideal language for modern integration scenarios where messages arrive in mixed formats.
There is no compilation or deployment step. Write your map, save it, and reference it from a Port. Art2link ESB handles the rest.
Maps are scoped to an Application. From the application menu, the Maps list shows every map you have defined inside that application; a map can only be referenced from ports in the same application.
The list view follows the platform's Selected Application behavior — with an Application selected, the list filters to it and the Application column is hidden; with no selection, the list spans every Application you have access to and the column is shown. Creating a new map uses the same flow: with an Application selected, the form opens with that Application preemptively chosen; without one, the form exposes an Application picker.
A map only does work once it is referenced from a hookpoint — most often a map step on a port. The hookpoint itself decides whether the map runs at all and, when several maps are in play, which one runs for a given message. There are three configurations.
Typed table rows are unique by source Message Type — the UI enforces that. From the map’s own perspective the three modes look the same: write the XSLT once and the hookpoint decides when it runs. The hookpoint-specific rules — how the incoming Message Type is resolved, what happens after the map runs, and which modes are available on a given side of a given port — live with the port: see Receive port, Send port, Loopback port, and Null port.
A map’s output is not just a new payload — it is a brand-new message that carries its own message type. The runtime treats that as an instantiation moment: the new type’s promotions are evaluated against the freshly produced payload and, if a schema is associated with the destination type, the payload is validated against it. This is the same machinery that fires at inbound classification — the second of the two moments documented in When a message type is instantiated.
The Art2link ESB map engine is powered by SaxonHE 12.9, an industry-standard XSLT processor that provides full compliance with the latest W3C specifications.
| Capability | Version |
|---|---|
| XSLT | 3.0 (backwards compatible with 1.0 and 2.0) |
| XPath | 3.1 |
| XQuery | 3.1 |
| XSLT 4.0 | Selective support for proposed features |
XSLT 3.0 handles the four message-type formats natively, but not all four can be read or written with the same machinery. XML and JSON are first-class on both sides; CSV is consumed natively and emitted as text; flat text outside CSV needs a small adapter on the way in.
CSV input is read with unparsed-text() and split per line with tokenize() — no pipeline component required. TXT input that is not a delimited grid (fixed-width records, EDI, binary) is the only format that has to be disassembled to XML or JSON by a pipeline component before the map can navigate it. Every format can be written directly because method="text" lets the XSLT emit whatever character stream you build with string-join() and xsl:text.
The mapping engine includes the full set of XSLT 3.0 / XPath 3.1 functions. Below are the most commonly used ones in integration scenarios.
| Function | Description |
|---|---|
| //element | Descendant axis — selects elements at any depth. |
| path/to/node | Child axis — navigates the document tree. |
| position() | Returns the context position within a sequence. |
| last() | Returns the size of the context sequence. |
| name() | Returns the name of the context node. |
| Function | Description |
|---|---|
| count() | Returns the number of items in a sequence. |
| sum() | Returns the sum of a sequence of numbers. |
| min() / max() | Returns the minimum or maximum value in a sequence. |
| avg() | Returns the average of a sequence of numbers. |
| Function | Description |
|---|---|
| concat() | Concatenates two or more strings. |
| string-join() | Joins a sequence of strings with a separator. |
| substring() | Extracts a portion of a string. |
| replace() | Replaces substrings using a regular expression. |
| tokenize() | Splits a string into a sequence using a regex pattern. |
| matches() | Tests whether a string matches a regular expression. |
| normalize-space() | Strips leading/trailing whitespace and collapses internal whitespace. |
| upper-case() / lower-case() | Case conversion. |
| Function | Description |
|---|---|
| current-dateTime() | Returns the current date and time. |
| format-dateTime() | Formats a dateTime value using a picture string. |
| format-number() | Formats a number using a picture string. |
| number() | Converts a value to a number. |
| Function | Description |
|---|---|
| map:merge() | Merges multiple maps into one. |
| map:get() | Retrieves a value from a map by key. |
| map:keys() | Returns all keys in a map. |
| array:size() | Returns the number of members in an array. |
| array:get() | Retrieves an item from an array by position. |
| array:for-each() | Applies a function to each member of an array. |
| Function | Description |
|---|---|
| for-each() | Applies a function to every item in a sequence. |
| filter() | Returns items from a sequence that match a predicate. |
| fold-left() / fold-right() | Reduces a sequence to a single value using an accumulator. |
| sort() | Sorts a sequence using a custom comparator. |
Beyond the built-in XSLT and XPath library, maps can call user-authored custom functions — compiled C# methods deployed through the Art2link ESB UI. See the Custom functions topic for how to author and deploy them. Once a function is compiled, a map can invoke it in two ways.
The same double-curly binding used elsewhere in the map for variables, promoted properties, and other references. Typing {{ opens intellisense, which exposes available custom functions alongside the other binding sources. Calls written this way are resolved by a preprocessor pass before the XSLT runs, so the function executes outside the XSLT context — no XPath context is shared with it.
<xsl:template match="Order"> <PurchaseOrder> <Active>{{Function.fnParseBool(IsActive)}}</Active> </PurchaseOrder> </xsl:template>
Custom functions can also be called inline from XSLT as native functions. This requires declaring the urn:art2link:functions namespace on the stylesheet and excluding its prefix from the result tree:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:art="urn:art2link:functions" exclude-result-prefixes="xs art">
With the namespace declared, invoke any custom function via art:invoke, passing the function name as the first argument and the function's parameters after it. Parameters use standard XPath nomenclature, so any XPath expression — field references, casts, computed values — can be passed in:
<xsl:template match="Order"> <PurchaseOrder> <CreatedAt> <xsl:value-of select="art:invoke('fnFormatDateTime', string(CreatedAt))"/> </CreatedAt> </PurchaseOrder> </xsl:template>
Four worked examples cover the most common integration shapes. Each one starts from a single XSLT 3.0 stylesheet — no library, no preprocessor — and emits the destination format with the standard xsl:output method.
The reverse pairings (XML → CSV, CSV → XML, CSV → JSON, etc.) work the same way — pick the read pattern for the source format and the xsl:output method for the destination, and the rest is XPath.
Restructure an XML document into a different schema. This example maps a source <Order> to a canonical <PurchaseOrder> format.
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="Order"> <PurchaseOrder id="{@OrderId}"> <Buyer><xsl:value-of select="Customer/Name"/></Buyer> <Items> <xsl:for-each select="LineItems/Item"> <LineItem sku="{@Code}"> <Description><xsl:value-of select="Name"/></Description> <Qty><xsl:value-of select="Quantity"/></Qty> <Price><xsl:value-of select="UnitPrice"/></Price> </LineItem> </xsl:for-each> </Items> <Total><xsl:value-of select="sum(LineItems/Item/(Quantity * UnitPrice))"/></Total> </PurchaseOrder> </xsl:template> </xsl:stylesheet>
Convert XML input to JSON output using XSLT 3.0 maps and arrays with serialize().
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://www.w3.org/2005/xpath-functions/map"> <xsl:output method="text"/> <xsl:template match="Order"> <xsl:variable name="result" select=" map { 'orderId': string(@OrderId), 'buyer': string(Customer/Name), 'items': array { for $item in LineItems/Item return map { 'sku': string($item/@Code), 'name': string($item/Name), 'qty': number($item/Quantity), 'price': number($item/UnitPrice) } }, 'total': sum(LineItems/Item/(Quantity * UnitPrice)) }"/> <xsl:value-of select="serialize($result, map { 'method': 'json', 'indent': true() })"/> </xsl:template> </xsl:stylesheet>
Consume a JSON input and produce structured XML. The map engine can accept JSON input directly using json-doc(). Inside the XSLT, the JSON is available as an XDM map.
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- JSON input is passed as the global context item (a map) --> <xsl:template name="xsl:initial-template"> <Invoice> <InvoiceNumber><xsl:value-of select="?invoiceNo"/></InvoiceNumber> <Vendor><xsl:value-of select="?vendor?name"/></Vendor> <Lines> <xsl:for-each select="?lines?*"> <Line> <Product><xsl:value-of select="?product"/></Product> <Amount><xsl:value-of select="?qty * ?price"/></Amount> </Line> </xsl:for-each> </Lines> </Invoice> </xsl:template> </xsl:stylesheet>
Produce a flat delimited file from JSON input. This example generates pipe-delimited output with a header row — a common pattern for EDI and legacy system integrations.
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template name="xsl:initial-template"> <!-- Header --> <xsl:text>Product|Qty|Price|Total </xsl:text> <!-- Data rows --> <xsl:for-each select="?lines?*"> <xsl:value-of select="string-join( (?product, string(?qty), string(?price), string(?qty * ?price)), '|')"/> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
The XSLT 3.0 and XPath 3.1 function libraries are extensive. Reach for Custom Functions only when built-in capabilities cannot meet the requirement.
Extract common transformation patterns into named templates with <xsl:template name="..."> and call them with <xsl:call-template>.
Use the XPath 3.1 lookup operator (?key) to navigate JSON structures instead of converting JSON to XML first. It is cleaner and more performant.
Use if or choose to guard against missing or empty values. Defensive maps prevent runtime errors when input data varies.
Saving a map overwrites the previous version immediately. Deploy changes when no messages are actively being processed to avoid unpredictable behavior.
Each map should handle one transformation. For complex pipelines that involve multiple transformations, chain them through components rather than building monolithic maps.
Ready to map
Open the map editor, write your XSLT, and save. Art2link ESB compiles and deploys your transformation automatically.