Recently, I got the chance to get my hands dirty with SharePoint Workflow. It was quite the challenge, in particular because of some oddities that, given all products were Microsoft based, I had a hard time understanding why certain things were so out of sync. One of these was the reason that the XML transmitted on the update operation from the InfoPath Task Edit form was not a document, but rather a fragment. And why the SharePoint API was ill-equipped to handle this. In the end, as with many things within our solution, this required custom code to appease both InfoPath and SharePoint.
Below is the code for completing this operation
1: XmlReaderSettings set = new XmlReaderSettings();
2: set.ConformanceLevel = ConformanceLevel.Fragment;
3:
4: using (XmlReader reader = XmlReader.Create(
5: new StringReader(afterProperties.ExtendedProperties["TakeOwnership"].ToString()), set)
6: )
7: {
8: while (reader.Read())
9: {
10: switch (reader.LocalName)
11: {
12: case REMAININGDAYS_LOCAL_NAME:
13: if (reader.Read())
14: if (int.TryParse(reader.Value, out daysRemaining))
15: reader.Read();
16: break;
17: case ISTAKEOWNERSHIP_LOCAL_NAME:
18: if (reader.Read())
19: if (bool.TryParse(reader.Value, out isTakeOwnership))
20: reader.Read();
21: break;
22: case CHANGEREMAININGWORKDAYS_LOCAL_NAME:
23: if (reader.Read())
24: if (int.TryParse(reader.Value, out changeRemainingDays))
25: reader.Read();
26: break;
27: }
28: }
29: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
I choose this example because it also shows a means to parse out multiple values coming back. The key to code is is Line #2. We are telling the XMLReader that this XML is a fragment and not a whole document, which is the default expectation. From there, knowing that the XML reader is a SAX based XML parser, we do reads checking various properties. The logic is essentially as follows:
- Perform a Read
- Check the Local (tag) name
- For a match, perform another read to get to the internal value
- If the value is not empty and parses to what we expect, perform another read to get to the end element
- When the loop comes back around, it will either be at the end of the document, or the next read will take it to the next element
This is not the most efficient means to read this XML, but it does get the job done. If there is no value passed, the Try call will fail. The code will continue to iterate until it comes to a node with a name it is expecting, at which point it will again try to read the value, or the document ends and the loop terminates.