Introduction
As I mentioned in my last post, although you can override XML serialisation attributes by passing an XmlAttributeOverrides instance to an XmlSerializer, the attributes you provide for a given type and member replace all the existing XML serialisation attributes - you can't simply tweak one or two and leave the rest intact.
If you're thinking that type and members only tend to have one or two serialistion attributes, then take a look at this set attributes from an auto-generated EquityDerivativeBase class:
[System.Xml.Serialization.XmlIncludeAttribute(typeof(EquityDerivativeShortFormBase))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(EquityOptionTransactionSupplement))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(BrokerEquityOption))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(EquityDerivativeLongFormBase))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(EquityOption))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(EquityForward))] [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.fpml.org/FpML-5/confirmation")]
Let's suppose I want to use XmlAttributeOverrides to alter the value of the XmlTypeAttribute at run-rime, to place the element in a different namespace. Well I can. But the XmlAttributeOverrides instance I supply is used to replace all the existing attributes. So I lose each of the XmlIncludeAttribute attributes which define the classes which use this class as a base class.
Book and Genre classes (with Xml Attributes)
To demonstrate how to override the attributes selectively I'm going to use the same Book class as in my last post to demonstrate selectively overriding these attributes. I've added a lot more attributes to the members of the Book class to demonstrate that they all get retained.
[XmlType(TypeName="Book")] [XmlRoot("book", Namespace="http://tempuri.org")] public class Book { [XmlIgnore] public int InternalId { get; set; } [XmlElement("title")] public string Title { get; set; } [DefaultValue("Anonymous")] [XmlArray("authors")] [XmlArrayItem("author")] public string[] Authors { get; set; } [XmlElement("isbn13")] public string Isbn13 { get; set; } [XmlText] public string Extract { get; set; } [XmlAttribute("genre")] public Genre Genre { get; set; } [XmlNamespaceDeclarations] public XmlSerializerNamespaces XmlNamespaces { get; set; } [XmlAnyAttribute] public XmlAttribute[] OtherAttributes { get; set; } [XmlAnyElement] public XmlElement[] OtherElements { get; set; } public Book() { XmlNamespaces = new XmlSerializerNamespaces(); XmlNamespaces.Add("ns", "http://tempuri.org"); } } public enum Genre { [XmlEnum("unknown")] Unknown, [XmlEnum("autobiography")] Autobiography, [XmlEnum("computing-text")] ComputingText, [XmlEnum("classic")] Classic }
Solution
The solution is to copy all the existing attributes into an XmlAttributeOverrides instance (modifying them as they're copied), and then apply the XmlAttributeOverrides to the XmlSerializer. That way the XmlAttributeOverrides object retains all of the original attributes (with the exception of any changes made in transit). Let me show you what I mean: