Wednesday, February 6, 2008

Working with InfoPath XML and Archiving it with BlackPearl and SharePoint

On the K2 Underground I have seen two very common requests for InfoPath but simple could use a little instruction on – changing XML Fields and archiving the XML.

Changing a XML value for InfoPath forms is a pretty hot topic on a couple different threads. In K2 2003 three there was an event that allowed you to set values into data or xml fields. The code it generated is rather trivial in nature. If you had lots of fields you needed to set and you wanted to centralize the code, you would start writing your own custom class to do the work and the wizard was not needed anymore. Plus if you had complex data structures, repeating data, etc. using that wizard would not suffice.

Luckily working with the K2 API to set values is really simple. I would still challenge anyone architecturally if they are putting large amounts of data into their process and activity level fields; especially if it is enterprise data. I would get that data out into a custom database using SmartObjects, custom service layers, existing code libraries, etc. BlackPearl makes it significantly easier to get at the process and activity level data utilizing their SmartObjects. However I still believe that BlackPearl a state machine which has a database to manage the state machine. Line of business data in the BlackPearl database is important to the enterprise but the contextual data about the business process instance should be externalized. For example, if I had a bunch of financial data I would not have it sitting in an XML field in the K2 database; I would save it out externally. But the K2 database will give us valuable insight into metrics and performance of the business process instances.

That said I would not use InfoPath xml files stored in a Form Library as a repository of data either. I would incorporate time into your project plans to shred the important of pieces of data out of the XML and push it out externally. You may still want to archive the InfoPath form but I would use K2's InfoPath integration with SmartObjects to load up the form when it is opened. I am not a fan of putting large amounts of business data into SharePoint lists and form libraries. Those tools are great for supporting the user collaboration experience but nothing replaces storing data in a database so the data can be leveraged across the enterprise.

1) Changing an XML Field Data

To start, drag on a Default Server event. You will see that none of this code is really K2 specific. All we do is get the XML string from the XML field, put it into an XmlDocument, add a InfoPath namespace, run an XPath query, and set the XML string back into the XML field.

//Get the XML Field string
string xml = K2.ProcessInstance.XmlFields["XXX"].Value.ToString();

//Load up the XML
XmlDocument doc = new XmlDocument();

//Create a name space manager for InfoPath
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("my", doc.DocumentElement.GetNamespaceOfPrefix("my"));

//Now set some values
doc.SelectSingleNode("//my:Company/my:CompanyID", nsMgr).InnerText = "1";

//Now set the value back into the XML Field
K2.ProcessInstance.XmlFields["XXX"].Value = doc.OuterXml;

Important Note
It is important for you to understand how K2 XML fields are managed. From what I know it has not changed since K2 2003 and I explained it previously in this post. To summarize when working with an InfoPath client event the XML schema is placed in the process level XML field as well as in all activities where there is an InfoPath client event. Then depending on how you have destination users configured for your activity, the number of slots, etc. the activity level field will be used by the destination activity instance. When the activity is completed, the XML from the activity instance will be copied back up to the process level. This is done for numerous valid reasons which are out of scope of this conversation.

Here is a simple rule, if you need to change some InfoPath values prior to the user doing something with the InfoPath form add a separate activity before the InfoPath client event and make your changes there. Same with editing the XML after the InfoPath client event; put it in a separate activity.

2) Archiving an XML File

Arching XML is a pretty simple thing to do. Look at the activity below.

So a common thing you may want to do is change the view of the InfoPath form before it is archived so that when the user opens up the XML in the archive folder they will see a read-only view. Note I would not store secure information in an InfoPath form because all a user has to do is open up the XML and they can change it.

2.1) Change the InfoPath View

The Change View event is a code event that I dropped into an activity. K2 2003 had an event to do this very thing however it was simple enough to write the code. Add the SourceCode.Workflow.Common namespace to the code event.

XmlDocument xmlDoc = new XmlDocument();
XmlNode k2Node = InfoPathHelper.GetK2Node(xmlDoc);
InfoPathHelper.SetK2FieldValue(k2Node, "DocumentView", "ArchiveView");
K2.ProcessInstance.XmlFields[0].Value = xmlDoc.OuterXml;

I got this code by digging down into the InfoPath client event Windows Workflow Foundation code which is accessible through studio by right clicking the event >> selecting View Code >> Event Item. This will drive you to a WF screen where you can look at all the code K2 is using. In there I found a handy class called InfoPathHelper which was created work with the _K2 node (added by K2 to the InfoPath form). As you can see we are changing the DocumentView value to ArchiveView which in this case is the name of the read only view in the InfoPath form.

So then how is the view actually switched? Since a second view was added to the InfoPath form, you will notice that K2 will add a rule into InfoPath. This can be accessed in InfoPath designer by going to Tools >> Form Options >> Open and Save >> click on Open Behavior Rules. This is where the view will be switched.

2.3) Restarting Archived XML

It is also very easy to use the archived form in a new process instance if you have a requirement to allow the person to re-submit, re-new, etc. the process. Use the code below to clear out the Serial Number (SN) in the _K2 node prior to archiving the form.

InfoPathHelper.SetK2FieldValue(k2Node, "SN", "");

Now when the user submits the InfoPath form it will be treated as a new instance.

2.3) Archive the XML

The drag and drop on a SharePoint Documents event into the activity and the following wizard will be started.

Select the Upload Documents event.

Select K2 Field because we will be taking the XML from the process and push it to a designated location. Remember that you do not have to go to the form library where the user last worked with the XML file. At this point it has been deleted by K2 because the InfoPath XML is being managed by K2, not SharePoint.

Select the XML Field with the InfoPath XML.

Configure the Site URL, Document Library and File Name. Note that ".xml" is appended to the file name. As well, there is no hard coding here, Environment variables have been used and this is critical for moving between development, QA and production environments.

No comments: