XmlDocument objects are easy to use for navigating the DOM and copying, modifying, or inserting nodes. However, they can also use a large amount of memory to store the entire DOM of a large XML string in memory. Because of this, the
XmlWriter classes are used for stream based manipulation of an XML string.
Using the code
insert method illustrates the process of reading two strings of XML with the
XmlTextReader from the
System.Xml namespace to ensure they are both valid XML. The source XML is read to ensure its validity and then stored in a
StringBuilder object. The target XML is read, but the root element is stripped off and the name and attributes and stored in string variables. The inner XML from the target document is read and stored in another
StringBuilder object. Finally the
XmlTextWriter is used to write out the root element and its attributes with the source XML inserted before the inner XML from the target document.
Start off with the
insert method declaration.
private string insert(string sourceXml, string targetXml)
XmlTextWriter objects must be created and initialized with the sourceXml string.
System.Text.StringBuilder sb = new System.Text.StringBuilder();
System.IO.StringReader stringReader =
System.IO.StringWriter stringWriter =
System.Xml.XmlTextReader xmlReader =
System.Xml.XmlTextWriter xmlWriter =
string strValidSourceXml = String.Empty;
string strValidTargetXml = String.Empty;
string strRootName = String.Empty;
string[,] arrRootAtts = null;
The source XML is read, validated, and written into the
StringBuilder object by parsing each node with the
XmlReader and subsequently writing each node to the
StringBuilder with the
"Error parsing source XML\n\nMessage: " + e.Message,
strValidSourceXml = sb.ToString();
After reading the source, the readers and writers must be reset to parse the target XML.
sb = new System.Text.StringBuilder();
stringReader = new System.IO.StringReader(targetXml);
stringWriter = new System.IO.StringWriter(sb);
xmlReader = new System.Xml.XmlTextReader(stringReader);
xmlWriter = new System.Xml.XmlTextWriter(stringWriter);
Then the root element is broken into its components - name and attributes. The inner XML from the root is read into a string variable.
strRootName = xmlReader.Name;
int i = 0;
arrRootAtts = new string[xmlReader.AttributeCount,2];
arrRootAtts[i,0] = xmlReader.Name;
arrRootAtts[i,1] = xmlReader.Value;
strValidTargetXml = xmlReader.ReadInnerXml();
"Error parsing target XML\n\nMessage: " + e.Message,
The root node and its attributes are written out to a
StringBuilder using the
XmlWriter. The validated XML from the source and the inner XML from the target are written as children of the root node.
if (arrRootAtts != null)
for (int i = 0; i < arrRootAtts.GetLength(0); i++)
xmlWriter.WriteRaw(strValidTargetXml + strValidSourceXml);
Finally, the method returns the string from the
StringBuilder object containing the combined XML as a string.
Be aware that the
StringBuilder and the strings themselves carry some memory overhead, so it's often worth taking time to compare the two approaches for typical strings of XML and determine if the memory savings is worth the extra development effort.
In my testing, for combining two strings of XML, using the
XmlReader resulted in 1/2 the memory consumption of the
XmlDocument object is certainly more intuitive for inserting nodes into a string of XML, the
XmlWriter objects can be utilized for quickly parsing and combining large strings of XML with less memory overhead than using the
XmlDocumentFragment objects to combine two documents.