C# 如何使用XmlSerializer将字符串序列化为CDATA?
是否可以通过某种类型的属性使用.Net XmlSerializer将字符串序列化为CDATA?除了John Saunders发布的方法外,您还可以直接使用a作为类型,尽管它可以归结为几乎相同的东西:C# 如何使用XmlSerializer将字符串序列化为CDATA?,c#,.net,xml-serialization,C#,.net,Xml Serialization,是否可以通过某种类型的属性使用.Net XmlSerializer将字符串序列化为CDATA?除了John Saunders发布的方法外,您还可以直接使用a作为类型,尽管它可以归结为几乎相同的东西: [XmlRoot("root")] public class Sample1Xml { internal Sample1Xml() { } [XmlElement("node")] public NodeType Node { get; set; }
[XmlRoot("root")]
public class Sample1Xml
{
internal Sample1Xml()
{
}
[XmlElement("node")]
public NodeType Node { get; set; }
#region Nested type: NodeType
public class NodeType
{
[XmlAttribute("attr1")]
public string Attr1 { get; set; }
[XmlAttribute("attr2")]
public string Attr2 { get; set; }
[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));
}
Content = value[0].Value;
}
}
}
#endregion
}
private string _message;
[XmlElement("CDataElement")]
public XmlCDataSection Message
{
get
{
XmlDocument doc = new XmlDocument();
return doc.CreateCDataSection( _message);
}
set
{
_message = value.Value;
}
}
用法:
MyClass mc = new MyClass();
mc.MyString = "<test>Hello World</test>";
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
StringWriter writer = new StringWriter();
serializer.Serialize(writer, mc);
Console.WriteLine(writer.ToString());
MyClass mc=newmyclass();
mc.MyString=“你好,世界”;
XmlSerializer serializer=新的XmlSerializer(typeof(MyClass));
StringWriter编写器=新的StringWriter();
serializer.Serialize(writer,mc);
Console.WriteLine(writer.ToString());
输出:
<?xml version="1.0" encoding="utf-16"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyString><![CDATA[<test>Hello World</test>]]></MyString>
</MyClass>
你好,世界]]>
在要序列化的类中:
public CData Content { get; set; }
和CData类:
public class CData : IXmlSerializable
{
private string _value;
/// <summary>
/// Allow direct assignment from string:
/// CData cdata = "abc";
/// </summary>
/// <param name="value">The string being cast to CData.</param>
/// <returns>A CData object</returns>
public static implicit operator CData(string value)
{
return new CData(value);
}
/// <summary>
/// Allow direct assignment to string:
/// string str = cdata;
/// </summary>
/// <param name="cdata">The CData being cast to a string</param>
/// <returns>A string representation of the CData object</returns>
public static implicit operator string(CData cdata)
{
return cdata._value;
}
public CData() : this(string.Empty)
{
}
public CData(string value)
{
_value = value;
}
public override string ToString()
{
return _value;
}
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
_value = reader.ReadElementString();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteCData(_value);
}
}
公共类CData:IXmlSerializable
{
私有字符串_值;
///
///允许从字符串直接赋值:
///CData=“abc”;
///
///正在转换为CData的字符串。
///CData对象
公共静态隐式运算符CData(字符串值)
{
返回新的CData(值);
}
///
///允许直接分配到字符串:
///字符串str=cdata;
///
///正在转换为字符串的CData
///CData对象的字符串表示形式
公共静态隐式运算符字符串(CData)
{
返回cdata.\u值;
}
公共CData():此(string.Empty)
{
}
公共CData(字符串值)
{
_价值=价值;
}
公共重写字符串ToString()
{
返回_值;
}
public System.Xml.Schema.XmlSchema GetSchema()
{
返回null;
}
public void ReadXml(System.Xml.XmlReader)
{
_value=reader.ReadElementString();
}
public void WriteXml(System.Xml.XmlWriter)
{
writer.WriteCData(_值);
}
}
此实现能够处理编码字符串中的嵌套CDATA(基于John Saunders的原始答案)
例如,假设您希望将以下文字字符串编码为CDATA:
I am purposefully putting some <![CDATA[ cdata markers right ]]> in here!!
在我的例子中,我使用的是混合字段,有些是CDATA,有些不是, 至少对我来说,以下解决方案是有效的 通过始终读取值字段,我得到了内容,无论是CDATA还是纯文本
[XmlElement("")]
public XmlCDataSection CDataValue {
get {
return new XmlDocument().CreateCDataSection(this.Value);
}
set {
this.Value = value.Value;
}
}
[XmlText]
public string Value;
迟做总比不做好
Cheers我也有类似的需求,但需要不同的输出格式-我希望在包含CDATA的节点上有一个属性。我从上述解决方案中获得了一些灵感,创造了自己的解决方案。也许它会在将来帮助某人
public class EmbedScript
{
[XmlAttribute("type")]
public string Type { get; set; }
[XmlText]
public XmlNode[] Script { get; set; }
public EmbedScript(string type, string script)
{
Type = type;
Script = new XmlNode[] { new XmlDocument().CreateCDataSection(script) };
}
public EmbedScript()
{
}
}
在要序列化的父对象中,我具有以下属性:
[XmlArray("embedScripts")]
[XmlArrayItem("embedScript")]
public List<EmbedScript> EmbedScripts { get; set; }
[XmlArray(“嵌入脚本”)]
[XmlArrayItem(“嵌入脚本”)]
公共列表{get;set;}
我得到以下输出:
<embedScripts>
<embedScript type="Desktop Iframe">
<![CDATA[<div id="play_game"><iframe height="100%" src="http://www.myurl.com" width="100%"></iframe></div>]]>
</embedScript>
<embedScript type="JavaScript">
<![CDATA[]]>
</embedScript>
</embedScripts>
]]>
这很有效
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
public class CDataContent
{
public CDataContent()
{
}
public CDataContent(string content)
{
this.Content = content;
}
[XmlIgnore]
public string Content
{
get => this.CData.FirstOrDefault()?.Value;
set
{
this.CData.Clear();
this.CData.Add(new XmlDocument().CreateCDataSection(value));
}
}
[XmlText]
public Collection<XmlNode> CData { get; } = new();
public static implicit operator CDataContent(string value) => new(value);
public static implicit operator string(CDataContent value) => value.Content;
}
使用System.Collections.ObjectModel;
使用System.Linq;
使用System.Xml;
使用System.Xml.Serialization;
公共类CDATA内容
{
公共内容()
{
}
公共CDATA内容(字符串内容)
{
这个。内容=内容;
}
[XmlIgnore]
公共字符串内容
{
get=>this.CData.FirstOrDefault()?.Value;
设置
{
this.CData.Clear();
this.CData.Add(新的XmlDocument().createCDATA节(值));
}
}
[XmlText]
公共集合CData{get;}=new();
公共静态隐式运算符CDATA内容(字符串值)=>new(值);
公共静态隐式运算符字符串(CDATA内容值)=>value.Content;
}
对我来说,这似乎不是最优雅的解决方案。这是唯一可行的方法吗?我认为这是实现这一目标的唯一方法,我在其他地方看到过这个话题,答案总是一样的。Philip的例子有点简洁,但概念相同。我所知道的唯一的另一种方法是在表示CDATA内容的类上实现您自己的>。我想做同样的事情,因为似乎将字符串存储为CDATA意味着更少的处理时间,因为我们“只能按原样”读/写字符串。涉及XmlDocument/xmlcatasection实例的代价有多高?整个属性都在那里,因此我们能够保持域模型类不受序列化逻辑细节的影响。如果肮脏的方式是唯一的方式,那就太可悲了。Philip的解决方案在页面后面稍微靠远一点是一件更整洁的事情。@Philip,这对反序列化有用吗?我看到一些注释说setter将接收一个XmlText值。@John Saunders-在反序列化过程中,它实际上在setter中接收一个XmlCharacterData值,这就是对.value的调用在setter中的作用(我最初将其作为内存中的ToString(),但这是不正确的)@PhilipRieck如果我们需要在CDATA节周围包装一个自定义对象,该怎么办。创建CDATA节接受字符串。谢谢!最简单的解决方案。这两个答案中值得注意的一点是,如果您只阅读XML,则不需要CDATA内容XmlSerializer.Deserialize
将自动为您将其转换为文本。这刚刚节省了我的时间。谢谢//如果您需要空的CDATA,您可以在源值为空时设置默认值以避免异常<代码>XmlDocument().CreateCataSection(MyString??String.Empty)代码>@pr0gg3r这是否也允许反序列化到同一对象?我遇到了这样的问题:如何将CDATA创建为文本值(而不是元素),例如Hello World]]]>?只需要能够处理空/空值,而不是像符咒一样输出。谢谢。这个答案值得更多的认可。尽管如此,定制的CData类型不再具有System.String类型喜欢的那些方便的内置方法。遗憾的是XmlElement不能处理字符串字段,然后您可以添加一个cdata类型,但不管怎样……太完美了!谢谢我需要做exac
[XmlArray("embedScripts")]
[XmlArrayItem("embedScript")]
public List<EmbedScript> EmbedScripts { get; set; }
<embedScripts>
<embedScript type="Desktop Iframe">
<![CDATA[<div id="play_game"><iframe height="100%" src="http://www.myurl.com" width="100%"></iframe></div>]]>
</embedScript>
<embedScript type="JavaScript">
<![CDATA[]]>
</embedScript>
</embedScripts>
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
public class CDataContent
{
public CDataContent()
{
}
public CDataContent(string content)
{
this.Content = content;
}
[XmlIgnore]
public string Content
{
get => this.CData.FirstOrDefault()?.Value;
set
{
this.CData.Clear();
this.CData.Add(new XmlDocument().CreateCDataSection(value));
}
}
[XmlText]
public Collection<XmlNode> CData { get; } = new();
public static implicit operator CDataContent(string value) => new(value);
public static implicit operator string(CDataContent value) => value.Content;
}