8Mar/100
Serialization to XML with CDATA tags
Sometimes you need CDATA tags around complex text in your destination XML.
There is no build in way of doing so (that I have found).
I found this nifty CdataWrapper class on Marc Gravell's blog. Thanks Marc!
Here is the basic class.
public sealed class CDataWrapper : IXmlSerializable
{
// implicit to/from string
public static implicit operator string(CDataWrapper value)
{
return value == null ? null : value.Value;
}
public static implicit operator CDataWrapper(string value)
{
return value == null ? null : new CDataWrapper
{
Value =
value
};
}
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
// "" => <Node/>
// "Foo" => <Node><![CDATA[Foo]]></Node>
public void WriteXml(XmlWriter writer)
{
if (!string.IsNullOrEmpty(Value))
{
writer.WriteCData(Value);
}
}
// <Node/> => ""
// <Node></Node> => ""
// <Node>Foo</Node> => "Foo"
// <Node><![CDATA[Foo]]></Node> => "Foo"
public void ReadXml(XmlReader reader)
{
if (reader.IsEmptyElement)
{
Value = "";
}
else
{
reader.Read();
switch (reader.NodeType)
{
case XmlNodeType.EndElement:
Value = ""; // empty after all...
break;
case XmlNodeType.Text:
case XmlNodeType.CDATA:
Value = reader.ReadContentAsString();
break;
default:
throw new InvalidOperationException("Expected text/cdata");
}
}
}
// underlying value
public string Value { get; set; }
public override string ToString()
{
return Value;
}
}
To use it, you must change your DataMember from String to CDataWrapper, make it private and give it a public property.
This:
[DataMember]
pubblic string Answer { get; set; }
Becomes this:
pubblic string Answer { get; set; }
[DataMember(Name="Answer", EmitDefaultValue=false)]
private CDataWrapper AnswerCDATA
{
get { return Answer; }
set { Answer = value; }
}
Then the serialization is done with one line:
. . . XElement xml = Microsoft.ServiceModel.Web.SerializationExtensions.ToXml(object); .
So simple!!!!