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
...
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:
- http://msdn.microsoft.com/en-us/library/system.io.memorystream.setlength.aspx
Read more here, about stream overload of XmlTextWriter constructor:
- http://msdn.microsoft.com/en-us/library/ms162588.aspx
And this for File.WriteAllBytes:
- http://msdn.microsoft.com/en-us/library/system.io.file.writeallbytes.aspx
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());
}
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.
I'm guessing flush would do approximately what you ask for. Just build and retrieve the XML, flush, rinse, repeat ;)
Cheers.
精彩评论