Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write an XElement to an XmlWriter that has contents already

Im am trying to write a very large XML document in a streaming manner. Instead of writing one XDocument or XElement, which might consume too much memory, the idea is that I write the root element using an XmlWriter, and then write many XElements to that writer, one after the other, before closing the root element. However, I have not found a way to do so. To simulate the problem, consider the following code:

using System;
using System.Xml;
using System.Xml.Linq;

internal static class Program
{
    private static void Main()
    {
        var settings = new XmlWriterSettings { Encoding = Console.OutputEncoding, Indent = true };

        using (var writer = XmlWriter.Create(Console.Out, settings))
        {
            const string namespaceUri = "http://example.com/";

            writer.WriteStartElement("x", "root", namespaceUri);

            XNamespace x = namespaceUri;

            XElement element = new XElement(x + "test");

            element.Save(writer);

            writer.WriteEndElement();
        }

        Console.WriteLine();
    }
}

The program fails on the element.Save(writer); line, with an InvalidOperationException: "Token StartDocument in state Element Start Tag would result in an invalid XML document".

The reason for this exception is clear: the XElement is assuming it has the entire XmlWriter all for itself, and calls WriteStartDocument() on it. Obviously that fails, as the document was already started, and already has a start element in it.

Note that I would expect this behavior if I were to use XDocument, but I'm not, I'm using XElement.

An alternative would be to write

            writer.WriteRaw(element.ToString());

instead of

            element.Save(writer);

It works, in the sense that it doesn't crash, and in the sense that it produces correct XML.

However, I don't like it, because it doesn't produce the clean and efficient XML I am looking for (it needlessly repeats the namespace declarations). It obviously couldn't, as the XElement is serialized without the context that the XmlWriter should provide. The fact that it needs an intermediary string to work is not even the biggest problem.

How should I write many XElement instances independently, one after the other, to an XmlWriter, in an efficient way, so that clean XML is produced? Or is this not possible?

like image 478
Kris Vandermotten Avatar asked Dec 17 '13 13:12

Kris Vandermotten


1 Answers

If you change element.Save(writer); to element.WriteTo(writer); there is no exception and it seems written to the console.

like image 106
Laszlo Boke Avatar answered Sep 27 '22 16:09

Laszlo Boke