Read Modes
Read modes define how content is extracted from the source message in a mapping rule. They control whether you read a single value, iterate over repetitions, concatenate multiple selectors, or use fixed literal values.
Overview
MyFormat supports five read modes, each designed for different data extraction patterns:
| Read Mode | Purpose | Output | Common Use Cases |
|---|---|---|---|
| SINGLE | Read one value | Single string | Default mode for most field mappings |
| LITERAL | Use fixed value | Single string | Constants, defaults, fixed text |
| CONCAT | Combine multiple selectors | Single string | Building composite values from multiple fields |
| FOREACH | Iterate over repetitions | Multiple values | Processing repeating elements, creating multiple target elements |
| FOREACH_CONCAT | Aggregate repetitions | Single string | Combining repetitive data into one field |
When to use each mode:
- Use SINGLE for straightforward field-to-field mappings
- Use LITERAL when you need to inject constant values or templates
- Use CONCAT to build composite values from multiple source fields
- Use FOREACH when you need to create multiple target elements from repetitive source data
- Use FOREACH_CONCAT when you need to aggregate repetitive source data into a single target field
Default Behavior
If no read mode is specified, SINGLE is used by default.
SINGLE Mode
The SINGLE read mode is the default mode that reads a single value from the source message using the provided selector.
Syntax:
Example 1: Basic field mapping
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Read single value from XML and write to CSV column
table.add(new MappingRule("/order/amount", "0"));
// Input XML: <order><amount>1500.00</amount></order>
// Output CSV: 1500.00
Example 2: With transformation
MappingTable table = new MappingTable(FileFormat.MT, FileFormat.XML);
// Read field 32A amount and convert to decimal format
MappingRule rule = new MappingRule("32A/Amount", "/document/amount");
rule.addTransformation(new Transformation(Key.formatDecimal, "0.00"));
table.add(rule);
// Input MT: :32A:231215EUR1500,
// Output XML: <document><amount>1500.00</amount></document>
LITERAL Mode
The LITERAL read mode allows you to specify a fixed value instead of reading from the source message. This is useful for injecting constants, defaults, or fixed text into the target message.
Syntax:
Syntax Variations
Literals can be defined using the LITERAL() function or simply with quoted text "value".
Example 1: Fixed constant
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Write fixed value to output
table.add(new MappingRule("LITERAL(USD)", "0"));
// Alternative: table.add(new MappingRule("\"USD\"", "0"));
// Output CSV: USD
Example 2: Default values when source is missing
MappingTable table = new MappingTable(FileFormat.JSON, FileFormat.XML);
// Try to read from source, use literal default if missing
table.add(new MappingRule("data.country", "/document/country"));
table.add(new MappingRule("LITERAL(UNKNOWN)", "/document/country", WriteMode.UPDATE));
// If data.country exists: uses that value
// If data.country missing: falls back to "UNKNOWN"
CONCAT Mode
The CONCAT read mode reads multiple selectors and concatenates their values into a single string. It can combine source fields with literal values to build composite content.
Syntax:
Example 1: Combining multiple fields
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Combine first name and last name with space separator
table.add(new MappingRule("CONCAT(/person/firstName, \" \", /person/lastName)", "0"));
// Input XML: <person><firstName>John</firstName><lastName>Doe</lastName></person>
// Output CSV: John Doe
Example 2: Building composite identifiers
MappingTable table = new MappingTable(FileFormat.MT, FileFormat.CSV);
// Build reference from multiple MT fields with separators
table.add(new MappingRule("CONCAT(20, \"|\", 21, \"|\", 59/1)", "0"));
// Input MT with field 20=REF001, field 21=INV2023, field 59 account=ACC123
// Output CSV: REF001|INV2023|ACC123
Example 3: Adding prefixes/suffixes
MappingTable table = new MappingTable(FileFormat.JSON, FileFormat.XML);
// Add currency prefix to amount
table.add(new MappingRule("CONCAT(\"USD \", transaction.amount)", "/document/formattedAmount"));
// Input JSON: {"transaction": {"amount": "1500.00"}}
// Output XML: <document><formattedAmount>USD 1500.00</formattedAmount></document>
Example 4: Complex composition
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Build structured reference with date, type, and ID
table.add(new MappingRule(
"CONCAT(/doc/date, \"-\", /doc/type, \"-\", /doc/id)", "0"));
// Input XML: <doc><date>2025-12-30</date><type>INV</type><id>12345</id></doc>
// Output CSV: 2025-12-30-INV-12345
FOREACH Mode
The FOREACH read mode iterates over multiple repeating elements in the source message and processes each one individually. For each iteration, the target is written separately, creating multiple target elements.
Syntax:
The two-parameter form allows you to specify:
- nodeSelector: Identifies the repeating elements to iterate over
- valueSelector: Extracts specific content from each element (can be a sub-path or literal)
Example 1: Basic iteration
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Iterate over each item and write to separate CSV rows
table.add(new MappingRule("FOREACH(/order/items/item)", "0"));
// Input XML:
// <order>
// <items>
// <item>Widget</item>
// <item>Gadget</item>
// <item>Tool</item>
// </items>
// </order>
// Output CSV:
// Widget
// Gadget
// Tool
Example 2: Two-parameter FOREACH with sub-path
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.JSON);
// Iterate over transactions, extract specific field
table.add(new MappingRule("FOREACH(/report/transactions/tx, ./amount)", "amounts[{n}]"));
// Input XML:
// <report>
// <transactions>
// <tx><amount>100</amount><desc>Payment</desc></tx>
// <tx><amount>200</amount><desc>Refund</desc></tx>
// </transactions>
// </report>
// Output JSON: {"amounts": ["100", "200"]}
Example 3: FOREACH with transformations
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Iterate and apply transformation to each element
MappingRule rule = new MappingRule("FOREACH(/data/codes/code)", "0");
rule.addTransformation(new Transformation(Key.upperCase));
table.add(rule);
// Input XML: <data><codes><code>abc</code><code>def</code><code>xyz</code></codes></data>
// Output CSV:
// ABC
// DEF
// XYZ
Example 4: Using literals in FOREACH
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Iterate over items but write the same literal value each time
table.add(new MappingRule("FOREACH(/order/items/item, \"ITEM\")", "1"));
// Input XML with 3 items creates 3 rows each with "ITEM" in column 1
Example 5: FOREACH with runtime variables in transformations
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Extract prefix from header
table.add(new MappingRule("/msg/header/code", "$prefix", WriteMode.VARIABLE));
// Apply dynamic prefix to each item
MappingRule rule = new MappingRule("FOREACH(/msg/items/item)", "0");
rule.addTransformation(new Transformation(Key.prepend, "[$prefix] "));
table.add(rule);
// Input XML: <msg><header><code>TYPE-A</code></header><items><item>X</item><item>Y</item><item>Z</item></items></msg>
// Output CSV:
// [TYPE-A] X
// [TYPE-A] Y
// [TYPE-A] Z
FOREACH_CONCAT Mode
FOREACH_CONCAT is a read mode that iterates over multiple repeating elements and concatenates their values into a single string with a specified separator. Unlike FOREACH which creates multiple target elements, FOREACH_CONCAT produces one aggregated result.
Syntax:
Parameters:
| Parameter | Required | Description |
|---|---|---|
selector |
Yes | Path to the repeating elements to aggregate |
separator |
Yes | String to insert between values (quoted) |
includeNulls |
No | true or false (default: false). When true, null values appear as empty strings in the result |
Key characteristics:
- Single output: All matched values are combined into one string
- Order preserved: Values appear in document order
- Transformations: Applied to the final concatenated result, not individual values
- Variable support: Result can be stored in a variable with
WriteMode.VARIABLE - Validation: Parameters are validated at compile time
Example 1: Basic aggregation from XML
Concatenate all item names from a repeating XML element:
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
table.add(new MappingRule("FOREACH_CONCAT(/order/items/item, \"|\")", "0"));
// Input XML:
// <order>
// <items>
// <item>Widget</item>
// <item>Gadget</item>
// <item>Tool</item>
// </items>
// </order>
// Output CSV: Widget|Gadget|Tool
Example 2: Store aggregation in variable for reuse
Aggregate values once and use them multiple times:
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// Aggregate into variable
table.add(new MappingRule("FOREACH_CONCAT(/invoice/lines/line/amount, \"+\")",
"$allAmounts", WriteMode.VARIABLE));
// Use in multiple places
table.add(new MappingRule("$allAmounts", "0"));
table.add(new MappingRule("CONCAT(\"Total: \", $allAmounts)", "1"));
// Input: <invoice><lines><line><amount>100</amount></line><line><amount>200</amount></line></lines></invoice>
// Output column 0: 100+200
// Output column 1: Total: 100+200
Example 3: Apply transformation to aggregated result
Transform the concatenated string (transformation applies to final result, not individual values):
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
MappingRule rule = new MappingRule("FOREACH_CONCAT(/data/names/name, \", \")", "0");
rule.addTransformation(new Transformation(Key.upperCase));
table.add(rule);
// Input: <data><names><name>alice</name><name>bob</name></names></data>
// Output: ALICE, BOB
Example 4: Handling null values
Control how missing values are handled with the includeNulls parameter:
MappingTable table = new MappingTable(FileFormat.XML, FileFormat.CSV);
// With includeNulls=false (default): null values are skipped
table.add(new MappingRule("FOREACH_CONCAT(/data/items/item, \"|\")", "0"));
// Values [A, null, C] → "A|C"
// With includeNulls=true: null values appear as empty strings
table.add(new MappingRule("FOREACH_CONCAT(/data/items/item, \"|\", true)", "1"));
// Values [A, null, C] → "A||C"
Comparison: FOREACH vs FOREACH_CONCAT
| Feature | FOREACH | FOREACH_CONCAT |
|---|---|---|
| Output | Multiple values (one per iteration) | Single concatenated string |
| Target creation | Creates multiple target elements | Creates one target element |
| Use with VARIABLE | Not supported | Supported |
| Transformations | Applied per element | Applied to final string |
| Use case | Copy repetitions | Aggregate repetitions |
When to use FOREACH: - You need to create multiple target elements - Each source element should be independently transformed - You're mapping to repeating structures in the target
When to use FOREACH_CONCAT: - You need to combine multiple values into a single field - The target format doesn't support repetitions - You're building comma-separated lists or similar aggregations
Read Mode Comparison Table
| Feature | SINGLE | LITERAL | CONCAT | FOREACH | FOREACH_CONCAT |
|---|---|---|---|---|---|
| Input | One selector | Fixed value | Multiple selectors | Repeating elements | Repeating elements |
| Output | One value | One value | One value | Multiple values | One value |
| Selectors | 1 | 0 | 2+ | 1-2 | 1 |
| Iterations | No | No | No | Yes | Yes |
| Literal support | No | Yes | Yes (in parameters) | Yes (as value) | No |
| Variable support | Source + Transform | Transform | Source + Transform | Transform only | Full support |
| Target creation | One element | One element | One element | Multiple elements | One element |