Introduction To XML sub-tree processing in .NET
This article will show you how to process XML
sub-trees when using XmlReaders and XmlWriters in the C# .NET
Background of XML sub-tree processing
Being services implemented over the POX/REST (Plain
Old XML/REpresentational State Transfer) protocol, I had the disadvantage of not
being able to take advantage of the SOAP implementation in the .NET framework
but, because I had to do it myself, I would have some control over the messages.
Part of the message content belonged to the protocol
implemented by the service provider (something like SOAP), and only a small part
of it was service specific content. The service clients use DTOs (Data Transfer
Objects) which were serialized using XmlSerializers.
To make it more difficult to tamper with message
content and to gain some performance, I opted by not using XmlDocuments,
instead, I used XmlReaders and XmlWriters.
Because the messages were being handed out to
XmlSerializers (and instances of other classes), I was afraid something could
happen to the message content because XmlReaders and XmlWriters were, some
times, out of my control. I had to build something that would guarantee the
integrity of the messages (and the XmlReaders and XmlWriters being used to
Processing XML sub-tree
The requirement looked simple; guarantee that each
element of the XmlReader or XmlWriter was treated as a sub-tree and seen by
other code as a complete XML document.
Reading XML sub-tree
To implement XML sub-tree reading, I opted on
building a XmlReader derived class (XmlSubtreeReader) that would receive, on
instantiation of its objects, an instance of an XmlReader derived class from
where its current element will be used as the root of a new XmlReader.
I opted also to implement IDisposable to take
advantage of the use of using (Using in Visual Basic) blocks and to be compliant
with the implementation of the XmlReader in the .NET framework 2.0.
Example of Reading XML sub-tree
public class XmlSubtreeReader : System.Xml.XmlReader,
wrappedReader) : base()
To guarantee that the recently created XmlSubtreeReader
doesn't compromise the integrity of the wrapped XmlReader, on its instantiation,
the wrapped XmlReader's current depth is stored and used to guarantee that the
wrapped XmlReader's depth doesn't go bellow its initial value.
public override bool Read()
this.namespaceAttributeCount = 0;
this.currentNamespaceAttribute = -1;
if ((this.wrappedReader.Depth == this.initialDepth) &&
|| ((this.wrappedReader.NodeType ==
this.readerState = XmlSubtreeReader.State.EndOfFile;
On the other hand, when closing the XmlSubtreeReader,
the wrapped XmlReader should be skipped until its initial depth is reached.
public override void Close()
if (this.readerState != XmlSubtreeReader.State.Closed)
while (this.readerState !=
this.readerState = XmlSubtreeReader.State.Closed;
Writing XML sub-tree
To implement XML sub-tree writing, I opted on
building a XmlWriter derived class (XmlSubtreeWriter) that would receive, on
instantiation of its objects, an instance of an XmlWriter derived class from
where its current element will be used as the root of a new XmlWriter.
For the same reasons as with the reader, I opted on
Example of Writing XML sub-tree
public class XmlSubtreeWriter : System.Xml.XmlReader,
wrappedWriter) : base()
To guarantee that the recently created XmlSubtreeWriter
doesn't compromise the integrity of the wrapped XmlWriter, on its instantiation,
the wrapped XmlWriter's current depth is stored and used to guarantee that the
wrapped XmlWriter's depth doesn't go bellow its initial value.
public override void WriteStartElement(string prefix, string localName, string ns)
this.wrappedWriter.WriteStartElement(prefix, localName, ns);
this.currentState = this.wrappedWriter.WriteState;
The CheckWrite method is called at the beginning of
every write start method to validate if the XmlSubtreeWriter is in a valid state
In the same way, the CheckWriteEndElement method is
called in the beginning of every write end method to validate if the
XmlSubtreeWriter has reached its root.
As in sub-tree reading, when closing the
XmlSubtreeWriter, the wrapped XmlWriter should end every element until its
initial depth is reached.
public override void Close()
this.currentState = System.Xml.WriteState.Closed;