Search code examples
c#xmlxmlserializer

Class properties ignored by XmlSerializer


I have a class representing a book and when I run the SerializeToXmlElement() method, it includes the class but not the class properties. How can I ensure that the public properties are included in the XML output?

Book class

[XmlType("Edition")]
public class Book 
{
    #region Attributes
    private string series;
    private string title;
    private string isbn;
    private string pubDate;
    #endregion Attributes

    #region Encapsulated fields
    [XmlElement]
    public string Series { get => series; set => series = value; }
    [XmlElement]
    public string Title { get => title; set => title = value; }
    [XmlElement("ISBN")]
    public string Isbn { get => isbn; set => isbn = value; }
    [XmlElement("Publication_Date")]
    public string EditionPubDate { get => pubDate; set => pubDate = value; }
    #endregion Encapsulated fields

    #region Constructors
    public Book() { }
    #endregion Constructors

    #region Methods
    public XmlElement SerializeToXmlElement()
    {
        XmlDocument doc = new XmlDocument();
        using (XmlWriter writer = doc.CreateNavigator().AppendChild())
        {
            new XmlSerializer(this.GetType()).Serialize(writer, this);
        }
        return doc.DocumentElement;
    }
    #endregion Methods
}

Input

XmlDocument doc = new XmlDocument();
doc.AppendChild(doc.CreateXmlDeclaration("1.0","utf-8",null));
XmlNode rootnode = doc.AppendChild(doc.CreateElement("Root_Node"));
XmlNode editionsNode = rootnode.AppendChild(doc.CreateElement("Editions"));

Book b = new Book();
b.Isbn = "978-0-553-10953-5";
b.Title = "A Brief History of Time";
XmlNode edition = doc.ImportNode(b.SerializeToXmlElement(), false);
editionsNode.AppendChild(edition);
edition.AppendChild(doc.CreateElement("Impressions"));

Output

<Root_Node>
    <Editions>
        <Edition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <Impressions />
        </Edition>
    </Editions>
</Root_Node>

Bonus points for someone who can tell me how I can remove the xmlns:xsi and xmlns:xsd attributes from the Edition node in the XML output.


Solution

  • You need to pass true for the second parameter to XmlDocument.ImportNode(XmlNode, Boolean):

    deep
     Type: System.Boolean
    true to perform a deep clone; otherwise, false.

    This indicates that the child nodes of the incoming node should be copied as well. Thus, your code should look like:

    XmlNode edition = doc.ImportNode(b.SerializeToXmlElement(), true);
    

    Bonus points for someone who can tell me how I can remove the xmlns:xsi and xmlns:xsd attributes from the Edition node in the XML output.

    As explained in this answer to Omitting all xsi and xsd namespaces when serializing an object in .NET? by Thomas Levesque you need to pass an XmlSerializerNamespaces with an empty name/namespace pair into Serialize():

    public XmlElement SerializeToXmlElement()
    {
        XmlDocument doc = new XmlDocument();
        using (XmlWriter writer = doc.CreateNavigator().AppendChild())
        {
            var ns = new XmlSerializerNamespaces();
            ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
            new XmlSerializer(this.GetType()).Serialize(writer, this, ns);
        }
        return doc.DocumentElement;
    }
    

    Working .Net fiddle.