Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents
minLevel3
outlinetrue
stylenone

 


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
ForRequiredLoop 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]

  • One variable form: each=”var_name” this is used to iterate over values

  • Two variables form: each=”key_var:value_var” this is used to iterate over entries (i.e. key:value pairs)
  • Two variables form can be used to define only one (e.g. “key_var:” or “:value_var”)

  • Variable names can be “deep” i.e. contain dots in them (e.g. “obj.type:obj.value”)

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

...

languagexml
themeEclipse
titleAssign 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
languagexml
themeEclipse
titleIterating over Query Result
<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>
#QuestionExplaination
1

How do I determine the number of iterations of a for loop?

Code Block
languagexml
themeEclipse
titleIterating over Query Result
<Query>
  <Find format="all">
    <VendorInfo>
      <vendorId ne=""/>
    </VendorInfo>
  </Find>
  <For Each="v" IN="$Response.Message.Value.Find">
    <Log Message="[:$LocalData.v:]"/>
  </For>
</Query>

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

  • For source: $Response.Message.Value.Find. There is only one container with <Find>.
  • For source: $Response.Message.Value.Find.Result. There are three containers with <Result> The size will be 3.
  • For source: $Response.Message.Value.Find.VendorInfo.vendorId. There are three containers with <vendorId> The size will be 3.
2

What happens if I do not specify value in Each i.e Each="k:v"

Code Block
languagexml
themeEclipse
titleIterating over Query Result
<Query>
  <Find format="all">
    <VendorInfo>
      <vendorId ne=""/>
    </VendorInfo>
  </Find>
  <For Each="k:v" IN="$Response.Message.Value.Find.Result.VendorInfo.vendorId">
    <Log Message="In Loop...: [:$LocalData.k:] -> [:$LocalData.v:]"/>
  </For>
</Query>
  • Number of iterations in the loop in this case is 0. Since the starting point is there are no child elements within vendorId that can be broken down into Key / Value pair.
  • If the starting point is made as
    $Response.Message.Value.Find.Result.VendorInfo, number of iterations are 4;

    The key/value is generated for only the last entry.

3

What happens if we provide only one variable in key/value format i.e either k: or :v

Code Block
languagexml
themeEclipse
titleIterating over Query Result
<Query>
  <Find format="all">
    <VendorInfo>
      <vendorId ne=""/>
    </VendorInfo>
  </Find>
  <For Each="k:" IN="$Response.Message.Value.Find.Result.VendorInfo.vendorId">
    <Log Message="In Loop...: [:$LocalData.k:] -> [:$LocalData.v:]"/>
  </For>
</Query>
  • Number of iterations in the loop in this case is 3. LocalData.v: will be unavailable. All the keys are printed i.e

    In Loop...: vendorA -> [:$LocalData.v:]

    In Loop...: vendorB -> [:$LocalData.v:]

    In Loop...: vendorC -> [:$LocalData.v:]

  • If we change it to :v format; the number of iterations in the loop remains as 3; LocalData.k: will be unavailable. All the keys are values are printed i.e.

    In Loop...: [:$LocalData.k:] -> vendorA

    In Loop...: [:$LocalData.k:] -> vendorB

    In Loop...: [:$LocalData.k:] -> vendorC



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
    languagexml
    themeEclipse
    titleAssign 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 -->
      </For>VendorInfo>
      <VendorInfo>
      <!-- Do an<VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId>
    Update -->   <Update>
        <From>Result</From><vendorName Status="Success_NoAction:1:1460757648025;" Value="Phidget" Version="1"/>
        <vendorTitle  <Include>$Response.Message.Value.Find</Include>
      </Update>
    </Query>
     Status="Success_NoAction:1:1460757648027;" Value="Sensor Provider" Version="1"/> <!-- Note Resultthere is.. -->
    <Find Status="Success" Format="version">
      <Result>
        <VendorInfo>
      no change in value -->
      </VendorInfo>
      <VendorInfo>
        <VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE<<VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId>
        <vendorName  <vendorTitle Status="Success_NoAction:1:1460757661429;" Value="Sensor ProviderPhidget3" Version="1"/>
        <vendorTitle  <vendorName Status="Success_NoAction:1:1460757661429;" Value="LibeliumSensor Provider" Version="21"/> <!-- Note there is </VendorInfo>no change in </Result>
    value -->
     <Result> </VendorInfo>
    </Update>

    Correct way is to point val → Find.Result.VendorInfo 

    Code Block
    languagexml
    themeEclipse
    titleAssign to STRUCTURE
    <Query>
      <VendorInfo>
    <Find format="Version">
         <VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId><VendorInfo>
          <vendorTitle Valueeq="Sensor Provider" Version="1"/>
     
        <vendorName Value="Phidget" Version="1"/>
        </VendorInfo>
      </Result>Find>
      <For <Result>
    each="val" in="Find.Result.VendorInfo">
       <VendorInfo> <IF Condition="/'[:$LocalData.val.vendorTitle.Value:]' eq 'Sensor Provider'">
     <VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId>     <Log  <vendorTitle ValueMessage="Found Sensor Provider" Version="1"/>
        </IF>
        <vendorName<SetLocalData ValueKey="Phidget3val.vendorTitle.Value" VersionValue="1Actuator Provider"/>
     
      </VendorInfo>For>
      </Result>
    </Find>
    <Update Status="Success" Format="version">
      <VendorInfo>!-- Do an Update -->
      <Update>
        <From>
         <VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE</VendorSysId> Result
       <vendorName Status="Success_NoAction:2:1460829683086;" Value="Libelium" Version="2"/> </From>
        <Include>
        <vendorTitle Status="Success_NoAction:1:1460757657344;" Value="Sensor Provider" Version="1"/> $Response.Message.Value.Find
        </Include>
      </Update>
    </Query>
    <!-- NoteResult thereis is-->
    no change in value -->
      </VendorInfo><Find Status="Success" Format="version">
      <Result>
        <VendorInfo>
          <VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG<<VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE</VendorSysId>
         <vendorName <vendorTitle StatusVersion="Success_NoAction:1:1460757648025;3" Value="Phidget"Actuator Version=Provider"1"/>
         <vendorTitle Status="Success_NoAction:1:1460757648027;" <vendorName Value="Sensor ProviderLibelium" Version="12"/>
     <!-- Note there is</VendorInfo>
    no change in</Result>
    value --> <Result>
     </VendorInfo>   <VendorInfo>
          <VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK<<VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId>
         <vendorName Status="Success_NoAction:1:1460757661429;" Value="Phidget3" Version="1 <vendorTitle Version="3" Value="Actuator Provider"/>
         <vendorTitle Status="Success_NoAction:1:1460757661429;" <vendorName Value="Sensor ProviderPhidget" Version="1"/> <!-- Note there is no change in value -->
      </VendorInfo>
    </Update>

    Correct way is to point val → Find.Result.VendorInfo 

    Code Block
    languagexml
    themeEclipse
    titleAssign to STRUCTURE
    <Query>
      <Find format="Version">
        <VendorInfo>
        </VendorInfo>
      </Result>
      <Result>
        <VendorInfo>
          <VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId>
          <vendorTitle Version="3" Value="Actuator Provider"/>
          <vendorTitle<vendorName eqValue="Phidget3"Sensor ProviderVersion="1"/>
        </VendorInfo>
      </Result>
    </Find>
    <Update  <For eachStatus="valSuccess" in="Find.Result.VendorInfo">
        <IF Condition="/'[:$LocalData.val.vendorTitle.Value:]' eq 'Sensor Provider'Format="version">
      <VendorInfo>
       <Log Message="Found Sensor Provider"/> <VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE</VendorSysId>
        <vendorName  </IF>Status="Success_NoAction:2:1460829683086;" Value="Libelium" Version="2"/>
        <SetLocalData<vendorTitle KeyStatus="val.vendorTitle.ValueSuccess=Updated:4:1460935288963;" Value="Actuator Provider" Version="4"/>
      </For>
      <!-- DoTitle anis Updateupdated -->
    
     <Update>     <From>
          Result
        </From>VendorInfo>
       <VendorInfo>
    <Include>       $Response.Message.Value.Find
    <VendorSysId>KQN7BUUZAAAAUAABBPXOPXWG</VendorSysId>
       </Include> <vendorName  </Update>
    </Query>
    <!-- Result is -->
    <FindStatus="Success_NoAction:1:1460757648025;" Value="Phidget" Version="1"/>
        <vendorTitle Status="Success=Updated:4:1460935288964;" FormatValue="Actuator Provider" Version="version4"/> <!-- Title <Result>is updated -->
      <VendorInfo></VendorInfo>
      <VendorInfo>
        <VendorSysId>KQN7B5X7AAAAUAABBN7HUYCE<<VendorSysId>KQN7CBXVAAAAUAABBNFHWPBK</VendorSysId>
        <vendorName  <vendorTitle VersionStatus="3Success_NoAction:1:1460757661429;" Value="Phidget3"Actuator ProviderVersion="1"/>
        <vendorTitle  <vendorName Status="Success=Updated:4:1460935288964;" Value="LibeliumActuator Provider" Version="24"/> <!-- Title is updated -->
      </VendorInfo>
     
    </Result>Update>

Examples

Code Block
languagexml
themeEclipse
titleIterating over Query Result
<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="Vendor Name is: [:$LocalData.val.vendorName.Value:]"/>
</For>
</Query>
Code Block
languagexml
themeEclipse
titleUsing a non-default store
<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
languagexml
themeEclipse
titleSpecify the local store
<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 

...

Examples

Code Block
languagexml
themeEclipse
titleIterating over Query Result
<Query>
  <Find format="Version">
    <VendorInfo>
data -->
<For each="val" in="Atomiton.FS.Features" from="$ContextData" using="$ProcessData">
  <Log Message="within loop...[:$ProcessData.val:]"/>
</For>
Code Block
languagexml
themeEclipse
titleLooping from ContextData
<For each="light" in="Message.Value.lights" from="$ContextData.response">
  <SetContextData key="state">
          <value>
              <intensityLevel>-1</intensityLevel>
     <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 --><powerConsumption>-1</powerConsumption>
              <reliability>0</reliability>
       <Log Message="Vendor Name is: [:$LocalData.val.vendorName.Value:]"/> </For>
</Query>
Code Block
languagexml
themeEclipse
titleUsing a non-default store
<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
languagexml
themeEclipse
titleSpecify the local store
<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="within loop...[:$ProcessData.val:]"/>
</For>value>
          </SetContextData>
          <if condition="[:$LocalData.light.location/count(latitude) gt 0:]">
            <then>
             ...
			</then>
		</if>
</For>       
Code Block
languagexml
themeEclipse
titleLoop with Each in key:val format
<For each="key:val" in="[:SUBSCRIPTIONS:]" from="$FacetData">
  <if condition="/'[:$LocalData.key:]' = '[:$Macro.Argument.Name:]'">
          <Log Message="[:$LocalData.val:]"/>
  </if>
</For>