Solved

XML query: Testing a value from an XML source in XSLT

  • 26 January 2021
  • 12 replies
  • 255 views

Hello,

 

In a workflow XML query, I'd like to test a value (like {ItemProperty:...}), from an XML source (List Form) inside my XSLT, but there's an error, here is my code :

<tr><td>John Doe</td> <xsl:if test="{ItemProperty:name} = 'John'"> <td>{ItemProperty:name}</td> </xsl:if> <xsl:if test="{ItemProperty:surname} != 'Doe'"> <td style="background-color:yellow;">{ItemProperty:surname}</td> </xsl:if> </tr>

 

 

 

Nintex Workflow version : Nintex Workflow 2013 - Version: 3.1.3.0 - English

 

Best regards.

icon

Best answer by MegaJerk 9 February 2021, 20:23

View original

12 replies

Userlevel 5
Badge +14

Unfortunately, XSLT does not work in the way that you are trying to use it there. What XSLT does is work through a provided and valid XML tree to produce an output using the data / topology of said xml...

It is NOT particularly friendly but it IS very powerful if you take the time to learn how to use it. Below I have worked up an example that uses some fake Repeating Section data and produces an HTML table from the Repeating Section XML. 

Here is the XML for a Repeating Section that contains a control called "name" and a control called "surname":


<?xml version="1.0" encoding="utf-8"?>
<RepeaterData>
<Version />
<Items>
<Item>
<name type="System.String">Blank</name>
<surname type="System.String">Frank</surname>
</Item>
<Item>
<name type="System.String">John</name>
<surname type="System.String">Doe</surname>
</Item>
<Item>
<name type="System.String">Jane</name>
<surname type="System.String">Doe</surname>
</Item>
<Item>
<name type="System.String">Fred</name>
<surname type="System.String">Rogers</surname>
</Item>
<Item>
<name type="System.String">Londo</name>
<surname type="System.String">Mollari</surname>
</Item>
<Item>
<name type="System.String">John</name>
<surname type="System.String">Doe</surname>
</Item>
</Items>
</RepeaterData>

 


Now that we have our RepeaterData XML, let's use some XSLT to transform it!

Here is my demonstration XSLT:


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<!-- This code is partially from the Blog Post found here: -->
<!-- https://community.nintex.com/t5/Community-Blogs/XSL-Transformation-of-repeating-section-to-html/ba-p/83123 -->
<!-- transform repeating section from xml to html -->
<xsl:template match="/">
<table border="1" width="100%" style="border-collapse:collapse;border:1px solid;font-size:100%;font-family:arial,helvetica,sans-serif;padding:8px">
<thead>
<tr>
<td style="padding:10px;text-align:left; background-color:#000; color:white;">First Name</td>
<td style="padding:10px;text-align:left; background-color:#000; color:white;">Surname</td>
</tr>
</thead>
<tbody>
<xsl:for-each select="//Items/Item">
<xsl:variable name="altColor">
<xsl:choose>
<xsl:when test="name = 'John'">yellow</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="position() mod 2 = 0">#f2f2f2</xsl:when>
<xsl:otherwise>#FFFFFF</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<tr style="background-color:{$altColor}">
<td style="padding:10px;text-align:left;">
<xsl:value-of select="name" disable-output-escaping="yes" />
</td>
<td style="padding:10px;text-align:left;">
<xsl:value-of select="surname" disable-output-escaping="yes" />
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>

 


If you were to run this XSLT on the XML, the resulting HTML would be:


<table border="1" width="100%" style="border-collapse:collapse;border:1px solid;font-size:100%;font-family:arial,helvetica,sans-serif;padding:8px">
<thead>
<tr>
<td style="padding:10px;text-align:left; background-color:#000; color:white;">First Name</td>
<td style="padding:10px;text-align:left; background-color:#000; color:white;">Surname</td>
</tr>
</thead>
<tbody>
<tr style="background-color:#FFFFFF">
<td style="padding:10px;text-align:left;">Blank</td>
<td style="padding:10px;text-align:left;">Frank</td>
</tr>
<tr style="background-color:yellow">
<td style="padding:10px;text-align:left;">John</td>
<td style="padding:10px;text-align:left;">Doe</td>
</tr>
<tr style="background-color:#FFFFFF">
<td style="padding:10px;text-align:left;">Jane</td>
<td style="padding:10px;text-align:left;">Doe</td>
</tr>
<tr style="background-color:#f2f2f2">
<td style="padding:10px;text-align:left;">Fred</td>
<td style="padding:10px;text-align:left;">Rogers</td>
</tr>
<tr style="background-color:#FFFFFF">
<td style="padding:10px;text-align:left;">Londo</td>
<td style="padding:10px;text-align:left;">Mollari</td>
</tr>
<tr style="background-color:yellow">
<td style="padding:10px;text-align:left;">John</td>
<td style="padding:10px;text-align:left;">Doe</td>
</tr>
</tbody>
</table>

 


If we were to render that in a page, it would look like: 



 


Not bad!


 


But how in the heck does it work? Here is the same XSLT with a LOT of comments to help explain certain principles on how to use it:


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<!-- This code is partially from the Blog Post found here: -->
<!-- https://community.nintex.com/t5/Community-Blogs/XSL-Transformation-of-repeating-section-to-html/ba-p/83123 -->
<!-- transform repeating section from xml to html -->

<!--
XSLT works from the top node of whatever XML you give it assuming you match something with
your template. In this case we're matching the topmost level of our XML by using the "/" XPath.
To be precise, this would put us as the level of "RepeaterData" in our XML!
-->
<xsl:template match="/">
<!--
Now we're just creating the <table> html needed for our table. Nothing fancy. Just the table, headers, and body.
-->
<table border="1" width="100%" style="border-collapse:collapse;border:1px solid;font-size:100%;font-family:arial,helvetica,sans-serif;padding:8px">
<thead>
<tr>
<td style="padding:10px;text-align:left; background-color:#000; color:white;">First Name</td>
<td style="padding:10px;text-align:left; background-color:#000; color:white;">Surname</td>
</tr>
</thead>
<tbody>
<!--
However, now that we're in the table body portion, this is where we actually wanna start getting data from our XML set
and using the values to determine certain characteristics of the table, and to populate the table's data cells.

We can achieve this by looping through the nodes found at the Xpath of:
select="//Items/Item"

Each loop will place us at the "Item" level, which is important, because it determines how all of our
statements of equality and references to the nodes will be written!
-->
<xsl:for-each select="//Items/Item">
<!--
Because we're now in the "Item" node, and those nodes have a 'position()' value inside of their parent "Items" node,
we can use that to create an alternating table row background color for the table. However, you ALSO want a special
background color for when the value of the 'name' node equals the string 'John'.

We can accomplish all of that using a variable. Because it's within the scope of our loop, it is available to be used by
everything inside of the loop! First we'll create it and give it the name of "altColor"
-->

<!-- Create Alternating Colors -->
<xsl:variable name="altColor">

<!--
Here is where we test our first condition to see if the child node called "name" equals the value of "John"
-->
<xsl:choose>
<!-- If it does, set the value of variable to "yellow" -->
<xsl:when test="name = 'John'">yellow</xsl:when>
<!-- If it doesn't... -->
<xsl:otherwise>

<!-- ... then we test another condition -->
<xsl:choose>
<!-- if the position is EVEN then we set the variable's value to "#f2f2f2" -->
<xsl:when test="position() mod 2 = 0">#f2f2f2</xsl:when>
<!-- but if it's ODD we set it to "#FFFFFF" -->
<xsl:otherwise>#FFFFFF</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<!--
Now that the variable is set to one of the three values above. we can simply plug that into
the style attribute of our new table rows.
-->
<tr style="background-color:{$altColor}">
<!-- We can also style our table data (cell) to give the value a little more space -->
<td style="padding:10px;text-align:left;">
<!--
Last but not least, we need to actually GRAB the value of our XML node and place it here
between the <td></td> tags. You can't use an {ItemProperty:surname} insert like you'd normally use
in Nintex, but instead have to reference the value using actual XSLT. To do this you use the "value-of"
element, which will obtain the value of whichever node you select using its "select" attribute.

As you can see, we're simply selecting the node called "name". The value-of element also has an
optional attribute called "disable-output-escaping" which will just make sure to convert any escaped
values back into something more readable in the final output. It's turned on here, but it's not
necessary if you're working with XML that has no escaped characters.
-->
<xsl:value-of select="name" disable-output-escaping="yes" />
</td>
<td style="padding:10px;text-align:left;">
<!--
Now we just do that same for the surname node.
-->
<xsl:value-of select="surname" disable-output-escaping="yes" />
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>

(note: It's probably easier to read if you copy the above code and paste it into your own code editor like VSCode, Sublime Text 3, or Adobe Brackets. All of those are free options and help to make your life easier when messing with these sorts of things)


 


Like I said, it's not an obvious language to use, nor is it particularly user friendly. But it is incredibly useful for when you want to manipulate or use a bunch of Repeating Section data in a single Workflow Action.


 


A site like this: https://www.w3schools.com/xml/xsl_intro.asp will help to show you which each xsl element does and how it works. They also have a list of all the functions that can be used within your template: https://www.w3schools.com/xml/xsl_functions.asp


 


Remember that Nintex Workflow is limited to using XSLT version 1.0!!! If you're trying to find help, be aware that some examples could be using 2.0, and there are things in that version which are simply not available to us in NintexLand unfortunately.


 


One of the other best resources I've found for working with XSLT is this little tool that lets you input your XML / XSLT and will produce the results in the window below: https://www.freeformatter.com/xsl-transformer.html


 


You can use that along side anything your prototyping for instant feedback on whether you got it right or terribly wrong! Super useful! 


 


---


 


Any who, I won't talk anymore about this odd language, but I hope that my above example will help you to solve the problem it is you're trying to solve.

let me know! 


 


 


 

Hello MegaJerk,


Thank you for your quick and very detailed response.

To be more precise on my side, the workflow starts once the input form is created, which generates the xml.



I am accessing xml data (via XML request source) with {ItemProperty: FormData}.



The output is processed using XSLT, and Ican use those token:
For the data entered in the form: <td> {ItemProperty: Name} </td>
For variables: <td> {WorkflowVariable: var_surname} </td>



But I'm wondering if I can use these tokens in my tests like that :
<xsl: when test = "{ItemProperty: Name} = 'John'"> yellow </ xsl: when>
Or if I have to access the xml data directly, as you explained:
<xsl: when test = "Name = 'John'"> yellow </ xsl: when>

Userlevel 5
Badge +14

No, you cannot use the tokens in the way you are trying. It needs to be an xpath to the node / element you wanna test against. 


 


You can use them for "Values" but that's about it.


 


If the Item you were iterating over was for a person named John, What you have written would simply translate to:


<xsl: when test = "John = 'John'">


 


Because there is no element named John, it has no me.


 


 

OK thanks for your answer.


 


By cons I wonder how to read the xml file given by {ItemProperty: FormData}, to see all the xpath to the nodes/elements I want to test.


 


I've tried to get Form xml but this file is too long and unreadable ...

Userlevel 5
Badge +14

Ideally you would just link the Repeating Section to a MultiLine Text List Column. That way your XML is pushed to that column value, and you then run your XSLT / XML Queries against that column. 

Ok,


  But I'm wondering how to get the xml file, to get all the markups and contents.


Does this match the xml code of my form? The content look like that :


...20 markups after...


<d2p1:FormControlProperties i:type="d2p1:CalculationFormControlProperties">


   <d2p1:InsertReferences xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
      <d2p1:InternalPropertyBag xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
         <d2p1:DataField>List:name</d2p1:DataField>


...


Or can I access it, from the request xml workflow action, and how (do you know an output request to get all the markups and contents)?



 


Best regards, Yann.

Userlevel 5
Badge +14

If you're asking how you might get the contents of the FormData into something you can view and play around with, I would simply send yourself an email to see what the contents are. If you only need to see it a few times but not all of the time, this is a good way.

If you really wanted to, you could even use a workflow the set the value of a Multiline Text Column to equal the value of the FormData so that you can see it for every form, but I do not recommend this as it is likely not something you will ever need to do. 

Is this what you are looking for? 


 


Hello,
•   Thank you for your answers.
I tried by sending the Nintex Form content, containing several fields by email in plain text (with {ItemProperty:FormData}), but I only received two items in return :


<?xml version="1.0" encoding="utf-8">
<FormVariables><Version />
<Nom type="System.String">Doe</Nom>
<Surname type="System.String"></Surname>
</FormVariables>

 
•It's quite complicated to test items with xslt, is it possible to add javascript, and how?


try this but with no result in the list


<script>
<![CDATA[
window.addEventListener("load", function () {
var aTags = document.getElementsByTagName("td");
var searchText = "KO";
var found;
for (var i = 0; i < aTags.length; i++) {
if (aTags[i].textContent == searchText) {
found = aTags[i];found.style.backgroundColor = "yellow";
}
}
});
]]>
</script>
</xsl:template>
</xsl:stylesheet>
Userlevel 5
Badge +14

It's difficult to help without seeing the form, can you take a screenshot of the form in both the form builder and the SharePoint edit mode? It might be helpful in allowing us to better see what's happening.

Hello,


   Sorry but I can't, tell me if it's really useful for you and I'll create a new one.


   But let me explain:



  • The workflow starts once the form is completed (with 10 fields, from radios, checkboxes, text)

  • XML is retrieved with {ItemProperty:FormData} (but unfortunately for me the xml received by email notification only returns two items/fields)

  • and transformed into HTML with XSLT :


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<!-- transform repeating section from xml to html -->
<xsl:template match="/">
...


  •  then the result is displayed in the list


 


So since I can't retrieve the XML I wonder if I can insert javascript in the XSLT?


 

Userlevel 5
Badge +14

It would be useful to see a test version of the form to better understand maybe what's happening and why you're not getting all of the xml data back that you should be. 


 


However to answer your other question, you cannot use javascript mixed in with the xslt to do anything. They are two different things. 

Hello, thank you again for your answers, I will not have time to do a test version.

Reply