Search code examples
c#xmlxmltextwriter

Reusing XmlTextWriter class


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
...

Solution

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