Clean-up job in a recent project that uses XML to store certain data. What I found:
- an XSD describing the XML schema
- C# proxy classes previously generated by the VS xsd.exe tool
- the actual XML files
- all of them not always in sync
The code reading and writing the XML files used LinqToXml to query the files and manually instantiate the XSD-generated classes.
Since the purpose of the proxy classes is to simplify read, write and query operations on statically typed classes, I replaced the Xml.Linq with compile-time type-safe object operations.
In order to verify that my changes did not corrupt the file or change any of the data, I needed to compare the original .xml files and the ones generated by XmlSerializer. I noticed differences between the two sets caused by the classes that wrote the files:
- XDocument.Root.Save does not generate namespace declarations, and writes a <element></element> closing tag for empty data.
- XmlSerializer does not write an explicit closing tag but uses the <element /> notation, and generates some namespace declarations in the <?xml> header.
I found the first hints of dealing with the closing tag here and here by implementing an XmlTextWriter, and the final code looks like this:
class MyXmlTextWriter : XmlTextWriter { public MyXmlTextWriter(Stream w) : base(w, Encoding.UTF8) { Indentation = 2; IndentChar = ' '; Formatting = System.Xml.Formatting.Indented; } public override void WriteEndElement() { if (this.WriteState == System.Xml.WriteState.Element) Formatting = System.Xml.Formatting.None; base.WriteFullEndElement(); Formatting = System.Xml.Formatting.Indented; } }
To omit the namespace declarations, one needs to provide an XmlSerializerNamespaces object for the XmlSerializer:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add(string.Empty, string.Empty); ns.Add(string.Empty, "http://www.w3.org/2001/XMLSchema-instance"); ns.Add(string.Empty, "http://www.w3.org/2001/XMLSchema"); using (var fs = new FileStream(filename, FileMode.Create, FileAccess.Write)) serializer.Serialize(new MyXmlTextWriter(fs), app, ns);
Pingback: XML Access Modes, Object Models, and Serialization in .Net « devioblog