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><?xml version="1.0" encoding="utf-8" ?></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.
Thank you mate.
Thanks this save me!