How to add an node to an XML Document (via a C# helper that can be called in an expression shape from an orchestration).
First example (uses AppendChild):
<code>
public static XmlDocument AddExceptionNodeToTMXML(XmlDocument TMXMLDocIn, Exception ex)
{
// three import fields in System.Exception are ex.Message, ex.StackTrace, ex.Source
// then there is an Ex.InnerException
XmlDocument xmlDocNewTMXML = new XmlDocument();
xmlDocNewTMXML.LoadXml(TMXMLDocIn.OuterXml); // make sure we don't update the original TMXMLDocIn
string errMessage = "";
string errSource = "";
string errStackTrace = "";
string xml;
if (ex.InnerException == null)
{
// if not nested exceptions, do not number them.
errMessage = ex.Message;
errStackTrace = ex.StackTrace;
errSource = ex.Source;
}
else
{
// loop through all the nested exceptions and concatenate them into single long string variables
System.Exception innerEx = ex;
int loopCounter = 0;
while (innerEx != null)
{
// number the nested exceptions
loopCounter++;
string separator = "";
if (loopCounter > 1)
separator = ";";
errMessage = errMessage + separator + "n Ex:" + loopCounter + ") " + innerEx.Message;
errStackTrace = errStackTrace + separator + "n Ex:" + loopCounter + ") " + innerEx.StackTrace;
errSource = errSource + separator + "n Ex:" + loopCounter + ") " + innerEx.Source;
innerEx = innerEx.InnerException;
}
}
// Added CDATA clauses below, because the err fields may have
// ampersand, less-than, greater than, or other problem characters that cause the xmlDoc.Load to fail.
xml =
@"<exs:Exceptions xmlns:exs='http://YourSchemaNamespace.Exceptions'>" +
"<ex:Exception index='1' id='1' type='' xmlns:ex='http://YourSchemaNamespace.Exception'>" +
" <messageText><![CDATA[" + errMessage + "]]></messageText>" +
" <source><![CDATA[" + errSource + "]]></source>" +
" <stackTrace><![CDATA[" + errStackTrace + "]]></stackTrace>" +
"</ex:Exception>" +
"</exs:Exceptions>";
XmlDocument exceptionXML = new XmlDocument();
exceptionXML.LoadXml(xml);
string strXPathRoot = "/*[local-name()='TMXML' and namespace-uri()='http://YourSchemaNamespace.MainSchema']";
XmlNode nodeTMXML = xmlDocNewTMXML.SelectSingleNode(strXPathRoot);
string strExXPathRoot = "/*[local-name()='Exceptions' and namespace-uri()='http://YourSchemaNamespace.Exceptions']";
XmlNode nodeExceptions = exceptionXML.SelectSingleNode(strExXPathRoot);
nodeTMXML.AppendChild(xmlDocNewTMXML.ImportNode(nodeExceptions, true));
return xmlDocNewTMXML;
}
</code>
Second example (uses CreateElement)
<code>
// This can be called from a BusinessRule which passes a TypedXmlDocument
// instead of a normal XmlDocument
public static void AddItineraryStep(TypedXmlDocument txd, string stepName, string activityPolicy)
{
// can we find the XPath indicate d?
string strXPathRoot = "//*[local-name()='ItinerarySteps']";
XmlNode node = LocateXPath(txd, strXPathRoot);
if (null == node)
{
throw new Exception("AddItineraryStep: XPath did not return a valid node, XPath=" +
strXPathRoot + " XML=" + txd.Document.OuterXml);
};
// determine the root node for the document
// if the XPath selects the TXD, it will have no root if it is an XmlDocument
// in that case, simply use the document from the TXD
XmlDocument root = node.OwnerDocument;
if (null == root)
{
// if the XPath selects the TXD, it may
// so fix accordingly
root = txd.Document as XmlDocument;
if (null == root) return;
}
// create a new node and add it in
string nodeName = "ItineraryStep";
XmlElement newNode = root.CreateElement(nodeName);
node.AppendChild(newNode);
// Not sure why ImportNode not available. Seems like it would be easier
//node.AppendChild(txd.Document.ImportNode(nodeItineraryStep, true));
//strXPathRoot = "/*[local-name()='Header']/*[local-name()='Itinerary']/*[local-name()='ItineraryStep']";
strXPathRoot = "//*[local-name()='ItineraryStep']";
node = LocateXPath(txd, strXPathRoot);
if (null == node)
{
throw new Exception("AddItineraryItem: XPath did not return a valid node, XPath=" +
strXPathRoot + " XML=" + txd.Document.OuterXml);
};
XmlElement newSubNode;
nodeName = "name";
newSubNode = root.CreateElement(nodeName);
newSubNode.InnerText = stepName;
newNode.AppendChild(newSubNode);
nodeName = "status";
newSubNode = root.CreateElement(nodeName);
newSubNode.InnerText = "PENDING";
newNode.AppendChild(newSubNode);
nodeName = "errorType";
newSubNode = root.CreateElement(nodeName);
// leave value to empty-string (no need to set InnerText)
newNode.AppendChild(newSubNode);
nodeName = "activityPolicy";
newSubNode = root.CreateElement(nodeName);
newSubNode.InnerText = activityPolicy;
newNode.AppendChild(newSubNode);
}
internal static XmlNode LocateXPath(TypedXmlDocument txd, string xPath)
{
// does the TXD contain a node?
XmlNode parent = txd.Document;
if (null == parent) return null;
// is there an XPath specified? if not, return the parent
if ((xPath == null) || (xPath == string.Empty)) return parent;
// return the first node that the XPath points to
return parent.SelectSingleNode(xPath, txd.NamespaceManager);
}
</code>