Hi @isabellamai
I have some clarifying questions to ask you before I can answer your questions.
1. Is the Repeating Section nested (2-levels) or 2 separated (1-level)?
Nested Repeating Section
Separated Repeating Section
2. What do you mean by "the data extracts correctly"
- Viewing the SP column values?
- Using Query XML and Log to History?
3. Getting Data from a single level Repeating Section
a) Use a XML Query action.
XML Source: [Content] the SP multiline column that is connected to the Repeating Section
XPath Query: /RepeaterData/Items/Item/<GUID>
Return result as: [Text]
Query result in: Collection-type Variable "Results"
b) Use a For-Each Loop
Input Collection: The Collection-type Variable "Results"
Output Value: Variable to store the VALUE
Output Index: Variable to store the INDEX
4. Getting Data from a nested Repeating Section
NOT RECOMMENDED - PLEASE AVOID
Its extremely difficult to extract the 2nd layer because its embedded with HTML Entities
("<" becomes <)
Cheers
Garrett has already answered the question if it's not a Nested Repeating Section, but I figured I could write up an example and tutorial on what to do *if* you do happen to be using Nested RS. Please mark their answer correct if this post here does not apply to the situation, otherwise, keep reading!
If you want to loop a nested Repeating Section you just need to do a little more prep work for your own sanity, but it is relatively easy once you know what to do.
Though I am making this example generic, so you will have to apply the basic idea to your own environment, but it should be simple enough. Additionally this should work for both Classic and Responsive Forms (at least for On Prem)
In this example I have created a basic form with a nested Repeating Section:
ALL of my Controls are named! This is important!!! When you're working with XML the Control Names are used as the Node Names in the XML and makes your life 1000 percent easier. If you don't name you're controls then you're going to be left looking at a bunch of GUIDs that will make you sad. As you can see, the two Repeating Sections follow the naming convention of "control_RS#" while the Single Line Text fields are named according to the Repeating Section they are nested in respectively.
Additionally, the control_RS1 outermost Repeating Section is connected to a Multiline Text Column on the list called "RS1XML":
Let's populate an item:
The Results:
Alright, that's not very easy to look at. Let's format it using a handy tool like (https://www.freeformatter.com/xml-formatter.html😞
<?xml version="1.0" encoding="UTF-8"?>
<RepeaterData>
<Version />
<Items>
<Item>
<control_RS1_someNumber type="System.String">1</control_RS1_someNumber>
<control_RS2 type="System.String">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;RepeaterData&gt;&lt;Version /&gt;&lt;Items&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;A&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;B&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;C&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;/Items&gt;&lt;/RepeaterData&gt;</control_RS2>
</Item>
<Item>
<control_RS1_someNumber type="System.String">2</control_RS1_someNumber>
<control_RS2 type="System.String">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;RepeaterData&gt;&lt;Version /&gt;&lt;Items&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;D&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;E&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;/Items&gt;&lt;/RepeaterData&gt;</control_RS2>
</Item>
</Items>
</RepeaterData>
hmm... it looks a little better, but obviously something is happening. It looks like once we get to our inner Repeating Section ("control_RS2") the XML is all garbled. That's because in XML a value can't contain certain characters like "<" and ">" because those are inherently special and reserved for the structure of the XML itself. So, to get around that, those characters are encoded in a special but standard way, so that they can later be decoded aka: unescaped back into what they actually are.
To make the above a bit more human readable, I'll go on and decode / un-escape it so that it *all* becomes standard xml (note: this is just for demonstration purposes only. you'll never need to do what I've done in the above step or this one in order to make a workflow that works with nested XML data. I'm only doing this so that you can visually see how the data is laid out as it can be important to understanding it later):
<?xml version="1.0" encoding="UTF-8"?>
<RepeaterData>
<Version />
<Items>
<Item>
<control_RS1_someNumber type="System.String">1</control_RS1_someNumber>
<control_RS2 type="System.String"><?xml version="1.0" encoding="utf-8"?><RepeaterData><Version /><Items><Item><control_RS2_someLetter type="System.String">A</control_RS2_someLetter></Item><Item><control_RS2_someLetter type="System.String">B</control_RS2_someLetter></Item><Item><control_RS2_someLetter type="System.String">C</control_RS2_someLetter></Item></Items></RepeaterData></control_RS2>
</Item>
<Item>
<control_RS1_someNumber type="System.String">2</control_RS1_someNumber>
<control_RS2 type="System.String"><?xml version="1.0" encoding="utf-8"?><RepeaterData><Version /><Items><Item><control_RS2_someLetter type="System.String">D</control_RS2_someLetter></Item><Item><control_RS2_someLetter type="System.String">E</control_RS2_someLetter></Item></Items></RepeaterData></control_RS2>
</Item>
</Items>
</RepeaterData>
Now it becomes far more apparent how the data is structured. Inside of our initial RepeaterData we have several Item nodes that each contain a "control_RS1_someNumber" node and a "control_RS2" node that has a value of *more* RepeaterData with its own Item nodes!
With this structure in mind, let's create a workflow to pull out those values
First thing first is that I am going to make a BUNCH of variables to hold all of our data. It should be noted here that we'll need at least 2 collection variables, one for set of RepeaterData:
After that I will create my first Query XML Action and configure it as follows:
Make sure that for the XML portion you're referencing the Column that your Main Repeating Section is associated to. In my case it's a column called "RS1XML"
Process using XPATH, and set the XPATH's value to //Item
In XPath you can use the double forward slash as a shortcut directly to the node specified, so "//Item" just means, "return all of the nearest children nodes that are named 'Item'".
Set the Return Results As to "Outer XML", and then store the results in one of the Collection Variables we created. In this case I'm using the variable var_RS1_Items.
The results of this will produce, when using the example XML I show above, (2) portions of XML that will go into our collection variable:
<!-- Item 1 -->
<Item>
<control_RS1_someNumber type="System.String">1</control_RS1_someNumber>
<control_RS2 type="System.String">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;RepeaterData&gt;&lt;Version /&gt;&lt;Items&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;A&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;B&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;C&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;/Items&gt;&lt;/RepeaterData&gt;</control_RS2>
</Item>
<!-- Item 2 -->
<Item>
<control_RS1_someNumber type="System.String">2</control_RS1_someNumber>
<control_RS2 type="System.String">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;RepeaterData&gt;&lt;Version /&gt;&lt;Items&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;D&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;Item&gt;&lt;control_RS2_someLetter type=&quot;System.String&quot;&gt;E&lt;/control_RS2_someLetter&gt;&lt;/Item&gt;&lt;/Items&gt;&lt;/RepeaterData&gt;</control_RS2>
</Item>
Knowing that, now we just need to loop through these items. Here's our first For Loop:
Notice that I'm selecting our Collection, and then storing its value in the var_RS1_Item variable. You don't have to include an Index variable in your own workflow, but I like to do that for added clarity.
Inside of this first For Loop will live another Query XML Action Configured as follows:
After the first Output, click on the "Add Output" button and configure the second one as follows:
All we're doing here is grabbing the value of RS1_someNumber, and the value of RS2. RS2 however is the more interesting of the two because it's the XML Data that has been encoded / escaped, meaning that if we want to be able to use it, we're going to have to figure out how to convert back into XML proper. Luckily Nintex has us covered.
Currently our Workflow looks like:
But we're going to add a Build String Action to take care of the XML Conversion:
Open the Build String Action and click on the Insert Reference button:
Inside of the Reference Dialog, find the Inline Functions tab, click on it, and then scroll to the bottom of the list. Double click on Decode XML to insert it into the text to insert:
with your mouse, click between the two parentheses of that function, then go back up and click on the Workflow Variables Tab, find the var_RS2 variable (or wherever you've stored the text of the nested Repeater Control), and double click it to insert it between the parentheses:
After hitting the OK button, make sure that you're saving this build string's output BACK to the same variable because we don't really need the encoded / escaped data. We just want the Decoded stuff:
What exactly does that decode function do you might ask? well it takes this:
<?xml version="1.0" encoding="utf-8"?><RepeaterData><Version /><Items><Item><control_RS2_someLetter type="System.String">A</control_RS2_someLetter></Item><Item><control_RS2_someLetter type="System.String">B</control_RS2_someLetter></Item><Item><control_RS2_someLetter type="System.String">C</control_RS2_someLetter></Item></Items></RepeaterData>
And turns it into this:
<RepeaterData>
<Version />
<Items>
<Item>
<control_RS2_someLetter type="System.String">A</control_RS2_someLetter>
</Item>
<Item>
<control_RS2_someLetter type="System.String">B</control_RS2_someLetter>
</Item>
<Item>
<control_RS2_someLetter type="System.String">C</control_RS2_someLetter>
</Item>
</Items>
</RepeaterData>
Now that we know we have yet another set of usable Repeater Data stored in our variable, we can create another Query XML action to start extracting the values inside of it:
And now that we have another Collection of Items to go through, we make another For Loop:
And another Query XML to get the values of whichever Item of this second RepeaterData set we're processing:
(Note: Here I'm only getting the value of the "control_RS2_someLetter" control because I only have one control inside of my Nested Repeating Section. If you have more than one control, then you can simply click on the "Add Output" link and get however many you'd like!)
Our workflow now looks like:
Or for the visually inclined:
To make sure I'm not crazy, I'm going to make an Output string variable that I can save all of these values into in and with a little formatting applied (note: I don't know why I spelled "Output" as "OutPut" but I'm too lazy to fix it now!):
I can just place these after the parts of my workflow when I'm getting the control values, and set them up accordingly:
And for the inner loop:
And then before the end of my workflow I just send the variable to my email:
The Results:
I know that this post is lengthy but any time one is messing with a lot of XML and loops, it's bound to go run on a bit. If you have any additional questions, feel free to ask, but I hope that this helps you to deal with any Nested Repeating Sections in the future.
Hey @MegaJerk
Thank you very much for the detailed explanation. As usual, you have put in a tremendous amount of work and effort into your explanations. Great work!!
I just like to highlight important issues for Nintex O365 Users
1. For New Responsive form - the named control does not appear in the XML. Instead, what is shown is the GUID - a sequence of 32 alphanumerical characters.
<RepeaterData><Items><Item><_GUID>
This is usually used as the Query XPath - "//_GUID"
You will also need to decipher which field is associated with which GUID.
2. There is no Inline Function feature in Nintex Workflow O365. So the function fn-XMLDecode is unavailable. Use multiple "Replace Substring in String" action.
Replace('&', '&'),
Replace('<', '<'),
Replace('>', '>') and
Replace('"', '"')
3. Incorrect XML usage will usually Suspend/Terminate the workflow.
XML content is invalid. Unexpected XML declaration. The XML declaration must be the first node in the document
4. Query XML is Nintex Live workflow action that executes on an external server. Execution time may take slightly longer which varies from one minute to five minutes.
My Personal Approach
FYI, if there is any Query XML needed to be done where the value needs to be extracted and populated into another column(s) - I usually avoid using Nintex Workflow (for XML) instead I use PowerShell scripts (which is faster to develop, faster to debug and faster to execute)
My two cents