For Each
You can use the For Each transform to iterate over one input array element, which can be either a simple type or a complex type repeating structure, and set the value of an output element.
Overview
The For Each transform contains a nested map. You must map the elements in the nested map, otherwise no action is executed when the transform runs.
You can configure the For Each transform to run when there are input elements that match your input selection criteria.
You can configure the For Each transform to execute once when the input array is empty by setting the Allow Empty input condition in the Filter Inputs property tab.
You can specify the indexes of the input array that participate in the For Each operation by setting the Cardinality property.
You can specify an XPath condition over the indexes that participate in the For Each operation by setting the Filter Inputs property. This condition determines which indexes are applied.
Inputs
- The For Each transform can have only one
primary input connection, and the input
must be repeatable.
- The Graphical Data Mapping editor counts the indexes from 1 to N for each processed input.
- When the input array element is empty or no inputs match a provided filter condition, the Graphical Data Mapping editor sets the index variable to 0.
- The Graphical
Data Mapping editor provides
a variable that contains the index value of each iteration
of the For Each transform. The name
is as follows: $VarName-index, where VarName is
the name of the repeating element. Note: Always use content assist to get the element name assigned by the Graphical Data Mapping editor to the repeating element.
- Extra connections to the For Each transform
must be of type Supplement. You can
use these inputs in any of the following ways:
- You might want to create a Filter Inputs expression based on the value of the input. You can use it to determine which indexes to apply as part of the transformation.
- You might want to pass an extra element into the nested transform. This input is available in the mapping of each iteration that is run by the For Each transform.
- You can configure the Cardinality property page on the For Each transform to indicate which index of an input array to iterate over.
- You can configure the Filter Inputs property page to specify the matching criteria for filtering input repeating elements.
Cardinality
The Cardinality property determines the inputs that participate in the For Each operation.
The first index element is 1.
You configure the Cardinality tab in the Properties view to specify the indexes that are processed by the transform. For more information, see Selecting the indexes of input array elements.
Filter Inputs
Configure the Filter Inputs property tab to specify an XPath expression that determines which instances of the repeating input are processed in the nested mapping. Each element of the repeatable input is tested against the condition. The transform runs for those elements that satisfy the condition.
You can use XPath, or methods from Java™ classes to define the Filter Inputs expression. You can also create a complex expression comprising XPath and Java.
You can use context assist by pressing Ctrl+Space while you construct the Filter Inputs expression. For more information, see Using content assist (Mapping syntax).
Enable Allow Empty input when the input array element is empty or no inputs match a provided filter condition, so that the transform is still entered exactly once. In this case, the primary input in the nested transform is missing, and the index variable is zero.
Outputs
The output element of a For Each transform can be a simple element, or a complex element, that can be a repeating element or a non-repeating element.
The output array size is equal to the input array size, minus any elements that are filtered out after applying the Cardinality and the Filter Inputs properties.
Variable $VarName-index
In the For Each transform, you can use the $VarName-index variable to indicate the index of the input array that the Graphical Data Mapping editor is processing.
For example, you might have an input array with 6 elements. When you set the Cardinality property of a For each transform to 1,3, you are telling the Graphical Data Mapping editor that you only want to process index 1 and index 3 of your input array. In this use case, the $VarName-index has a value of 1 for the first entry and a value of 3 for the second entry.
You can use the variable $VarName-index as part of the XPath condition that you can define to filter inputs, or as part of any transformation within the nested map that is associated to the For each transform.
The fist value of $VarName-index is 1 when your input array is not empty.
The value of $VarName-index is 0 when your input array is empty. You must enable the Allow Empty input property.
Variable $VarName-count
In the nested mapping of the For Each transform, you can use the $VarName-count variable to determine the number of times the Graphical Data Mapping editor enters the nested mapping to allow populating the output array.
The variable $VarName-count initial value is 1 . The maximum value is determined by the Cardinality and the Filter Inputs properties that are applied.
You cannot use the variable $VarName-count as part of the XPath condition that you can define to filter inputs.
You can use the variable $VarName-count as part of any transformation within the nested map that is associated to the For each transform.
- When you set the Cardinality property of a For each transform to 1:3, you are telling the Graphical Data Mapping editor that you only want to process index 1, index 2 and index 3 of your input array. In this use case, the nested map is executed 3 times and the $VarName-count variable is equal to 1 the first time is executed, 2 the second time is executed, and then 3.
- When you have a Filter expression that only matches index 1 and 3 of you input array, the $VarName-count variable is equal to 1 the first time the nested mapping is entered for the data of input index 1. The $VarName-count variable is equal to 2 on the second time the nested mapping is entered for the data of input index 3.
The value of $VarName-count is 1 when you enable Allow Empty input in a For each transform and the nested mapping is entered as a result of the empty condition.
Example 1: Filter inputs by configuring the cardinality property
In this example, the For Each transform only runs for a restricted number of elements of the repeating element. The rest of the elements in the array are not considered.
The For Each transform iterates over instances 2, 3, and 4 between the input element stock and the output element inventory.
2:4
<?xml version="1.0" encoding="UTF-8"?>
<tns:Input xmlns:tns="http://www.example.org/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/schema foo.xsd ">
<tns:stock>
<tns:name>apple</tns:name>
<tns:number>1</tns:number>
<tns:description>fruit</tns:description>
</tns:stock>
<tns:stock>
<tns:name>banana</tns:name>
<tns:number>2</tns:number>
<tns:description>fruit</tns:description>
</tns:stock>
<tns:stock>
<tns:name>cap</tns:name>
<tns:number>3</tns:number>
<tns:description>accessory</tns:description>
</tns:stock>
<tns:stock>
<tns:name>door</tns:name>
<tns:number>4</tns:number>
<tns:description>furniture</tns:description>
</tns:stock>
<tns:stock>
<tns:name>elephant</tns:name>
<tns:number>5</tns:number>
<tns:description>animal</tns:description>
</tns:stock>
</tns:Input>
you get the following output:
<?xml version="1.0" encoding="UTF-8"?><io:Output xmlns:io="http://www.example.org/schema">
<io:inventory>
<io:name>banana</io:name>
<io:number>2</io:number>
<io:description>fruit</io:description>
<io:index>1</io:index>
<io:count>1</io:count>
</io:inventory>
<io:inventory>
<io:name>cap</io:name>
<io:number>3</io:number>
<io:description>accessory</io:description>
<io:index>2</io:index>
<io:count>2</io:count>
</io:inventory>
<io:inventory>
<io:name>door</io:name>
<io:number>4</io:number>
<io:description>furniture</io:description>
<io:index>3</io:index>
<io:count>3</io:count>
</io:inventory>
</io:Output>
Example 2: Filter inputs by configuring the Filter Inputs property
In this example, the For Each transform only runs for a restricted number of elements of the repeating element. The rest of the elements in the array are not considered. The For Each transform iterates over instances where the name of a stock item is a string with more than 4 characters.
In the For Each transform, the input element is stock and the output element is inventory.
The For Each transform iterates over instances where the value of stock.name is a string with more than 4 characters.
fn:string-length($stock/io:name) > 4
<?xml version="1.0" encoding="UTF-8"?>
<tns:Input xmlns:tns="http://www.example.org/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/schema foo.xsd ">
<tns:stock>
<tns:name>apple</tns:name>
<tns:number>1</tns:number>
<tns:description>fruit</tns:description>
</tns:stock>
<tns:stock>
<tns:name>banana</tns:name>
<tns:number>2</tns:number>
<tns:description>fruit</tns:description>
</tns:stock>
<tns:stock>
<tns:name>cap</tns:name>
<tns:number>3</tns:number>
<tns:description>accessory</tns:description>
</tns:stock>
<tns:stock>
<tns:name>door</tns:name>
<tns:number>4</tns:number>
<tns:description>furniture</tns:description>
</tns:stock>
<tns:stock>
<tns:name>elephant</tns:name>
<tns:number>5</tns:number>
<tns:description>animal</tns:description>
</tns:stock>
<tns:stock>
<tns:name>flower</tns:name>
<tns:number>6</tns:number>
<tns:description>decoration</tns:description>
</tns:stock>
<tns:stock>
<tns:name>gold</tns:name>
<tns:number>7</tns:number>
<tns:description>money</tns:description>
</tns:stock>
<tns:stock>
<tns:name>honey</tns:name>
<tns:number>8</tns:number>
<tns:description>food</tns:description>
</tns:stock>
<tns:stock>
<tns:name>igloo</tns:name>
<tns:number>9</tns:number>
<tns:description>cold</tns:description>
</tns:stock>
<tns:stock>
<tns:name>jeep</tns:name>
<tns:number>10</tns:number>
<tns:description>car</tns:description>
</tns:stock>
</tns:Input>
you get the following output:
<?xml version="1.0" encoding="UTF-8"?><io:Output xmlns:io="http://www.example.org/schema">
<io:inventory>
<io:name>apple</io:name>
<io:number>1</io:number>
<io:description>fruit</io:description>
<io:index>0</io:index>
<io:count>1</io:count>
</io:inventory>
<io:inventory>
<io:name>banana</io:name>
<io:number>2</io:number>
<io:description>fruit</io:description>
<io:index>1</io:index>
<io:count>1</io:count>
</io:inventory>
<io:inventory>
<io:name>elephant</io:name>
<io:number>5</io:number>
<io:description>animal</io:description>
<io:index>4</io:index>
<io:count>2</io:count>
</io:inventory>
<io:inventory>
<io:name>flower</io:name>
<io:number>6</io:number>
<io:description>decoration</io:description>
<io:index>5</io:index>
<io:count>3</io:count>
</io:inventory>
<io:inventory>
<io:name>honey</io:name>
<io:number>8</io:number>
<io:description>food</io:description>
<io:index>7</io:index>
<io:count>4</io:count>
</io:inventory>
<io:inventory>
<io:name>igloo</io:name>
<io:number>9</io:number>
<io:description>cold</io:description>
<io:index>8</io:index>
<io:count>5</io:count>
</io:inventory>
</io:Output>
Example 3: Filter inputs by configuring the Cardinality and the Filter Inputs properties
In this example, the For Each transform only runs for the first three elements of the repeating element. The rest of the elements in the array are not considered. For each element in the array, if the first 4 characters of the element B start with UK01, then the transformation inside the nested map is executed.
Inside the nested map, the fn:concat transform calculates the value of element e based on the input element index and the input element D.
<?xml version="1.0" encoding="UTF-8"?>
<NewElement>
<A>A1</A>
<C>Field_1</C>
<C>Field_2</C>
<C>Field_3</C>
<D>1000</D>
<E>CUSTOMER_AREA1</E>
</NewElement>
you get the following output:
<NewElement1>
<c>
<d/>
<e>0_1000</e>
</c>
</NewElement1>
<?xml version="1.0" encoding="UTF-8"?>
<NewElement>
<A>A1</A>
<B>UK011234567</B>
<B>B2</B>
<B>UK019999999</B>
<B>UK01xxxxxxx</B>
<C>Field_1</C>
<C>Field_2</C>
<C>Field_3</C>
<D>1000</D>
<E>CUSTOMER_AREA1</E>
</NewElement>
you get the following output:
<NewElement1>
<c>
<d>UK011234567</d>
<e>1_1000</e>
</c>
<c>
<d>UK019999999</d>
<e>3_1000</e>
</c>
</NewElement1>