Table of Contents | ||||||
---|---|---|---|---|---|---|
|
Description
The for each statement enumerates the elements of a collection, executing an embedded statement for each element of the collection.
...
Examples of each of these variations will be provided in the next section.
Tag | Optional/Required | Description |
---|---|---|
For | Required | Loop is implemented as a generic FacetScript construct and NOT specific to any facet so you can use it anywhere FacetScript can be used. |
Each= | Required | "each" defines loop variable[s] name[s]
|
in= | Required | “in” specifies the source key to iterate over |
from= | Optional | “from” specifies the source key prefix. Default value is “$Response.Message.Value”. That is, loop will [virtually] concatenate from+in to obtain actual key and some optimizations. |
using= | Optional | “using” specifies the data store where loop variable[s] will be allocated. Default value is “$LocalData”. That is, since loop body is a scope, a new loop variable[s] will be created for each loop iteration. If you need to pass/keep some data between iteration then you can use a different store (e.g. $ProcessData, $ContextData etc.), combination of stores or wrap loop in another scope and initialize your data there |
Tips and Caveats
...
We are manipulating structures, so the general idea is to assign a STRUCTURE to a loop variable so you can manipulate the CONTENT of the structure through the variable. That is, <For each=”val” in=”Find.Result.VendorInfo.VendorTitle.Value”> will allow you to do if/select on the val, but will NOT allow you to change the VendorTitle, only the value of loop variable which is a simple value in this case.
Caveat Example
...
language | xml |
---|---|
theme | Eclipse |
title | Assign STRUCTURE |
...
FAQ
In this section let's try to understand For Each in a FAQ style of documentation. For all questions below: Let's take VendorInfo to contain three Vendors
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<Find Status="Success" Format="all">
<Result>
<VendorInfo QName="Atomiton.Sensors.VendorInfo">
<vendorId>vendorA</vendorId>
<vendorCity Value="Calgary" Known="Calgary" Version="1" Timestamp="1489093271736" DateTime="2017-03-09 13:01:11.736" QName="Atomiton.Sensors.VendorInfo.vendorCity" FName="vendorCity"/>
<vendorName Value="Phidget" Known="Phidget" Version="1" Timestamp="1489093271734" DateTime="2017-03-09 13:01:11.734" QName="Atomiton.Sensors.VendorInfo.vendorName" FName="vendorName"/>
</VendorInfo>
</Result>
<Result>
<VendorInfo QName="Atomiton.Sensors.VendorInfo">
<vendorId>vendorB</vendorId>
<vendorCity Value="Calgary" Known="Calgary" Version="1" Timestamp="1489093277295" DateTime="2017-03-09 13:01:17.295" QName="Atomiton.Sensors.VendorInfo.vendorCity" FName="vendorCity"/>
<vendorName Value="Phidget" Known="Phidget" Version="1" Timestamp="1489093277294" DateTime="2017-03-09 13:01:17.294" QName="Atomiton.Sensors.VendorInfo.vendorName" FName="vendorName"/>
</VendorInfo>
</Result>
<Result>
<VendorInfo QName="Atomiton.Sensors.VendorInfo">
<vendorId>vendorC</vendorId>
<vendorCity Value="Calgary" Known="Calgary" Version="1" Timestamp="1489093282311" DateTime="2017-03-09 13:01:22.311" QName="Atomiton.Sensors.VendorInfo.vendorCity" FName="vendorCity"/>
<vendorName Value="Phidget" Known="Phidget" Version="1" Timestamp="1489093282311" DateTime="2017-03-09 13:01:22.311" QName="Atomiton.Sensors.VendorInfo.vendorName" FName="vendorName"/>
</VendorInfo>
</Result>
</Find> |
# | Question | Explaination | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
1 | How do I determine the number of iterations of a for loop?
| Number of iterations is always determined by the Number of Containers from the specified source and Each is a single variable format. Example: Here Source is: $Response.Message.Value.Find
| |||||||||
2 | What happens if I do not specify value in Each i.e Each="k:v"
|
| |||||||||
3 | What happens if we provide only one variable in key/value format i.e either k: or :v
|
|
Tips and Caveats
- If you use $LocalData your loop variables will NOT be available after the loop (they are defined in the scope of iteration only)
We are manipulating structures, so the general idea is to assign a STRUCTURE to a loop variable so you can manipulate the CONTENT of the structure through the variable. That is, <For each=”val” in=”Find.Result.VendorInfo.VendorTitle.Value”> will allow you to do if/select on the val, but will NOT allow you to change the VendorTitle, only the value of loop variable which is a simple value in this case.
Caveat Example
Code Block language xml theme Eclipse title Assign STRUCTURE <Query> <Find format="Version"> <VendorInfo> <vendorTitle eq="Sensor Provider"/> </VendorInfo> </Find> <For each="val" in="Find.Result.VendorInfo.VendorTitle.Value"> <IF Condition="/'[:$LocalData.val:]' eq 'Sensor Provider'"> <!-- This is simply to show how if can be used --> <Log Message="Found Sensor Provider"/> </IF> <SetLocalData Key="val" Value="Actuator Provider"/> <!-- This will change <Value> only --> </For> <!-- Do an Update --> <Update> <From>Result</From> <Include>$Response.Message.Value.Find</Include> </Update> </Query> <!-- Result is.. --> <Find Status="Success" Format="version"> <Result> <VendorInfo> <VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE</VendorSysId> <vendorTitle Value="Sensor Provider" Version="1"/> <vendorName Value="Libelium" Version="2"/> </VendorInfo> </Result> <Result> <VendorInfo> <VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId> <vendorTitle Value="Sensor Provider" Version="1"/> <vendorName Value="Phidget" Version="1"/> </VendorInfo> </Result> <Result> <VendorInfo> <VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId> <vendorTitle Value="Sensor Provider" Version="1"/> <vendorName Value="Phidget3" Version="1"/> </VendorInfo> </Result> </Find> <Update Status="Success" Format="version"> <VendorInfo> <VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE</VendorSysId> <vendorName Status="Success_NoAction:2:1460829683086;" Value="Libelium" Version="2"/> <vendorTitle Status="Success_NoAction:1:1460757657344;" Value="Sensor Provider" Version="1"/> <!-- Note there is no change in value --> </VendorInfo> <VendorInfo> <VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId> <vendorName Status="Success_NoAction:1:1460757648025;" Value="Phidget" Version="1"/> <vendorTitle Status="Success_NoAction:1:1460757648027;" Value="Sensor Provider" Version="1"/> <!-- Note there is no change in value --> </VendorInfo> <VendorInfo> <VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId> <vendorName Status="Success_NoAction:1:1460757661429;" Value="Phidget3" Version="1"/> <vendorTitle Status="Success_NoAction:1:1460757661429;" Value="Sensor Provider" Version="1"/> <!-- Note there is no change in value --> </VendorInfo> </Update>
Correct way is to point val → Find.Result.VendorInfo
Code Block language xml theme Eclipse title Assign to STRUCTURE <Query> <Find format="Version"> <VendorInfo> <vendorTitle eq="Sensor Provider"/> </VendorInfo> </Result>Find> <Result><For each="val" in="Find.Result.VendorInfo"> <VendorInfo> <IF Condition="/'[:$LocalData.val.vendorTitle.Value:]' eq 'Sensor <VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId>Provider'"> <vendorTitle<Log ValueMessage="Found Sensor Provider" Version="1"/> </IF> <vendorName <SetLocalData ValueKey="Phidgetval.vendorTitle.Value" VersionValue="1Actuator Provider"/> </For> </VendorInfo>!-- Do an </Result> Update --> <Result> <Update> <VendorInfo> <From> <VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId> Result </From> <vendorTitle Value="Sensor Provider" Version="1"/> <Include> <vendorName Value="Phidget3" Version="1"/>$Response.Message.Value.Find </VendorInfo>Include> </Result>Update> </Find> <UpdateQuery> <!-- Result is --> <Find Status="Success" Format="version">version"> <Result> <VendorInfo> <VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE</VendorSysId> <vendorName<vendorTitle StatusVersion="Success_NoAction:2:1460829683086;3" Value="Libelium"Actuator Version=Provider"2"/> <vendorTitle Status="Success_NoAction:1:1460757657344;" <vendorName Value="Sensor ProviderLibelium" Version="12"/> <!-- Note there is</VendorInfo> no change in</Result> value --> <Result> </VendorInfo> <VendorInfo> <VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId> <vendorName <vendorTitle StatusVersion="Success_NoAction:1:1460757648025;3" Value="Phidget" Version="1Actuator Provider"/> <vendorTitle Status="Success_NoAction:1:1460757648027;" <vendorName Value="Sensor ProviderPhidget" Version="1"/> <!-- Note there is</VendorInfo> no change in</Result> value --> <Result> </VendorInfo> <VendorInfo> <VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId> <vendorName <vendorTitle StatusVersion="Success_NoAction:1:1460757661429;3" Value="Phidget3" Version="1Actuator Provider"/> <vendorTitle Status="Success_NoAction:1:1460757661429;" <vendorName Value="Sensor ProviderPhidget3" Version="1"/> <!-- Note there is no</VendorInfo> change in value --> </VendorInfo>Result> </Update>
Correct way is to point val → Find.Result.VendorInfo
Code Block language xml theme Eclipse title Assign to STRUCTURE <Query> <Find format="Version"> Find> <Update Status="Success" Format="version"> <VendorInfo> <VendorInfo> <VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE</VendorSysId> <vendorTitle eq="Sensor Provider<vendorName Status="Success_NoAction:2:1460829683086;" Value="Libelium" Version="2"/> </VendorInfo> </Find> <For each="val" in="Find.Result.VendorInfo"> <IF Condition="/'[:$LocalData.val.vendorTitle.Value:]' eq 'Sensor Provider'"> <vendorTitle Status="Success=Updated:4:1460935288963;" Value="Actuator Provider" Version="4"/> <!-- Title is updated --> </VendorInfo> <VendorInfo> <VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId> <Log<vendorName Message="Found Sensor ProviderStatus="Success_NoAction:1:1460757648025;" Value="Phidget" Version="1"/> </IF> <SetLocalData Key="val.vendorTitle.Value<vendorTitle Status="Success=Updated:4:1460935288964;" Value="Actuator Provider"/> </For> Version="4"/> <!-- DoTitle anis Updateupdated --> <Update> <From> Result </From>VendorInfo> <VendorInfo> <Include> <VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId> $Response.Message.Value.Find </Include> </Update> </Query>
Examples
...
language | xml |
---|---|
theme | Eclipse |
title | If then else with constant expression |
...
<vendorName Status="Success_NoAction:1:1460757661429;" Value="Phidget3" Version="1"/> <vendorTitle Status="Success=Updated:4:1460935288964;" Value="Actuator Provider" Version="4"/> <!-- Title is updated --> </VendorInfo> </Update>
Examples
Code Block | ||||||
---|---|---|---|---|---|---|
Code Block | ||||||
| ||||||
| ||||||
<if condition="true">
<then>
<Log Message="I am in true block!"/>
</then>
<else>
<Log Message='I am in false block!"/>
</else> | ||||||
| ||||||
<Query> <Find format="Version"> <VendorInfo> <vendorSysId ne=""/> </VendorInfo> </Find> <For each="val" in="Find.Result.VendorInfo"> <!-- Note that since From is not specified: It will default to $Response.Message.Value --> <Log Message="IVendor amName in false block!"/> </else> </if> </Query> |
Special Tags when used with TQL
There are two ways in which XPath Expressions can be used as part of boolean expression.
...
is: [:$LocalData.val.vendorName.Value:]"/>
</For>
</Query> |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<if condition="$ContextData/projectKey eq '[:RuntimeParams.ProjectSettings_ProjectKey:]'">
<then>
<Log Message="I am in true block!"/>
</then>
<else>
<Log Message="I am in false block!"/>
</else>
</if> |
b) Whole boolean expression itself can be XPath expression. This is done using by starting the expression with "/"
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<if condition="/'[:$Macro.Argument.StopWid:]' != '' and '[:$Macro.Argument.StopTarget:]' != ''">
<then>
<Log Message="I am in true block!"/>
</then>
<else>
<Log Message="I am in false block!"/>
</else>
</if> |
Using Multiple operands
...
| |
<SetContextData Key="Atomiton.FS.Features.1" Value="Conditional Statements"/>
<SetContextData Key="Atomiton.FS.Features.2" Value="For Statements"/>
<SetContextData Key="Atomiton.FS.Features.3" Value="Case Statements"/>
<!-- Let's iterate over ContextData -->
<For each="val" In="Atomiton.FS.Features" From="$ContextData">
<Log Message="...[:$LocalData.val:]"/>
</For> |
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| <if condition="[:$Macro.Argument.RouteLoc:]/not(boolean(Site)) and '[:$Macro.Argument.SelfWid:]' != '' and '[:$Macro.Argument.StopTarget:]' != ''">
<then>
<Log Message="I am in true block!"/>
</then>
<else>
| |||||||
<SetContextData Key="Atomiton.FS.Features.1" Value="Conditional Statements"/> <SetContextData Key="Atomiton.FS.Features.2" Value="For Statements"/> <SetContextData Key="Atomiton.FS.Features.3" Value="Case Statements"/> <!-- Let's iterate over ContextData and use ProcessData to store iterated data --> <For each="val" in="Atomiton.FS.Features" from="$ContextData" using="$ProcessData"> <Log Message="I am in false block!within loop...[:$ProcessData.val:]"/> </else> </if> <if condition="/'[:$Macro.Argument.SiteCur:]' = '[:CONFIG.CompanyId:]' or [:$ProcessData.$BTV.Worker.SlackCounter:] >= [:CONFIG.RULES.MaxWorkerSlack:] orFor> |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<For each="light" in="Message.Value.lights" from="$ContextData.response"> <SetContextData key="state"> <value> [:$LocalData.Rand:] > [:$ProcessData.$BTV.Worker.SlackTendency:]"> <then><intensityLevel>-1</intensityLevel> <Log Message="I am in true block!"/> <<powerConsumption>-1</then>powerConsumption> <else> <Log Message="I am in false block!"/> </else> </if> |
Nested If Statements
Note that if you do not have else, usage of <then> is optional.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<if condition="/'[:$Macro.Argument.StopWid:]' != '' and '[:$Macro.Argument.StopTarget:]' != ''"> <reliability>0</reliability> </value> <Log Message="I am in true block!"/></SetContextData> <if condition="/'[:$Macro$LocalData.Argument.SiteCur:]' = '[:CONFIG.CompanyId:]' orlight.location/count(latitude) gt 0:]"> <then> [:$ProcessData.$BTV.Worker.SlackCounter:] >= [:CONFIG.RULES.MaxWorkerSlack:] or ... </then> </if> </For> |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<For each="key:val" in="[:SUBSCRIPTIONS:]" from="$FacetData"> <if condition="/'[:$LocalData.Randkey:]' >= '[:$ProcessData$Macro.$BTVArgument.Worker.SlackTendencyName:]'"> <Log Message="I am in true, true block![:$LocalData.val:]"/> </if> </For> </if> </if> |