XML declarations in Linq to XML

The new XML API that comes with Linq to XML has some peculiar ways of handling the XML declaration (aka the XML prolog). Take a look at this sample:

Process[] processes = Process.GetProcesses();

XDocument document = new XDocument(

  new XDeclaration(“1.0”, “utf-8”, “true”),

  new XElement(“processes”,

    new XAttribute(“total”, processes.Count()),

    from process in processes

    select new XElement(“process”,

      new XAttribute(“id”, process.Id),

      process.ProcessName)

    )

  );

Console.WriteLine(document);

You might expect the XML declaration to be written to the console, but the actual output is without.

OutputLinqToXmlDeclaration

The XDocument.Save method on the other hand will always output the prolog. You can specify a filename or TextWriter to save your XML string to. Since Console.Out is a TextWriter instance simply change the last line to

document.Save(Console.Out);

and watch the output change to:

OutputLinqToXmlDeclaration2

The prolog is now:

<?xml version=”1.0″ encoding=”IBM437″?>

So, what gives? We specified a certain encoding, but the encoding of the TextWriter instance is used. This is definitely something to take into account, as you cannot rely on your XDeclaration values to prevail.

Fixing the above is done by setting the output encoding explicitly:

Console.OutputEncoding = new UTF8Encoding();

document.Save(Console.Out);

What if you want to have a string value with the prolog?

// Write XML to in-memory stream

MemoryStream stream = new MemoryStream();

XmlTextWriter writer =
  new XmlTextWriter(stream, new UTF32Encoding());

document.Save(writer);

 

// Read back string from stream

writer.Flush();

stream.Position = 0;

StreamReader reader = new StreamReader(stream);

string xml = reader.ReadToEnd();

Console.WriteLine(xml);

Console.WriteLine(reader.ReadToEnd());

Also, when you specify the XML version to be 1.1 in the declaration, the output will still give you version=”1.0″. Reflector reveals that the all overloads of the XDocument.Save implementation eventually call XmlTextWriter.WriteStartDocument that has the following line:

builder.Append(string.Concat(new object[] { “version=”, this.quoteChar, “1.0”, this.quoteChar }));

This clearly shows the hardcoded 1.0 version. Your XDeclaration’s version is ignored.

BTW, if you would like to get rid of the XML declaration when you use the Save method, you need a bit of a work-around. The Save methods accepts a SaveOptions enumeration, but this enum only lets you disable the formatting of the XML. Here’s how you would omit the declaration:

// Write XML to in-memory stream

MemoryStream stream = new MemoryStream();

XmlWriterSettings settings = new XmlWriterSettings();

settings.OmitXmlDeclaration = true;

XmlWriter writer = XmlWriter.Create(stream, settings);

document.Save(writer);

// Rest is same

There you go.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s