<foreach>
This looping statement processes any children statements in either a repeated loop or in parallel for each node in a node set. The node set is defined in an XPath expression.
You can use most EMML statements within <foreach>. You can also use <break> within this statement to forceably stop loop processing.
For examples, see <foreach> as Sequential Loops, <foreach> as Parallel Loops for All Nodes or <foreach> as Parallel Loops for Any One Node.
| Can Contain | ( Statements Group | ( Variables Group ) | ( ( macro:custom-macro-name | any element in a non-EMML namespace )* ) | ( break ) | ( variables ) | fuse )+ |
| Allowed In | mashup, else, elseif, for, foreach, if, macro, operation, sequence, while, |
Attributes
| Name | Required | Description |
|---|---|---|
| variable | yes | The name for the variable to hold each 'item' for this looping statement. The scope for this variable is limited to the <foreach> loop. |
| items | yes | An XPath 2.0 expression that defines the set of nodes (or sequence) to loop through. The length of this set defines the limit for looping and typically also defines a context for relative expressions used in statements or content within the <foreach> loop. |
| parallel | Determines whether each loop is processed sequentially (the default) or concurrently (parallel="yes"). Valid values include:
|
|
| tasks | Determines how many loops are processed when loops are processed concurrently (parallel="yes"). This can be all loops or any one loop (the first loop to complete ends all loop processing). Valid values include:
|
|
| merge | Determines how the results from multiple concurrent loops are fused into one or more variables:
This attribute is only meaningful when parallel="yes" and tasks="invokeall". The order in which concurrent loops are assigned or fused in variables is not determinant. |
<fuse>
Optionally, defines the literal XML structure and specific nodes or computations to include in the result when loops are processed concurrently for <foreach>. If this is omitted, loops are processed concurrently, but the results of each loop are not bound to any variables.
How results for each loop are fused together and assigned to variable(s) depends on the value of the merge attribute in <foreach>. The <fuse> outputvariable attribute identifies the variable for the fused result, and if applicable the base name for variable names for the results of each loop.
Note: The structure inside <fuse> must be well-formed, enclosed in a root node. Elements in the structure should use a namespace, so that they are clearly separated from EMML markup.
| Can Contain | Can contain text and any well-formed literal XML. |
Attributes
| Name | Required | Description |
|---|---|---|
| outputvariable | yes | The required variable to accept the output of this statement. |
<foreach> Examples
<foreach> as Sequential Loops
For sequential loops, you must set two attributes: items and variable. You define the set of nodes to iterate through in the items attribute with an XPath expression. You can use predicates to control which nodes are selected, or use XPath functions as needed.
You must also identify a variable to hold each iteration of the set of nodes. XPath expressions for statements within <foreach> use this iteration variable to access data for the current node.
Note: the iteration variable is declared implicitly and has a local scope within <foreach> only.
The following example iterates through employee nodes. Within the loop, it uses an <if> statement to test the current employee node before adding content to a variable using <appendresult>.
<foreach variable="$staff" items="$employees_Array//employee">
<if condition="$staff/department = 'Accounting' and
$staff/years > 5">
<appendresult outputvariable="$employeesResult">
<res:vested>
<res:name>{$staff/name)}</res:name>
<res:vestedYears>{$staff/years - 5}</res:vestedYears>
</res:vested>
</if>
</appendResult>
</for>
<foreach> as Parallel Loops for All Nodes
With concurrent loop processing, you define the iterations and variables just as you do for sequential loop processing. You set parallel="yes" and use the remaining attributes, plus a <fuse> child, to define how the concurrent loops are processed and how loop results are merged.
When concurrent processing is used, each node identified in the items attribute spawns a new concurrent task. Set tasks="invokeall" to ensure that each loop completes processing.
<foreach variable="$url" items="$urls/url/string()" parallel="yes"
tasks="invokeall" merge="true">
<!-- invoke several web sites in parallel -->
<directinvoke endpoint="$url" outputvariable="$tempResult"/>
<!-- merge all results and construct final result -->
<fuse outputvariable="$summary">
<feedsummary title="{$tempResult/rss/channel/title}" url="{$url}">
{$tempResult/rss/channel/item[1]/title}
</feedsummary>
<fuse>
</foreach>
With concurrent processing, you must construct the output of <foreach> with a <fuse> child. You define the literal XML for the result within the body of <fuse> and use static values or Dynamic Mashup Expressions to define how data is assigned to the result.
The outputvariable for <fuse> combined with the merge attribute on <foreach> determines what variable(s) hold the result(s) of the concurrent loops. To aggregate all the loop results in a single variable, set merge to true as shown in this example.
Note: the order in which loop results are added to the combined, final result is not determinant.
The final result, assigned to the summary variable, for the previous concurrent <foreach> example would look something like this:
<taskresults>
<taskresult>
<feedsummary title="Yahoo! Finance"
url="http://finance.yahoo.com/rss/headlines">
Facebooks Boots CFO Yu, Here Comes the IPO</feedsummary>
</taskresult>
<taskresult>
<feedsummary title="Business and Financial News - CNNMoney.com"
url="http://rss.cnn.com/rss/money_topstories.rss">
Auto bankruptcy, What it means</feedsummary>
</taskresult>
...
</taskresults>
Each loop creates a <taskresult> element in which the <fuse> structure appears.
If you set the merge attribute to false, the results of each loop is assigned to its own variable. The outputvariable value for <fuse> is used to create individual variables as output-variable-name1, output-variable-name2 and so on.
Note: the order in which loop results are assigned to individual, final result is not determinant.
The combined outputvariable contains references to each individual loop result. For the previous example, the final result assigned to the summary variable would look something like this:
<taskresults> <taskresult>$summary1</taskresult> <taskresult>$summary2</taskresult> ... </taskresults>
<foreach> as Parallel Loops for Any One Node
With concurrent loops, you can also stop all further loop processing once one loop completes using tasks set to invokeany. The first loop that completes stops all other loops.
<foreach variable="$url" items="$urls/url/string()" parallel="yes"
tasks="invokeany" merge="true">
<!-- invoke several web sites in parallel, stop when one returns -->
<directinvoke endpoint="$url" outputvariable="$tempResult"/>
<!-- construct final result -->
<fuse outputvariable="$summary">
<feedsummary title="{$tempResult/rss/channel/title}" url="{$url}">
{$tempResult/rss/channel/item[1]/title}
</feedsummary>
<fuse>
</foreach>
You must still define the structure of the result using a <fuse> child and specifying the variable to hold the result. With this example, the summary variable might look something like this:
<taskresults>
<taskresult>
<feedsummary title="Business and Financial News - CNNMoney.com"
url="http://rss.cnn.com/rss/money_topstories.rss">
Auto bankruptcy, What it means</feedsummary>
</taskresult>
</taskresults>
Enterprise Mashup Markup Language (EMML) Documentation is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
