Search code examples
c#xmlpersistencehuman-readable

How to Persist Object as human readable XML File with XML Declaration?


Background

I'm developing a desktop application that can create/open a project (think of visual studio). I need to persist such a project object to a XML file (think of .csproj) and load that project object from the XML file.

Goals

  1. Store / load class MyProject to / from XML file
  2. Human-readable XML (manual edits are bad, but it could simplify some tasks)
  3. Valid XML that could be parsed from other languages / apps:
    • File starts with XML Declaration like <?xml version="1.1" encoding="utf-8"?> since user defined strings in any culture may end up here, thus the encoding is important. Also see Does a valid XML file require an xml declaration?
    • Class namespaces can be specified (e.g. via DataContractAttribute.NameSpace)

Q: What's the best way to persist an object into a readable & valid XML file?

There are many ways to create XML and for me it seems the [DataContract] attribute is the way to go, since this allows for simple serialization and deserialization back into an object (goal 1). When using an XmlTextWriter I can also specify Formatting.Indented, which solves goal 2. However, I'm unable to create the XML declaration.

Edit: Solution based on Accepted Answer

Using the XmlTextWriter was a dead end, it does not accept XmlWriterSettings. There are too many (wrong/bad) ways to write XML. Using XmlWriter.Create(..) with the desired settings indeed produces human readable XML including declaration. The created instance is some internal class like WellFormedXmlWriter. The code:

    public static void Store<T>(string filename, T obj)
        where T : class
    {
        XmlWriterSettings settings = new XmlWriterSettings()
        {
            Indent = true, // human readable
            OmitXmlDeclaration = false, // don't omit the encoding
            Encoding = Encoding.UTF8
        };
        using (var xmlwriter = XmlWriter.Create(filename, settings))
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(T));
            ser.WriteObject(xmlwriter, obj);
        }
    }

    public static T Load<T>(string filename)
        where T : class
    {
        using (var xmlReader = XmlReader.Create(filename))
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(T));
            return (T)ser.ReadObject(xmlReader, true);
        }
    }

Solution

  • You can pass an XmlWriterSettings instance to XmlWriter.Create in order to control serialization more finely. I believe XmlWriterSettings.OmitXmlDeclaration is what you need.

    There's a small overview of XML output formatting on MSDN.