Reusing XmlTextWriter class

1.6k views Asked by At

Is it possible to reuse the same instance of XmlTextWriter class for generating more xml documents? I mean something like this:

XmlTextWriter writer = new XmlTextWriter();
writer.WriteStartDocument();
writer.WriteStartElement("Message1");
writer.WriteEndElement();
writer.WriteEndDocument();

// do something with xml created
...

writer.Reset() // ?
writer.WriteStartDocument();
writer.WriteStartElement("Message2");
writer.WriteEndElement();
writer.WriteEndDocument();
// do something with xml created
...
3

There are 3 answers

2
Matías Fidemraizer On BEST ANSWER

Easy answer: yes, it's possible to do that.

But this would be achived if underlying stream isn't pointing to a file. MemoryStream could be a good example of that.

As MemoryStream saves the stream "in memory", you can write a lot of XML files with your XmlTextWriter and after ending each document, do a MemoryStream.ToArray() and give it as argument for File.WriteAllBytes.

After writing all bytes, you'd clear your memory stream.

You can clear your memory stream by calling MemoryStream.SetLength method and give 0 as length:

Read more here, about stream overload of XmlTextWriter constructor:

And this for File.WriteAllBytes:

About some concerns when reusing an XmlTextWriter

Some years ago @NigelTouch raised a concern on some comment:

The problem I found is that if an exception is thrown part-way through, for example after WriteStartElement(), then even though you Flush() the Writer and set the Stream length to 0, the Writer remains in a WriteState of Element. When you start the next document, it begins with a closing ">" (for example). Avoid reuse

And some hours ago, @Mike-EEE got into the same issue:

Please provide working code of an example solution. I am running into the same problem as Nigel describes

BTW, a bit of trial-error got me to recover a given XmlTextWriter to reuse it as many times as you want:

    using(MemoryStream stream = new MemoryStream())
    using(StreamReader streamReader = new StreamReader(stream))
    using(XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8))
    {
        writer.WriteStartDocument(true);
        writer.WriteStartElement("a");

        try 
        {
            throw new Exception();
        }
        catch 
        {
            // This line makes de magic: ending the document
            // avoids the issue mentioned by @NigelTouch
            writer.WriteEndDocument();
            writer.Flush();
            stream.SetLength(0);
        }


        writer.WriteStartDocument(true);
        writer.WriteStartElement("b");
        writer.WriteEndElement();
        writer.Flush();

        stream.Position = 0;

        Console.WriteLine(streamReader.ReadToEnd());

    }
0
Oded On

The XmlTextWriter class:

Represents a writer that provides a fast, non-cached, forward-only way of generating streams or files containing XML data that conforms to the W3C Extensible Markup Language (XML) 1.0 and the Namespaces in XML recommendations.

(emphasis mine)

The class doesn't provide a Reset or any similar function, nor does it give access to the underlying stream. If you have access to the underlying stream yourself, you can reset that stream yourself.

This all means that it is not possible to reuse it directly.

1
Berry Langerak On

I'm guessing flush would do approximately what you ask for. Just build and retrieve the XML, flush, rinse, repeat ;)

Cheers.