Sergey Shishkin

on agile software development

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());

 

Sample Code

Technorati Tags: ,,
Advertisements

Written by Sergey Shishkin

28.02.2008 at 18:11

Posted in Development