Overview
With an InfoPath form as a workflow list item, we can gain access to its data via workflowProperties.Item. However, there is no native support in MOSS workflows for repeating table/sections. So we developers have to write custom helper method to gain this function.
Reference
Julie's Office Dev Blog : InfoPath 2007, SharePoint Workflows and Whatnot
Code Snippet
Parse repeating data in an InfoPath form (normally this is the submit form)
This code is copied form "MOSS SDK Workflow Example - Inter-System Purchase Order" by Microsoft
1 private void GetLineItemsFromOrder(out DateTime dueDate, out LineItem[] items)
2 {
3 List<LineItem> LineItems = new List<LineItem>();
4
5 //Load the bytes for the document
6 byte[] xmlBytes = this.workflowProperties.Item.File.OpenBinary();
7
8 //Remove the BOM from the xml file so XmlDocument Can handle it
9 string Xml = System.Text.Encoding.UTF8.GetString(xmlBytes);//, 1, xmlBytes.Length - 1);
10 if (Xml[0] == (char)0xfeff)
11 {
12 Xml = Xml.Substring(1);
13 }
14
15 XmlDocument Document = new XmlDocument();
16 Document.LoadXml(Xml);
17
18 XmlElement RootElement = Document.DocumentElement;
19
20 XmlNamespaceManager Manager = new XmlNamespaceManager(Document.NameTable);
21 Manager.AddNamespace("my", RootElement.NamespaceURI);
22
23 //Get Due Date
24 dueDate = DateTime.Parse(RootElement.SelectSingleNode("//my:ShipBy", Manager).InnerText);
25
26 //Get Order Details
27 XmlNodeList OrderItems = RootElement.SelectNodes("//my:OrderItem", Manager);
28 foreach(XmlNode OrderItem in OrderItems)
29 {
30 LineItem LineItem = new LineItem();
31 LineItem.ProductID = OrderItem.SelectSingleNode("my:ProductID", Manager).InnerText;
32 LineItem.Quantity = OrderItem.SelectSingleNode("my:Quantity", Manager).InnerText;
33 LineItems.Add(LineItem);
34 }
35
36 items = LineItems.ToArray();
37
38 }
Passing repeating data to an InfoPath task form
In MOSS workflows, InfoPath task form is receiving data by setting up a secondary data source bound to a "ItemMetadata.xml" file. Unfortunately, repeating data schema is not supported in this file.
In this example, I will try to send the data in original list item file to the InfoPath task form, I am sending over the actual xml of the original list item file as a string value in the ItemMetadata. To get the actual xml of the original list item file, we can use the code snippet extracted from above example:
//Load the bytes for the document
byte[] xmlBytes = this.workflowProperties.Item.File.OpenBinary();
//Remove the BOM from the xml file so XmlDocument Can handle it
string Xml = System.Text.Encoding.UTF8.GetString(xmlBytes);//, 1, xmlBytes.Length - 1);
if (Xml[0] == (char)0xfeff)
{
Xml = Xml.Substring(1);
}
Here we get the string variable "Xml" as the xml of the original list item file, and we can pass it to ItemMetadata. Next step is to parse this xml string into repeating data in the InfoPath task form, to do this, we have to write custom code in the InfoPath task form, will require the form to be "Fully Trust". The code snippet of the task form is as below:
public void FormEvents_Loading(object sender, LoadingEventArgs e)
{
string xmlSource = this.DataSources["ItemMetadata"].CreateNavigator().SelectSingleNode("/z:row/@ows_repeatData", NamespaceManager).Value;
XmlDocument nodeDoc = new XmlDocument();
nodeDoc.LoadXml(xmlSource);
XPathNavigator sectionNode = this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields", NamespaceManager);
string ns = sectionNode.NamespaceURI;
//we need to delete the default one Infopath adds in
this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:repeatDetail", NamespaceManager).DeleteSelf();
foreach (XmlNode thisNode in nodeDoc.DocumentElement.ChildNodes)
{
if ((thisNode.LocalName == "repeatDetail"))
{
//Start populating the data
XmlWriter write = sectionNode.AppendChild();
write.WriteStartElement("my", "repeatDetail", ns);
write.WriteElementString("my", "DataColumn1", ns, "Value1");
write.WriteElementString("my", "DataColumn2", ns, "Value2");
write.WriteElementString("my", "DataColumn3", ns, "Value3");
write.WriteElementString("my", "DataColumn4", ns, "Value4");
write.WriteEndElement();
write.Close();
}
}
}