最近又开始使用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(); } }
终于搞定了,终于可以继续后面的任务!刚过了十二点!