Dealing With Namespaces in XmlWriter

XmlTextWriter comes in really handy when all you need is serial XML output. With simple commands you can create well formed and nicely indented document:

using (var xw = new XmlTextWriter(stream)) {
    xw.WriteStartDocument(true);
    xw.Formatting = Formatting.Indented;
	xw.WriteStartElement("abc:Group");
    xw.WriteAttributeString("xmlns:abc", "http://www.example.com/something/");
    xw.WriteStartElement("abc:Element");
    ...
}

However, XmlTextWriter has limited formatting capabilities. If you want LF instead of Windows-style CRLF you will need to use something else. For me that “something else” was XmlWellFormedWriter.

To get XmlWellFormedWriter you just ask XmlWriter to create one for you. Direct replacement code would look close to this:

var settings = new XmlWriterSettings() {
	Encoding = new UTF8Encoding(false),
	Indent = true,
	IndentChars = "    ",
	NewLineChars = "\n"
};
using (var xw = XmlWriter.Create(stream, settings)) {
    xw.WriteStartDocument(true);
	xw.WriteStartElement("abc:Group");
    xw.WriteAttributeString("xmlns:abc", "http://www.example.com/something/");
    xw.WriteStartElement("abc:Element");
    ...
}

And, lo and behold, this code causes ArgumentException (Invalid name character in 'abc:Group'. The ':' character, hexadecimal value 0x3A, cannot be included in a name.). With XmlWellFormedWriter there is no cheating and manually creating XML namespaces. You can still use them, but code will look a bit different:

using (var xw = XmlWriter.Create(stream, settings)) {
    xw.WriteStartDocument(true);
    xw.WriteStartElement("abc", "Group", "http://www.example.com/something/");
    xw.WriteStartElement("abc", "Element", null);
    ...
}

PS: Yes, there is no guarantee that XmlWriter.Create will give you XmlWellFormedWriter. However, it will surely give you something close enough for this code to work.