Welcome to palaso.org
Website of the Payap Language Software Development Group
XML indentation in .Net
Author Tim
Upon integration of Chorus into WeSay and more specifically in using a DVCS (specifically Mercurial) to manage WeSay’s XML encoded .lift file, the exact format of that file has taken on a new importance. Because Mercurial (and Chorus at this point) uses a standard line diffing tool to express the difference between two revisions, line breaks, indentations and other white space have suddenly become an issue where they normally are not in XML documents.
As it turns out formatting XML in .net is not entirely trivial. Though the XMLWriter and XMLReader as well as their respective xmlWriterSettings and XmlReaderSettings have various switches for enabling and disabling indentation and linebreaking on attributes, these are bound together by subtle interactions which I hope to clarify in this post.
First some background:
The indentation and whitespace in a given XML file can be of interest for at least two reasons:
- line differs typically care about whitespace and the name itself bears witness to the importance of newlines.
- readability. It’s much easier for a human being to read a nicely formatted XML file.
In WeSay the .lift file is frequently created from two seperate files. First, a valid .lift file and secondly an xml fragment file. Each time an entry is added or modified these two files are merged to form the new .lift file. For this reason we are interested in the interaction between an XmlReader and an XmlWriter that outputs said readers data.
As an example we will use some very simple XML rather than an actual lift entry as that construct is unnecassarily complex for this discussion.
Here are the two source files:
File 1:
<one at1="at1" at2="at2"> <two> <three at1="3at1" at2="3at2" /> </two> </one>
File 2:
<four at1="at1" at2="at2"> <five> <six at1="3at1" at2="3at2" /> </five> </four>
Here is our envisioned result:
<?xml version="1.0" encoding="utf-8"?><document> <one at1="at1" at2="at2"> <two> <three at1="3at1" at2="3at2" /> </two> </one> <four at1="at1" at2="at2"> <five> <six at1="3at1" at2="3at2" /> </five> </four></document>
All of these files have been written with indentation and new lines for each element and attribute. This makes for ok readability and should keep our diff files nice and small.
The first thing we are going to try is to see what happens when we start with completely unformatted input files, default readers and a default writer:
File 1:
<one at1="at1" at2=""at2""><two><three at1="3at1" at2="3at2" /></two></one>
File 2:
<four at1="at1" at2=""at2""><five><six at1="3at1" at2="3at2" /></five></four>
And the code goes something like this:
XmlReaderSettings readerSettings = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
XmlWriterSettings writerSettings = new XmlWriterSettings
{
ConformanceLevel = ConformanceLevel.Document
};
XmlReader reader = XmlReader.Create(stream0, readerSettings);
XmlWriter writer = XmlWriter.Create(stream1, writerSettings);
while (!reader.EOF)
{
writer.WriteNode(reader, true);
}
With these settings the resulting file looks like this:
{
Indent = Indent,
NewLineOnAttributes = newLineOnAttribute,
ConformanceLevel = ConformanceLevel.Document
};
Resulting file:
<?xml version="1.0" encoding="utf-8"?><document> <one at1="at1" at2="at2"> <two> <three at1="3at1" at2="3at2" /> </two> </one> <four at1="at1" at2="at2"> <five> <six at1="3at1" at2="3at2" /> </five> </four></document>
*sigh*… beautiful.
But being geeks we just can’t halp but fix something that ain’t broke. So inspite of this beautiful result we now want to try and fix the the source file. This isn’t entirely unreasonable considering you may want to look at the source file while debugging and it would be nice if it were a bit more legible. So just for kicks, let’s see what happens when we put a single line break in the source file.. say after the
File 1:
<one at1=""at1"" at2=""at2""><two><three at1=""3at1"" at2=""3at2""></three></two></one>
Resulting File:
<?xml version="1.0" encoding="utf-8"?><document> <one at1="at1" at2="at2"> <two><three at1="3at1" at2="3at2" /></two> </one> <four at1="at1" at2="at2"> <five> <six at1="3at1" at2="3at2" /> </five> </four></document>
?!!? what happened?! Not only do we have a line break after the
This brings us to our first interesting observation: Whitespace in a source document causes the writer to ignore it’s Indent Attribute until the containing element of the whitespace (in our case
<?xml version="1.0" encoding="utf-8"?><document> <one at1="at1" at2="at2"> <two> <three at1="3at1" at2="3at2"></three></two> </one> <four at1="at1" at2="at2"> <five> <six at1="3at1" at2="3at2" /> </five> </four></document>
Interestingly, you’ll notice that this is not the case for the NewLineOnAttribute Property of the XmlWriterSettings. This is even more interesting when you consider that this property is ignored UNLESS the Indent Property is TRUE. here it is straight from the horses mouth (i.e. MSDN): This setting has no effect when the Indent property value is false.
Ok.. so we’ve established that whitespace is an issue. The easiest way to get around this is to instruct the reader to ignore whitespace so that the writer doesn’t get too clever on us:
XmlReaderSettings readerSettings = new XmlReaderSettings
{
IgnoreWhitespace = true,
ConformanceLevel = ConformanceLevel.Fragment
};
So now we are back on track and looking good! To celebrate, let’s tell the world how happy we are! Let’s write a string into our first file that will proclaim our joy! Of course we will do this without spaces.. just in case.
File 1:
<one at1=""at1"" at2=""at2""><two>I'mSoHappy<three at1=""3at1"" at2=""3at2""/></two></one>
Resulting file:
<?xml version="1.0" encoding="utf-8"?><document> <one at1="at1" at2="at2"> <two>I'mSoHappy<three at1="3at1" at2="3at2" /></two> </one> <four at1="at1" at2="at2"> <five> <six at1="3at1" at2="3at2" /> </five> </four></document>
Arrrgh! It did it again!!! So here is observation number two: A text node in a source document causes the writer to ignore it’s Indent Attribute until the containing element of the text node (in our case
Finally, WeSay uses an XPathNavigator in some places and in the course of my testing I noticed that XmlWriter.WriteNode() behaves slightly different when it is passed an XPathNavigator rather than an XmlReader. Specifically, it seems to always ignore whitespace. So passing an XmlReader (with IgnoreWhitespace = false) to WriteNode for the first file and an XPathDocument for the second file where the files look like this:
File 1:
<one at1="at1" at2="at2"><two><three at1="3at1" at2="3at2"/></two></one>
File 2:
<four at1="at1" at2="at2"><five><six at1="3at1" at2="3at2" /></five></four>
Results in a final file looking like this:
<?xml version="1.0" encoding="utf-8"?><document> <one at1="at1" at2="at2"> <two><three at1="3at1" at2="3at2" /></two> </one> <four at1="at1" at2="at2"> <five> <six at1="3at1" at2="3at2" /> </five> </four></document>
Here’s an outline of the code:
XmlReaderSettings readerSettings = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
XmlWriterSettings writerSettings = new XmlWriterSettings
{
ConformanceLevel = ConformanceLevel.Document
};
XmlReader reader = XmlReader.Create(stream0, readerSettings);
XmlReader reader2 = XmlReader.Create(stream0, readerSettings);
XmlDocument document = new XmlDocument();
document.Load(reader2);
XmlWriter writer = XmlWriter.Create(stream1, writerSettings);
while (!reader.EOF)
{
writer.WriteNode(reader, true);
}
writer.WriteNode(document.CreateNavigator(), true);
Note that this is the case even when you create an XmlDocument from an XmlReader with IgnoreWhistespace = false.
So that about wraps it up. This was not meant to be an exhaustive study of all the Xml- Reader/Writer/Document/WrietSettings/ReaderSettings/XPathNavigator interactions so if you find anything else unusual or that I grossly misrepresented something please feel free to let me know!
Purchase Discounted Chanel Bags Online In Australia
Purchase Discounted Replica Chanel Shoes
Purchase Cheap Chanel Bags In Uk
Buy Discounted Replica Chanel Shoes In Ireland
Purchase Designer Replica Chanel Online In Canada
Replica Chanel Bags In Usa
Buy Cheap Designer Replica Chanel Shoes Online
Purchase Cheap Replica Chanel Shoes Online
Buy Discounted Replica Chanel Bags In Uk
Purchase Discounted Replica Chanel Bags In Canada
Buy Discounted Replica Chanel Online In Uk
Chanel Handbags In Australia
Discounted Chanel In Canada
Buy Fake Chanel Shoes Online In Usa
Discounted Chanel Bags Online In Canada
Purchase Discounted Replica Chanel In Usa
Purchase Cheap Designer Replica Chanel Bags Online
Buy Cheap Replica Chanel Bags In Ireland
Buy Fake Chanel Online In Uk
Cheap Chanel Shoes Online In Australia
Buy Cheap Designer Replica Chanel Bags In Australia
Purchase Chanel Bags Online In Canada
Cheap Designer Replica Chanel Shoes In Canada
Discounted Fake Chanel Shoes Online In Ireland
Discounted Chanel Shoes Online In Usa
Discounted Chanel Bags Online
Purchase Fake Chanel Online In Usa
Buy Cheap Replica Chanel Handbags Online
Cheap Chanel Online In Usa
Purchase Discounted Fake Chanel Handbags In Uk
Cheap Fake Chanel Bags Online In Usa
Discounted Fake Chanel Shoes In Ireland
Discounted Chanel Shoes Online In Canada
Chanel Handbags Online In Canada
Purchase Cheap Replica Chanel Online In Ireland
Purchase Designer Replica Chanel In Ireland
Purchase Cheap Designer Replica Chanel Shoes In Uk
Buy Fake Chanel Handbags
Buy Cheap Chanel Shoes Online In Uk
Cheap Designer Replica Chanel Bags In Australia
Discounted Designer Replica Chanel Bags In Uk
Fake Chanel
Buy Cheap Chanel Shoes In Canada
Discounted Fake Chanel Bags
Purchase Discounted Fake Chanel Shoes Online In Usa
Purchase Discounted Designer Replica Chanel Bags In Ireland
Buy Cheap Chanel In Usa
Purchase Designer Replica Chanel Handbags In Usa
Chanel In Australia
Purchase Discounted Designer Replica Chanel Shoes In Ireland
Buy Discounted Chanel Shoes In Canada
Purchase Replica Chanel Shoes Online In Uk
Fake Chanel Handbags In Australia
Purchase Fake Chanel In Uk
Purchase Cheap Fake Chanel In Usa
Buy Chanel Bags In Usa
Designer Replica Chanel Shoes In Canada
Designer Replica Chanel Bags In Ireland
Buy Discounted Replica Chanel
Buy Designer Replica Chanel Shoes Online
Chanel Online In Usa
Purchase Cheap Fake Chanel Online In Australia
Purchase Cheap Fake Chanel Bags
Replica Chanel Online In Ireland
Purchase Replica Chanel Bags Online In Usa
Cheap Fake Chanel Handbags Online In Ireland
Purchase Discounted Designer Replica Chanel Bags Online In Usa
Replica Chanel Online
Purchase Fake Chanel Shoes Online In Ireland
Buy Cheap Fake Chanel Bags In Uk
Purchase Cheap Chanel In Usa
Cheap Replica Chanel Shoes Online In Canada
Replica Chanel Bags In Canada
Cheap Chanel Handbags Online In Australia
Purchase Cheap Chanel Shoes Online In Australia
Purchase Discounted Designer Replica Chanel Handbags In Usa
Replica Chanel Bags In Uk
Designer Replica Chanel Shoes Online
Purchase Discounted Chanel Handbags In Usa
Discounted Replica Chanel Handbags Online
Buy Discounted Fake Chanel Shoes Online In Uk
Buy Discounted Chanel Shoes Online In Uk
Purchase Cheap Chanel In Ireland
Purchase Discounted Designer Replica Chanel In Ireland
Buy Replica Chanel Bags Online In Ireland
Purchase Discounted Fake Chanel Bags In Australia
Purchase Fake Chanel Handbags Online In Australia
Purchase Cheap Chanel Handbags In Canada
Cheap Replica Chanel Handbags In Ireland
Purchase Discounted Fake Chanel Handbags Online In Canada
Purchase Fake Chanel Shoes Online In Canada
Designer Replica Chanel Handbags In Usa
Purchase Discounted Designer Replica Chanel Bags In Canada
Cheap Chanel Shoes In Australia
Purchase Replica Chanel Handbags
Buy Cheap Designer Replica Chanel Handbags Online In Uk
Cheap Replica Chanel Handbags Online In Australia
Replica Chanel Online In Uk
Buy Cheap Designer Replica Chanel Online
Purchase Cheap Replica Chanel Shoes
Cheap Replica Louis Vuitton Handbags
Buy Cheap Fake Louis Vuitton Handbags
Discounted Replica Jimmy Choo
Discounted Replica Prada Handbag Online
Cheap Designer Replica Lv
Buy Discounted Designer Replica Givenchy Online
Discounted Designer Replica Miu Miu Online
Designer Replica Dg Shoes Online
Discounted Valentino
Buy Cheap Replica Alexander Mcqueen Shoes
Cheap Designer Replica Balenciaga Online
Buy Cheap Fake Dolce Gabbana Shoes
Buy Cheap Replica Burberry Handbags
Buy Discounted Designer Replica Prada Handbag Online
Buy Cheap Fake Hermes Handbags
Buy Cheap Prada
Replica Salvatore Ferragamo Handbags Online
Discounted Fake Bottega Veneta Handbag Online
Buy Discounted Replica Burberry Shoes Online
Replica Gucci Shoes Online
Buy Cheap Replica 3.1 Phillip Lim Handbag Online
Designer Replica Versace
Discounted Designer Replica Lv Handbag Online
Buy Discounted Replica Marc Jacobs Handbag Online
Cheap Replica Celine
Discounted Fake Vivienne Westwood Shoes
Buy Versace Handbags Online
Buy Discounted Fake Ysl Shoes Online
Buy Dg Handbag Online
Buy Cheap Replica Lv Handbags Online
Buy Christian Dior Handbag Online
Buy Fake Dg Handbag Online
Buy Discounted Designer Replica Anya Hindmarch Handbag
Discounted Chanel
Cheap Designer Replica Tory Burch Online
Fake Christian Louboutin Shoes
Discounted Fake Givenchy Handbags Online
Discounted Replica Balenciaga Handbag Online
Buy Cheap Fake 3.1 Phillip Lim Handbag Online
Designer Replica Marc Jacobs Online
Cheap Designer Replica Valentino Handbag
Discounted Replica Marni
Discounted Alexander Wang Online
Manolo Blahnik Shoes
Buy Designer Replica Versace Handbags Online
Cheap Replica Cartier Handbag
Buy Miu Miu Online
Buy Replica Miu Miu Shoes Online
Cheap Designer Replica Anya Hindmarch
Cheap Replica Salvatore Ferragamo Handbags Online
Buy Discounted Designer Replica Jimmy Choo
Cheap Fake Dolce Gabbana Handbag
Designer Replica Marc Jacobs Handbag
Buy Marc Jacobs Shoes
Yves Saint Laurent Handbag Online
Buy Fake Cartier
Buy Cheap Designer Replica Gucci Handbag
Buy Discounted Salvatore Ferragamo Handbags Online
Buy Discounted Replica Fendi Handbags Online
Buy Chanel Handbags
Cheap Giuseppe Zanotti Online
Buy Cheap Designer Replica Salvatore Ferragamo
Buy Discounted Designer Replica Thomas Wylde Online
Buy Cheap Christian Dior Handbags Online
Buy Discounted Ysl Shoes
Buy Discounted Designer Replica Burberry Handbag Online
Fake Chanel Shoes
Discounted Fake Loewe
Buy Replica Lancel
Buy Cheap Designer Replica Vivienne Westwood Online
Cheap Gucci
Cheap Balenciaga Handbag Online
Buy Alexander Mcqueen Shoes Online
Fake Bally Handbag Online
Cheap Fake Salvatore Ferragamo Handbags Online
Discounted Replica Mulberry Handbags
Buy Replica Lv Handbags
Discounted Replica Chanel Handbag Online
Buy Discounted Replica Giuseppe Zanotti
Buy Discounted Fake Bally
Buy Replica Givenchy
Cheap Fake Balenciaga
Vivienne Westwood Shoes Online
Discounted Jimmy Choo Handbag
Buy Discounted Designer Replica Lancel Handbags Online
Reader's Comments
Comment
You must be logged in to post a comment.
Options
-
February 22, 2010 -
Uncategorized -
2 comments
-
Comments RSS -
Del.ico.us
-
Digg!
Dare I ask about the consistent / equivalent behaviour on Mono?
Always the troublemaker… glad you asked of course
It seems that mono behaves identically to .net in this case except for one exception (see addendum above). But an equally large issue that I should have caught before did rear its ugly head and that is the difference between newline characters in Linux and Windows land. I changed liftIO to always output “\r\n” for newlines so all should be well now. Glad we caught that.