.NET XML Serialization of CDATA ATTRIBUTE

Recently I needed to create a .NET class (C#) that when serialized should contain a CDATA attribute similar to this:

<?xml version="1.0" encoding="utf-8" ?>
<RootNode Type="zzzzz" Version="1" >    
    <CDataAttribute>
        <![CDATA[
         <?xml version="1.0" encoding="utf-8" ?>
        ]]>
    </CDataAttribute>    
</RootNode>

 

I started by creating a schema for validating this xml that can be (generated with xsd.exe and slightly altered):

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Example" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="RootNode">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="CDataAttribute" type="xs:string" minOccurs="0"/>
      </xs:sequence>
      <xs:attribute name="Type" type="xs:string" />
      <xs:attribute name="Version" type="xs:string" />
    </xs:complexType>
  </xs:element>
  <xs:element name="Example">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="RootNode" />
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

Note that the CDataAttribute is specified as type string and I could not find any type for referring a CDATA.

Now if you take this schema and generate a class from it (again with xsd.exe) you will see that the CDataAttribute is, as expected, represented by a string.

private string cDataAttributeField;

If you use the generated class and serialize a object from it, the .NET serializer will not encode the CDataAttribute between a CDATA xml structure, but instead will escape all the special characters that you place inside the CDATA.

<?xml version="1.0"?>
<Example xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <RootNode Type="xxxx" Version="1">
    <CDataAttribute>&lt;?xml version="1.0" encoding="utf-8" ?&gt;</CDataAttribute>
  </RootNode>
</Example>

As I really needed it to be placed inside a CData section, I searched on the Internet but did found a satisfying solution for this “problem”, but using the idea behind some of the articles (use XmlNode for the class CDataAttribute member instead of string) my solution was the following.

 

First I generated my schema class without the CDataAttribute.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Example" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="RootNode">
    <xs:complexType>
      <xs:sequence>
        <!-- NOTE: We could not generate a CDATA directly from XSD.
             Generated by partial class -->
        <!--<xs:element name="CDataAttribute" type="xs:string" minOccurs="0"/>-->
      </xs:sequence>
      <xs:attribute name="Type" type="xs:string" />
      <xs:attribute name="Version" type="xs:string" />
    </xs:complexType>
  </xs:element>
  <xs:element name="Example">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="RootNode" />
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

Then I extended the partial generated class with my own implementation of the CDataAttribute.

using System;
using System.Xml;
 
public partial class RootNode
{
    private XmlNode cDataAttributeField;
 
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public XmlNode CDataAttribute
    {
        get {return this.cDataAttributeField;}
        set {this.cDataAttributeField = value;}
    }
    
    /// <summary>
    /// Getter/Setter method for the CDATA document content field.
    /// Encapsulates the internal CDATA XmlNode
    /// </summary>
    [System.Xml.Serialization.XmlIgnore()]
    public String CDataAttributeByString
    {
        get 
        { // Retrieves the content of the encapsulated CDATA
          return cDataAttributeField.Value;
        }
 
        set
        { // Encapsulate in a CDATA XmlNode
          XmlDocument xmlDocument = new XmlDocument();
          this.cDataAttributeField = xmlDocument.CreateCDataSection(value);
        }
    }
}

Note that I used a XMLNode for representing the class member that will be serialized. For setting this XMLNode I created a property (CDataAttributeByString) that receives a string and places in the XmlNode a CDataSection containing the received string value.

As so I only work with the CDataAttributeByString property, that is excluded from the serialization, and I let the .NET serializer use the CDataAttribute property for properly creating my CDataAttribute.

 

Using the extended class, the serialized xml will now be:

<?xml version="1.0"?>
<Example xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <RootNode Type="xxxx" Version="1">
    <CDataAttribute>
        <![CDATA[<?xml version="1.0" encoding="utf-8" ?>]]>
    </CDataAttribute>
  </RootNode>
</Example>

 

I hope that this can help some of you, and if you know a better solution please tell me.

I leave a sample project here.

Architect Forum 2008

This week I participated in the Architect Forum 2008 in Portugal.

The event was all about Cloud Computing and the agenda had two sessions:

  • Microsoft’s Cloud Computing Platform : What it is and when to use it, by David Chappell
  • Windows Azure, Padrões de Arquitectura e Caso de Uso, by João Pedro Martins, José António Silva, Nuno Godinho

The first session was more introductory and theoretical serving its purpose of presenting this new computing platform paradigm. What I also liked about it, was that the speaker focused not only on the Microsoft’s platform but on other platforms like the one’s from Amazon and Google, showing their differences and similarities, possible strengths and weaknesses.

Personally it seems that Microsoft’s platform given its “late appearance”  (no one is really late) was given more thought and took advantage of the other previous experiments. But everything is right at the beginning and as so I expect everyone to be more or less “on-pair” when these platforms really take off.

The second session made the bridge from the theory to the practice by presenting scenarios where a cloud computing architecture “should” make sense and presenting advantages over “traditional” architectures. They showed a real case scenario with a expense reporting application running in the cloud platform of Microsoft that among other things made use of Live Mesh, .NET Services (e.g. Service Bus) and SQL Services (e.g. Storage).

Overall I really enjoyed the event and look forward to dive deeper and experiment with these cloud platforms.