Iteration & Grouping

Iteration & Grouping


When working with repeated data, XPath enables you to loop through multiple elements or extract specific subsets of data based on conditions.

This section covers repeat loops, grouping techniques, and handling warnings when no nodes are selected.

Avoiding warnings in job logs when repeats select no nodes

Iterate across multiple detail lines (repeat).

Creating a repeat loop for a subset of nodes (based on a unique attribute, node name, or subtree value)

Grouping nodes (e.g., summarizing values from grouped nodes)

List values of all nodes, with a generic node name (starting with xxx).

Identifying the current line number within a repeat (e.g., in a transformation)

Avoiding warnings in job logs when repeats select no nodes

 

In the job logs you might see this warning:
Template.001014: Invalid element [idxx] 'Repeat' expression evaluated to 0 nodes:

 

 NG2Xpath0011

 

If you want to avoid such warnings, then you can consider to add a condition to test if there are any nodes for the repeat like below:

Change this:

  NG2Xpath0012

 

And add a condition either like this:

  NG2Xpath0013

 

The boolean() function returns true() if there is at least one node with that path. This is the most efficient test.


The alternative (less efficient way) is to count the number of nodes and compare that with zero like below:

  NG2Xpath0014


Iterate across multiple detail lines (repeat).


If you insert this Repeat Element, then InterFormNG2 will run the elements inside of the Repeat loop for each Document node in the XML file:

  NG2RepeatExample0001

 

  

 

You can then inside of the Repeat loop refer to the DocumentNo inside each Document node with an Xpath like this in a text element:

  

 

Please note, that both DocumentNo and ./DocumentNo will work in the rendered result, but the result view will also show the data of the first node, if you specify ./Document as above.

 

This will retrieve the values ‘1004', '1001' and '1003'.

 


Creating a repeat loop for a subset of nodes (based on a unique attribute, node name, or subtree value)


You do not need to include all the XML nodes with the same name/path in a repeat loop. You can also subset the nodes for the repeat e.g. based on attributes and/or the subtree of each of the nodes.

 

If we e.g. consider this XML file:

<persons>
  <chairman gender="female">
    <name>Maggie Frederiksen</name>
  </chairman>
  <person gender="female">
    <name>The Little Mermaid</name>
  </person>
  <person gender="male">
    <name>Mr. Andersson</name>
  </person>
  <person gender="male">
    <name>Mr. Nilsson</name>
  </person>
  <person gender="female">
    <name>Mercedes Hansen</name>
  </person>
  <person gender="female">
    <name>Lada Jaskagidaj</name>
  </person>
  <person gender="N/A">
    <name>Abcd Jensen</name>
  </person>
</persons>

 

Then we can e.g. define a repeat loop, that lists the name of all female persons (a gender attribute that is female) with this repeat loop: 

  NG2XPathIntro0003

 

We can also condition the subset on the contents of the subset of the current node. We can e.g. list all persons that has the text 'sen' somewhere in the name node like so:

  NG2XPathIntro0004

 

We can also condition a node set on the name of the nodes. If we e.g. have list of multiple nodes named "Adress" followed by a number (in sequence) like this:

  NG2XPathIntro0005

 

Then we can build a repeat loop to go all of these "Address" nodes like so:

/Root/Document/*[contains(name(),'Adress')]

 

If we want to print out the contents of all the Adress nodes the full setup can look like this:

  NG2XPathIntro0006

Where * selects any sub-node of the Document node and the name() function returns the name of the current node. The contains function is described here.

Grouping nodes (e.g., summarizing values from grouped nodes)
This section shows how you can group nodes in an XML file e.g. to only display the unique values/groups and e.g. summarize values from each group.
For this example we can use an XML file, that looks like this:
<Root>
    <CompanyInfo></CompanyInfo>
    <Greeting>HELLO WORLD</Greeting>
    <Barcode>www.interformng.com</Barcode>
    <Document Company="Herring Marine Research">
        <Contact_person>Martin Merman</Contact_person>
        <Date>20-09-2011</Date>
        <DocumentNo>1004</DocumentNo>
        <Adress1>Seaweed Street 14</Adress1>
        <Adress2>9000 Battleaxe</Adress2>
        <Country>DK-Denmark</Country>
        <Reference>PMK</Reference>
        <Intro></Intro>
        <Paragraphs></Paragraphs>
        <DetailLine SEQ="1">
            <Product>Interword400</Product>
            <Model>510</Model>
            <i-Group>i300</i-Group>
            <SN>44A2971</SN>
            <LicenseCode>81 20 01 3A</LicenseCode>
        </DetailLine>
        <DetailLine SEQ="2"></DetailLine>
    </Document>
    <Document Company="Florence Flowers">
    </Document>
</Root>

In the XML file above there are multiple Documents (in the Document nodes) and each document can contain multiple DetailLine nodes. The DetailLine nodes are the onces, that we want to list in this section.
Each DetailLine contains a node called Product and a node called Model.
For one of the documents we find these valus in the DetailLine:
    NG2XPathGroup0002

But now we only to list each unique product once and then sum up all of the models for this unique product. So we want to list Swiftview(50) and InterExcel400 once, but also only include InterForm400 once with the models summed up (515+810+890+520+530+270).

So how can we do that?
For that there are two solutions:
  • Preceding-sibling. We can do a repeat of all detail lines and use XPath functions, preceding-sibling or following-subling to count the number of nodes before or after the current node (with the same unique selection).

  • Distinct-values. We can use the Xpath function, distinct-values to generate a list of all unique values, count this number and iterate across each of these unique values


Preceding-sibling
One way is to iterate across of all of the detail lines (of the current document) and then only list the detail line, if this is the first detail line, that contains the current product name.

This can be done with the template below:
   

The setup is described below - line for line:
  1. Go through each of the Document nodes in the XML file with a repeat.
  2. We insert a new page for each document.
  3. A table is inserted with the headers for the table (this should/could be inserted in a page header to handle page overflows).
  4. A repeat loop iterates through the DetailLine nodes of the current document.
  5. We copy the value of the product of the current DetailLine into a variable, product (case sensitive).
  6. We calculate the number of preceding-siblings (DetailLines prior to the current one), that has the same product name as the current one. If there are no earlier ones (i.e. the number is 0), then we know, that this is the first occurrence of a unique product and then we want to output the current detail line. In this test we use the product variable from above ($product).
  7. We insert a table to output the values of the current detail line.
  8. Inside the table we print out the sum of all of the Model nodes for the detail lines, that has the same product name as the current one.
The expression: count(preceding-sibling::DetailLine[Product=$product])=0  tests the number of previous detail nodes with the same product name.
The result of the setup looks like this:
   

The expression: count(following-sibling::DetailLine[Product=$product])=0 tests, if the current node is the last (instead of the first) detail line with the specific product name.
The result of the setup looks like this:
   

Distinct-values
If you prefer to use the Xpath function, distinct-values, then then solution can look like below:
  

The setup is described below - line for line:
  1. Go through each of the Document nodes in the XML file with a repeat.
  2. Set the variable, count to 1 to start a new document. We use this variable to keep track of the current index of the distinct values.
  3. The repeat loop iterates for the number of distinct-value of the product. The distinct-values returns a list of distinct (unique) values and the count function is used for counting how many unique values, that we have found. So if e.g. 4 unique values are found, then the repeat loop will run 4 times.
  4. Next we update a variable, product to the product name of the current distinct value, that we intend to print out.
  5. Then we insert the table that is to contain the output values.
  6. In cell one we want to output the value of the @SEQ node, that has the same product name, as the one we are currently working with. We select that by comparing the value of the product inside the DetailLines with the currently selected Product name, which is stored in the variable called product.
  7. In the column, where we want to print out the product we simply use the variable.
  8. In the column, that should print out the sum of all Models we select a node set of all Models found in DetailLine nodes, that has a product that equals the currently selected product.
  9. In the bottom we increase the counter for each iteration, when we go through each distinct value.
List values of all nodes, with a generic node name (starting with xxx).

It is possible to list the all nodes, that has a name starting with a specific text. An example of a relevant XML file can be this:
  

In this example we want to list the values of all the nodes, that starts with Adress and we do not know how many there can be.

A way to do that is to use a repeat loop with this specification:
/Root/Document/*[starts-with(name(),'Adress')]
   

In the example above the repeat loop goes through all nodes with the path/name: /Root/Document/Adress* and with the text() specification we print out the value of each node.

In this example the output is:
  
Identifying the current line number within a repeat (e.g., in a transformation)

In a transformation you cannot use a variable to keep track of the current node number, so if you e.g. within a repeat wants to calculate the current node number, then you can consider this expression:

count(preceding-sibling::*) + 1
 

This is e.g. relevant in a transformation, where you cannot use a variable to keep track of this node number - especially if you want to verify the current line node number in a repeat for the line nodes of a spooled file.

 

 






    Notice: Help Center Transition Update

    As of January 13, 2025, we are excited to announce that our new Help Center is in the final stages of development. While the Knowledge Base is already accessible, our current JIRA system will continue to manage support tickets during this transition period. For assistance with InterForm Output Management Software, please refer to the Support for InterForm Output Management Software.

    We appreciate your patience and understanding as we work to enhance your support experience. If you have any questions or encounter any issues, please do not hesitate to reach out via the existing support channels.

    Best regards,
    The InterForm Support Team


      • Related Articles

      • Node Existence & Conditions

        XPath allows you to verify the existence of nodes, check if they contain data, count occurrences, and ignore namespaces. This section covers essential techniques for validating and filtering XML elements. Calculating the sum of nodes Counting ...
      • XML Node Selection & Referencing

        XPath provides multiple ways to reference and navigate through an XML structure. Learn how to select specific nodes using direct references, index numbers, conditions, and relationships with other nodes. Connecting preceding or following node sets to ...
      • Repeat element

        You can make InterFormNG2 repeat a selection of elements in a sub-folder. The repeat element repeats e.g. the elements a number of times, where this number can be either fixed or found via an Xpath expression, but it can also repeat the sub-folder ...
      • Repeat workflow component

        The advanced, utilities workflow component, Repeat creates a loop in which the components following it are executed a number of times. At the start of each repetition, the workflow payload and variables are reset to the state they have at the point ...
      • Repair an XML with invalid characters in a node

        Some characters cannot be used inside the value of a node or attribute within an XML file. The characters are: Original character Escaped character " &quot; ' &apos; < &lt; > &gt; & &amp; The table above indicates, that you should use the sequence ...