Archive for February 2008
Fluent XML Writer
Via Glenn Block I’ve found a very interesting example of a Fluent Interface for creating XML markup.
I’m not a big fan of the XmlDocument class because I usually need just to write the markup down to some stream but not caching the whole document in memory. Obviously, I decided to write a very simple fluent XmlWriter:
public class FluentXmlWriter { private XmlWriter writer; public FluentXmlWriter(XmlWriter writer) { this.writer = writer; } public XmlWriter XmlWriter { get { return this.writer; } } public FluentXmlWriter Flush() { this.writer.Flush(); return this; } public FluentXmlWriter StartElement(string localName) { this.writer.WriteStartElement(localName); return this; } public FluentXmlWriter EndElement() { this.writer.WriteEndElement(); return this; } public FluentXmlWriter Element(string localName, string value) { this.writer.WriteElementString(localName, value); return this; } public FluentXmlWriter Attribute(string localName, string value) { this.writer.WriteAttributeString(localName, value); return this; } }
It’s not a full replacement of the XmlWriter class, it doesn’t support namespaces yet and so on, but it’s certainly a good point to start with when you just need to write some markup.
My next idea was to make a writer be able to store written XML and give it back when needed. The solution was an inherited class with embedded MemoryStream and several GetX() methods for any taste:
public class MemoryXmlWriter : FluentXmlWriter { private readonly MemoryStream stream; private MemoryXmlWriter(MemoryStream stream, XmlWriterSettings settings) : base(XmlWriter.Create(stream, settings)) { this.stream = stream; } public MemoryXmlWriter(XmlWriterSettings settings) : this(new MemoryStream(), settings) { } public MemoryXmlWriter() : this(null) { } public override string ToString() { base.Flush(); using (Stream copy = GetReadOnlyStream()) using (StreamReader reader = new StreamReader(copy)) { return reader.ReadToEnd(); } } public byte[] ToArray() { base.Flush(); return this.stream.ToArray(); } public XmlDocument ToXmlDocument() { base.Flush(); using (Stream copy = GetReadOnlyStream()) { XmlDocument xml = new XmlDocument(); xml.Load(copy); return xml; } } public Stream GetReadOnlyStream() { base.Flush(); return new MemoryStream( this.stream.GetBuffer(), 0, (int)this.stream.Length, false); } }
The MemoryXmlWriter can also give you an XmlDocument, but of course you can’t make synchronized changes to both the writer and the XmlDocument.
Finally, usage looks like this:
MemoryXmlWriter writer = new MemoryXmlWriter(); writer.StartElement("root") .StartElement("item") .Attribute("name", "value") .Element("child", "Text text text") .EndElement() .EndElement(); Console.WriteLine(writer.ToString());