Tuesday, April 12, 2011

Serialization: How to override the element Name of an item inside a Collection

We cannot control the display name for the element if the object is an item inside a collection / array / list and etc. We can use XmlAttributeOverrides to override each property name of that object but not the element name of the object itself.

Consider the following scenerio of the XML structure: <customers><customer></customer>...<customer></customer>...</customers>

  <?xml version="1.0" encoding="utf-8"?>  
  <customers>
    <customer id="2600CD00">
      <firstName>Pat</firstName>
      <lastName>Thurston</lastName>
      ...
    </customer>
    <customer id="1E9CC4B0">
      <firstName>Kari</firstName>
      <lastName>Furse</lastName>
      ...
    </customer>
    <customer id="60R120B3">
      <firstName>Carl</firstName>
      <lastName>Stuart</lastName> 
      ...
    </customer>
    ...  
  </customers>

We want to make use of the existing classes to generate the above XML structure.

BeforeAfter
  public class Subscriber {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string ID { get; set; }
    ...
  }
 [XmlRoot(ElementName = "customer")]
  public class Subscriber {
    [XmlElement(ElementName="firstName")]
    public string FirstName { get; set; }

    [XmlElement(ElementName="lastName")]
    public string LastName { get; set; }

    [XmlAttribute( AttributeName="id" )]
    public string ID { get; set; }
    
    ...
  }
  public class Subscribers 
    : System.ComponentModel.IListSource {

    System.ComponentModel.BindingList<Subscriber> bList;
    ...
    
  }
public class Subscribers 
  : System.ComponentModel.IListSource {

  System.ComponentModel.BindingList<Subscriber> bList;
  ...
  
  public void ToXml(string outputFileName) {   
    StreamWriter w = new StreamWriter(outputFileName); 
    
    XmlRootAttribute root 
     = new XmlRootAttribute("customers");        
      
    XmlSerializerNamespaces ns 
     = new XmlSerializerNamespaces();
    ns.Add("", "");    
    
    XmlSerializer ser 
     = XmlSerializer(bList.GetType(), root)    
    ser.Serialize(w, bList, ns); 
  }    
}    

Now when we call Subscribers to generate XML: new Subscribers().ToXml("customers.xml");, the result is not what we want.

  <?xml version="1.0" encoding="utf-8"?>  
  <customers>
    <Subscriber id="2600CD00">
      <firstName>Pat</firstName>
      <lastName>Thurston</lastName>
      ...
    </Subscriber>
    <Subscriber id="1E9CC4B0">
      <firstName>Kari</firstName>
      <lastName>Furse</lastName>
      ...
    </Subscriber>
    <Subscriber id="60R120B3">
      <firstName>Carl</firstName>
      <lastName>Stuart</lastName> 
      ...
    </Subscriber>
    ...  
  </customers>

If we directly serialize our Subscriber class, for sure, we can alter the element name at the root level:

  <?xml version="1.0" encoding="utf-8"?>    
    <customer id="AE19600F">
      <firstName>Janko</firstName>
      <lastName>Cajhen</lastName>
      ...
    </customer>

Inspired by my another personal project, I fortunately figured out my own solution.

The Solution:

  [XmlRoot("customers")]
  public class Subscribers 
    : System.ComponentModel.IListSource {

    System.ComponentModel.BindingList<Subscriber> bList;
    ...
    
    
    [XmlElement("customer")]
    public List<Subscriber> All {
      get {
        return bList.ToList();
      }
    }
    
    ...
    
    public void ToXml(string outputFileName) {
      StreamWriter w = new StreamWriter(outputFileName); 
        
      XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
      ns.Add("", "");    

      XmlSerializer ser = new XmlSerializer(typeof(Subscribers));      
      ser.Serialize(w, new Subscribers(), ns); 
    }    
  }

No comments:

Post a Comment