返回首页
当前位置: 主页 > 网络编程 > .Net实例教程 >

XmlSerializer 序列化与反序列化CDATA 以及实现IXmlSerializable

时间:2013-03-17 19:59来源:知行网www.zhixing123.cn 编辑:麦田守望者

XmlSerializer类可以帮助我们将对象的状态序列化对保存,同时通过反序列化,可以还原对象的状态。通过与XML序列化与反序列化相关的特性(Attribute),可以控制我们的序列化的XML格式;同时通过实现IXmlSerializable接口,可以自定义的实现序列化与反序列化。关于此类,详情查看MSDN XmlSerializer类。不过在一些特殊情况下,CDATA类型的序列化与反序列化并不那么容易,或者说会出现一定的问题,本文将对此进行探讨。

1,新建测试项目和窗体

窗体代码如下:

using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;

namespace XmlSerializerTest
{
public partial class Main : Form
{
public Main()
{
InitializeComponent();
}

private void buttonSerialize_Click(object sender, EventArgs e)
{
var tc = new TestClass();
tc.ID = 2011;
tc.CDataContent = @"<table id=""test"">test";
var serializer = new XmlSerializer(tc.GetType());
var text = new StringBuilder();
using (var s = new StringWriter(text))
{
serializer.Serialize(s, tc);
}
this.textBoxXml.Text = text.ToString();
}

private void buttonDeserialize_Click(object sender, EventArgs e)
{
var serializer = new XmlSerializer(typeof(TestClass));
using (var s = new StringReader(this.textBoxXml.Text))
{
var tc = serializer.Deserialize(s) as TestClass;
if (tc != null)
{
MessageBox.Show(tc.CDataContent);
}
}
}

/// <summary>
/// Test class
/// </summary>
[Serializable]
public class TestClass
{
[XmlElement("ID")]
public int ID { get; set; }

[XmlElement("Content")]
public string CDataContent { get; set; }
}
}
}

运行,点击Serialize按钮,可以得到序列化生成的XML文档:

<?xml version="1.0" encoding="utf-16"?>
<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>2011</ID>
<Content>&lt;table id="test"&gt;test</Content>
</TestClass>

点击Deserialize按钮,可以得到以下结果:

---------------------------

---------------------------
<table id="test">test
---------------------------
OK
---------------------------

2,序列化为CDATA

如果需要将序列化生成的XML转化为以下格式(在实际中往往我们需要的是这种效果,而不是被转义的字符):

<?xml version="1.0" encoding="utf-16"?>
<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>2011</ID>
<Content>
<![CDATA[
<table id="test">test]]>
</Content>
</TestClass>
这个时候我们至少有两种方法来实现。

2.1,修改实体类

我们将实体类TestClass修改为以下(关于为什么需要这样定义,请大家自行思考):

/// <summary>
/// Test class
/// </summary>
[Serializable]
public class TestClass
{
[XmlElement("ID")]
public int ID { get; set; }

[XmlIgnore]
public string CDataContent { get; set; }

[XmlElement("Content")]
public XmlNode[] Nodes
{
get
{
var dom = new XmlDocument();
return new XmlNode[] { dom.CreateCDataSection(this.CDataContent) };
}
set
{
if (value == null)
{
this.CDataContent = null;
return;
}

if (value.Length != 1)
throw new InvalidOperationException("Invalid array.");
var content = value[0];
if (null == content)
throw new InvalidOperationException("Node is null.");
this.CDataContent = content.Value;
}

}
}

运行后,TextBox的内容为:

<?xml version="1.0" encoding="utf-16"?>
<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>2011</ID>
<Content><![CDATA[<table id="test">test]]></Content>
</TestClass>

已经实现。

2.2,实现IXmlSerializable接口

/// <summary>
/// Test class
/// </summary>
[Serializable]
public class TestClass : IXmlSerializable
{
[XmlElement("ID")]
public int ID { get; set; }

[XmlElement("Content")]
public string CDataContent { get; set; }


System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{
return null;
}

void IXmlSerializable.ReadXml(XmlReader reader)
{
reader.ReadStartElement("TestClass");
this.ID=reader.ReadElementContentAsInt("ID", "");
this.CDataContent=reader.ReadElementContentAsString("Content", "");
reader.ReadEndElement();
}

void IXmlSerializable.WriteXml(XmlWriter writer)
{
writer.WriteStartElement("ID");
writer.WriteValue(this.ID);
writer.WriteEndElement();
writer.WriteStartElement("Content");
writer.WriteCData(this.CDataContent);
writer.WriteEndElement();

}
}

请留意ReadXml与WriteXml两个方法。一个将Xml的值读取出来赋值给当前实例,一个将当前实例的属性值写入到XML;而另外一个GetSchema在返回此对象对应的XML架构用于验证是否为合法的XML文档。

经过测试,上述方法可以达到第一种方法的效果,而且更加的安全,只不过在实现接口的时候需要麻烦一点。

对于一些无法直接序列化的类比如泛型的List等,也可以按照这种方式实现自定义的序列化与反序列化。

------分隔线----------------------------
标签(Tag):C# C#实例教程 c#基础教程 C#源代码 c#技巧
------分隔线----------------------------
推荐内容
猜你感兴趣