mattbriggs

Modifying Forms XML

Blog Post created by mattbriggs Employee on May 27, 2016

With Nintex Forms for SharePoint On Premises 2013, you can download a serialized version of your Nintex Form in XML format. By changing certain element values in the XML you can write an application that can update the text of your labels, switch the target URLs for your images, update CSS, and so on. This is helpful for instance if you need to create a batch update of the Nintex Forms for rebranding your site or to make other modest changes to the content of a large number of forms. In this post, I'm going to look at creating a C# console application to modify a single form.

 

Table of Contents

About the XML DOM and XPath

In working with XML, you are going to read the XML document into memory and interact with the XML document object model (DOM). If you are familiar with programming with JavaScript, you are probably already familiar with working with a document object model. Like the HTML DOM, the XML DOM represents the document as tree of nodes. A valid XML document has a root, and then follows a parent and child pattern (that is, the branches of the tree). XPath is a a query language for selecting nodes within the XML document. If you are unfamiliar with the XML DOM, you can find an introduction and tutorial on working with the DOM at W3, and an introduction and explanation about XML and Xpath.

Some Suggested Tools

Working with XML can provide some challenges, and there are a couple of tools that I tend to turn to when I am working with it: XML text editor and Xpath Query tool. In addition, Visual Studio and the .NET Framework have many libraries and tools to work with XML.

  • XML text editor
    I usually need a basic text editor that is aware of the DOM and provides a collapsible view of the XML tree. I use a piece of freeware called PSPAd, but here is also Microsoft's XML Notepad.
  • XPath Query tool
    I use XPath Checker (a Firefox FireBug Add-on). The checker is an interactive XPath expression tool. In FireFox load your XML document, right-click, and then choose View XPath, and then you can try out your XPath queries to check your syntax.
  • XML Libraries (XML Tools in Visual Studio).
    This is a good starting place if you are not familiar with the full set of classes and tools that offered by both the .NET Framework but also some Microsoft extensions to Visual Studio.

Creating a Console Application

The following console application uses the XMLDocument class in the .Net Framework and the XPath queries to identify nodes in the XML DOM that will be updated. I am updating a banner graphic and a label control. Before I use the code sample in the Nintex Forms SDK, I'll export my Nintex Form XML, examine it in my XML editor, and then use my XPath query tool to create the XPath strings to target my nodes. I'll download the sample and modify to load the node for the banner and the label text, and update the nodes with the new values, and then save the resulting XML. Finally, I'll upload the changed file.

Here is the original form:

oiginalform.png

1. Download the Nintex Form XML

I downloaded the XML from the Nintex Forms Designer. Note, you can also access the XML by using the API. You can find an overview and a sample at "Migrate Forms with the Nintex Forms Web Service API."

2. Open the XML in an XML text editor

I opened the Form XML in PSPad to identify the nodes I wanted to change.  Note, you may run into an issue when opening the form XML due its encoding. When I open in the file PSPAD, for example, the file opens as a Hex file. I found that I can open the file in Windows Notepad and save the file to convert it. The file declares that it is in UTF-16; however, I found you can work with the file and reload the Form XML after opening and savings in from Windows Notepad. In addition, I usually beatify the XML. Many text editors have a reformat in HTML or XML option that will tidy the XML formatting so that the child nodes are nested under parent nodes. This step doesn't have any effect on the data, but it does make the file a lot easier to work with.

Here is an image of the XML in the PSPad showing the XML DOM:

pspad_xml.png

3. Review the structure of well-formed Nintex Form XML

I identified the nodes I wanted to change. It may help to become familiar with the general structure and hierarchy of the file format if you plan on doing a lot of work with it. You can find more information in the XML Reference in the SDK.

4. Open the XML in the XPath Query Tool

I noted the namespaces prefix and namespace declarations. For example, the following table shows the prefix and namespaces identified by the XPath Checker in my XML:

You will use this information to create your namespace table in the XmlNamespaceManager in the console application.

Here is an image of the XPath Checker finding the node containing the image value:

xpathchecker.png

I built my XPath Queries for each element that I was going to change. Using FireFox, I opened the XML, and then searched for the string I knew I was going to change, in this case the reference to the banner graphic and then the label text. For each string I right-clicked, selectex Xpath, and then in the XPath Checker copies the XPath query.

  • Node containing the image reference:
    /n:Form/n:FormControls/n1:FormControlProperties[1]/n1:ImageUrl
  • Node containing the label text:
    /n:Form/n:FormControls/n1:FormControlProperties[10]/n1:DisplayName

5. Download the code sample from the SDK

I created a new solution and used the stubbed code from the SDK. You can find the sample at "Update a Single Form XML."

6. Add the namespace prefixes and namespace declarations.

In the code sample, I updated the XmlNamespaceManager to specify the namespaces discovered by the XPath Checker.

           XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
            nsmgr.AddNamespace("n", "http://schemas.datacontract.org/2004/07/Nintex.Forms");
            nsmgr.AddNamespace("n1", "http://schemas.datacontract.org/2004/07/Nintex.Forms.FormControls");
            nsmgr.AddNamespace("d2p1", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");

7. Update each node.

For each element I wanted to change, I added the XPath query string to load the node and replace with the new node value.

The banner:

            // Find with XPATH using the Namespace
            // update with the xpath to your FormXML for the banner image
            string xPathString1 = "/n:Form/n:FormControls/n1:FormControlProperties[1]/n1:ImageUrl";
            XmlNode xmlNode1 = doc.DocumentElement.SelectSingleNode(xPathString1, nsmgr);
            string text1 = xmlNode1.FirstChild.Value;
            //update with the new URL
            string yourupdatevalue1 = "http://that-or-this.com/sdk/banner_update.png";
            xmlNode1.FirstChild.Value = yourupdatevalue1;

The label:

            // update with the xpath to your FormXML for the label text
            string xPathString2 = "/n:Form/n:FormControls/n1:FormControlProperties[10]/n1:DisplayName";
            XmlNode xmlNode2 = doc.DocumentElement.SelectSingleNode(xPathString2, nsmgr);
            string text2 = xmlNode2.FirstChild.Value;
            //update with the new URL
            string yourupdatevalue2 = "><span style="font-size: 18pt;" RteNodeId="2"><strong>Changed Text</strong></span>";
            xmlNode2.FirstChild.Value = yourupdatevalue2;

8. Add Input and Output Paths

I added the input path and output path.

Input:

doc.Load(@"C:\out\FormXML.xml");

Output:

doc.Save(@"C:\out\FormXML_update.xml");

9. Build and execute the application.

I built and executed the application. The XML appeared in the console. I checked the output folder, and found the output XML.

10. Load into the Nintex Forms designer

Finally, the moment of truth! I loaded the updated XML into the Nintex Forms. The file import expects strictly valid XML and will error out if there is an issue. In this case, the the XML loaded with the update.

Here is an image of the updated form:

updatedform.png

Complete Example Code

Here is the code I used in the example. I was updating two nodes, label text and a banner graphic.

/* Program.cs

   Copyright (c) 2016 - Nintex. All Rights Reserved.  
   This code released under the terms of the  
   Microsoft Reciprocal License (MS-RL,  http://opensource.org/licenses/MS-RL.html.)
   
*/

using System;
using System.Xml;

namespace _2013_ONPREM_NF_UpdateFormXML
{
    /// <summary>
    /// This class demonstrates how to use the XMLDocument class to update a Nintex Form. 
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            // Create, load, and then extract the XML document.
            // the filepath to your FormXML.
            XmlDocument doc = new XmlDocument();
            doc.Load(@"C:\out\FormXML.xml");
            string xmlcontents = doc.InnerXml;

            // Add namespaces to the namespace manager (prefix and then namespace).
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
            nsmgr.AddNamespace("n", "http://schemas.datacontract.org/2004/07/Nintex.Forms");
            nsmgr.AddNamespace("n1", "http://schemas.datacontract.org/2004/07/Nintex.Forms.FormControls");
            nsmgr.AddNamespace("d2p1", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");

            // Find with XPATH using the Namespace
            // update with the xpath to your FormXML for the banner image
            string xPathString1 = "/n:Form/n:FormControls/n1:FormControlProperties[1]/n1:ImageUrl";
            XmlNode xmlNode1 = doc.DocumentElement.SelectSingleNode(xPathString1, nsmgr);
            string text1 = xmlNode1.FirstChild.Value;
            //update with the new URL
            string yourupdatevalue1 = "http://that-or-this.com/sdk/banner_update.png";
            xmlNode1.FirstChild.Value = yourupdatevalue1;

            // update with the xpath to your FormXML for the label text
            string xPathString2 = "/n:Form/n:FormControls/n1:FormControlProperties[10]/n1:DisplayName";
            XmlNode xmlNode2 = doc.DocumentElement.SelectSingleNode(xPathString2, nsmgr);
            string text2 = xmlNode2.FirstChild.Value;
            //update with the new URL
            string yourupdatevalue2 = "Changed Text";
            xmlNode2.FirstChild.Value = yourupdatevalue2;

            // your target path
            Console.WriteLine(doc.DocumentElement.OuterXml);
            doc.Save(@"C:\out\FormXML_update.xml");

        }
    }
}

Outcomes