使用IXmlSerializable的问题
2013-10-29 00:03 Wizardlsw 阅读(1125) 评论(0) 收藏 举报最近又开始使用XML了,但今天遇到一个折腾我一下午加一个晚上的时间,终于从网络上找到相关的资料解决了。
有一个成员是用来存放正则表达式的,由于里面包含其它字符,所以想用CDATA来保存方便查看,所以想到另建一个类再通过继承IXmlSerializable 接口来实现CDATA节点。参照了官方MSDN文档,写了类似以下的代码:
using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Diagnostics;
namespace BeiBei.Core.Tests
{
[XmlRoot("Worker")]
public class Worker
{
[XmlElement]
public string JobTitle { get; set; }
[XmlAttribute("active")]
public bool Active { get; set; }
[XmlElement]
public string NextPageEncodingName { get; set; }
[XmlElement]
public Person Person { get; set; }
[XmlElement]
public Person Person2 { get; set; }
}
public class Person : IXmlSerializable
{
// Private state
private string personName;
// Constructors
public Person(string name)
{
personName = name;
}
public Person()
{
personName = null;
}
// Xml Serialization Infrastructure
public void WriteXml(XmlWriter writer)
{
writer.WriteString(personName);
}
public void ReadXml(XmlReader reader)
{
personName = reader.ReadString();
}
public XmlSchema GetSchema()
{
return (null);
}
// Print
public override string ToString()
{
return (personName);
}
}
[TestClass]
public class IXmlSerializableTests
{
[TestMethod]
public void S_Person_Test()
{
var p = new Person("Shawn");
XmlSerializer serializer = new XmlSerializer(typeof(Person));
string path = "D:\\Test.Person.xml";
string path2 = "D:\\Test.Person.2.xml";
using (var writer = XmlWriter.Create(path))
{
serializer.Serialize(writer, p);
}
using (var reader = XmlReader.Create(path))
{
var p2 = serializer.Deserialize(reader) as Person;
using (var writer2 = XmlWriter.Create(path2))
{
serializer.Serialize(writer2, p2);
}
}
var xml1 = File.ReadAllText(path);
var xml2 = File.ReadAllText(path2);
Assert.AreEqual(xml1, xml2);
Debug.WriteLine(xml2);
}
[TestMethod]
public void S_Worker_Test()
{
var p = new Person("Shawn");
var pp = new Person("John");
var w = new Worker()
{
JobTitle = "Boss",
Person = p,
Person2 = pp,
NextPageEncodingName = "gb2312",
};
XmlSerializer serializer = new XmlSerializer(typeof(Worker));
string path = "D:\\Test.Worker.xml";
string path2 = "D:\\Test.Worker.2.xml";
using (var writer = XmlWriter.Create(path))
{
serializer.Serialize(writer, w);
}
using (var reader = XmlReader.Create(path))
{
var w2 = serializer.Deserialize(reader) as Worker;
using (var writer2 = XmlWriter.Create(path2))
{
serializer.Serialize(writer2, w2);
}
}
var xml1 = File.ReadAllText(path);
var xml2 = File.ReadAllText(path2);
Debug.WriteLine(xml2);
Assert.AreEqual(xml1, xml2);
}
}
}
结果Serialize出来的文件是正常的,但Deserialize后文件中,第一个Person之后的其它属性都没有了。
尝试了很多次,当个PERSON对象序列化/反序列化都是没有问题的,但当对象包括PERSON,且PERSON属性后还定义了其它的属性,尝试添加<XmlElement>之类的特性都没用。结论就是:第一个PERSON属性之后的其它属性一率都没能正常Deserialize。怪自己对这块不了解,更怪MSDN没有写好例子!
后来在这里找到答案:
http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly
其实跟属性顺序没有关系,而是我们没有把ReadXml的实现正确地实现了。再改成如下就正常了:
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
var isEmptyElement = reader.IsEmptyElement;
reader.ReadStartElement();
if (!isEmptyElement)
{
personName = reader.ReadString();
reader.ReadEndElement();
}
}
终于搞定了,终于可以继续后面的任务!刚过了十二点!
浙公网安备 33010602011771号