As I have mention in the past LINQ to XML is a great way to manipulate the XML data out of an InfoPath form. I thought I would show how you can also use the same technique to work with the data of a form saved to a form library which launches a workflow (although you could apply this technique to the association or task forms as well). The first thing we need to do is get the XML of the InfoPath initiation form, before we can work with it.
For the purpose of my example, my OnWorkflowActivated activity writes to a public SPWorkflowActivationProperties property called workflowProperties. In my Invoked event handling method of my OnWorkflowActivated activity, we use the Item object on my workflowProperties to open the file and get the XML. You can then use the File object along with OpenBinary() to get the raw bytes of the XML.
byte xmlBytes = workflowProperties.Item.File.OpenBinary();
You can then takes those bytes and read them into a regular string.
string xmlString = System.Text.Encoding.UTF8.GetString(xmlBytes);
if (xmlString == (char)0xfeff)
xmlString = xmlString.Substring(1);
If you are curious about the 0xfeff business that is used to deal with the byte-order mark character in Unicode. I picked up this trick from another post somewhere, but I can’t remember where currently.
Now we need to get the XML string into an XDocument class so that we can query it and manipulate it. Since we have a string, we will need to create a StringReader to read it.
XDocument documentsXml = XDocument.Load(new System.IO.StringReader(xmlString));
If you wanted to work with the Association form instead of the form that started the workflow, you would use a line like the following. The InitiationData property of the SPWorkflowActivationProperties object provides XML that can be loaded into the XDocument class.
XDocument documentsXml = XDocument.Load(workflowProperties.InitiationData);
InfoPath documents always have a namespace defined for my so we need to use the XNamespace object for any future references inside the InfoPath form.
XNamespace documentNamespace = "http://schemas.microsoft.com/office/infopath/2003/myXSD/2098-05-03T16:48:38";
At this point you can start using LINQ to XML to get the data you need out of the InfoPath form. For example, if I had a field called my:FirstName at the root of the document. I could use something like the following to get the value.
string firstName = documentsXml.Root.Element(documentNamespace + "FirstName").Value;
If you are working with other data types, you can always cast it like this.
int customerId = int.Parse(documentsXml.Root.Element(documentNamespace + "CustomerId").Value);
In my example from last week, you saw how you could use LINQ to XML to iterate through a repeating table. As another example to iterate through a repeating table called Items with an element of Item, you could do something like the following:
var items = from item in documentsXml.Root.Element("Items").Elements("Item")
foreach (var item in items)
In this case, I use LINQ to return an IEnumberable<XElement> representing each repeating item. I can then use this in a foreach loop to print out the results. Yes I know you wouldn’t use Console.Writeline in a workflow, but you get the point here. LINQ to XML really offers a lot of flexibility to manipulate the XML data inside a form. Hopefully, it will make your experience with InfoPath and workflow a better one.