问题
I am having problems serializing a cdata section using c#
I need to serialize XmlCDataSection object property as the innertext of the element.
The result I am looking for is this:
<Test value2="Another Test">
<![CDATA[<p>hello world</p>]]>
</Test>
To produce this, I am using this object:
public class Test
{
[System.Xml.Serialization.XmlText()]
public XmlCDataSection value { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute()]
public string value2 { get; set; }
}
When using the xmltext annotation on the value property the following error is thrown.
System.InvalidOperationException: There was an error reflecting property 'value'. ---> System.InvalidOperationException: Cannot serialize member 'value' of type System.Xml.XmlCDataSection. XmlAttribute/XmlText cannot be used to encode complex types
If I comment out the annotation, the serialization will work but the cdata section is placed into a value element which is no good for what I am trying to do:
<Test value2="Another Test">
<value><![CDATA[<p>hello world</p>]]></value>
</Test>
Can anybody point me in the right direction to getting this to work.
Thanks, Adam
回答1:
Thanks Richard, only now had chance to get back to this. I think I have resolved the problem by using your suggestion. I have created a CDataField object using the following:
public class CDataField : IXmlSerializable
{
private string elementName;
private string elementValue;
public CDataField(string elementName, string elementValue)
{
this.elementName = elementName;
this.elementValue = elementValue;
}
public XmlSchema GetSchema()
{
return null;
}
public void WriteXml(XmlWriter w)
{
w.WriteStartElement(this.elementName);
w.WriteCData(this.elementValue);
w.WriteEndElement();
}
public void ReadXml(XmlReader r)
{
throw new NotImplementedException("This method has not been implemented");
}
}
回答2:
The way Test
is defined, your data is a CData object. So the serialisation system is trying to preserve the CData object.
But you want to serialise some text data as a CData section.
So first, the type of Test.value
should be String.
You then need to control how that field is serialised, but there does not appear to be any inbuilt method or attribute to control how strings are serialised (as string, maybe with entities for reserved characters, or as CDATA). (Since, from an XML infoset perspective all of these are the same, this is not surprising.)
You can of course implemented IXmlSerializable and just code the serialisation of the Test
type yourself which gives you complete control.
回答3:
Just found an alternative from here:
[XmlIgnore]
public string Content { get; set; }
[XmlText]
public XmlNode[] CDataContent
{
get
{
var dummy = new XmlDocument();
return new XmlNode[] {dummy.CreateCDataSection(Content)};
}
set
{
if (value == null)
{
Content = null;
return;
}
if (value.Length != 1)
{
throw new InvalidOperationException(
String.Format(
"Invalid array length {0}", value.Length));
}
var node0 = value[0];
var cdata = node0 as XmlCDataSection;
if (cdata == null)
{
throw new InvalidOperationException(
String.Format(
"Invalid node type {0}", node0.NodeType));
}
Content = cdata.Data;
}
}
}
回答4:
I had very same problem as Adam. However this Answer does not helped me at 100% :) but gives me a clue. So I'va created a code like below. It generates XML like this:
<Actions>
<Action Type="reset">
<![CDATA[
<dbname>longcall</dbname>
<ontimeout>
<url>http://[IPPS_ADDRESS]/</url>
<timeout>10</timeout>
</ontimeout>
]]>
</Action>
<Action Type="load">
<![CDATA[
<dbname>longcall</dbname>
]]>
</Action>
</Actions>
Code:
public class ActionsCDataField : IXmlSerializable
{
public List<Action> Actions { get; set; }
public ActionsCDataField()
{
Actions = new List<Action>();
}
public XmlSchema GetSchema()
{
return null;
}
public void WriteXml(XmlWriter w)
{
foreach (var item in Actions)
{
w.WriteStartElement("Action");
w.WriteAttributeString("Type", item.Type);
w.WriteCData(item.InnerText);
w.WriteEndElement();
w.WriteString("\r\n");
}
}
public void ReadXml(XmlReader r)
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(r);
XmlNodeList nodes = xDoc.GetElementsByTagName("Action");
if (nodes != null && nodes.Count > 0)
{
foreach (XmlElement node in nodes)
{
Action a = new Action();
a.Type = node.GetAttribute("Type");
a.InnerText = node.InnerXml;
if (a.InnerText != null && a.InnerText.StartsWith("<![CDATA[") && a.InnerText.EndsWith("]]>"))
a.InnerText = a.InnerText.Substring("<![CDATA[".Length, a.InnerText.Length - "<![CDATA[]]>".Length);
Actions.Add(a);
}
}
}
}
public class Action
{
public String Type { get; set; }
public String InnerText { get; set; }
}
回答5:
This basically shorter version of Jack answer with better error messages:
[XmlIgnore]
public string Content { get; set; }
[XmlText]
public XmlNode[] ContentAsCData
{
get => new[] { new XmlDocument().CreateCDataSection(Content) };
set => Content = value?.Cast<XmlCDataSection>()?.Single()?.Data;
}
来源:https://stackoverflow.com/questions/1398680/xml-serialization-xmlcdatasection-as-serialization-xmltext