分享

使用IXmlSerializable的问题

 昵称10504424 2013-10-30
最近又开始使用XML了,但今天遇到一个折腾我一下午加一个晚上的时间,终于从网络上找到相关的资料解决了。

     有一个成员是用来存放正则表达式的,由于里面包含其它字符,所以想用CDATA来保存方便查看,所以想到另建一个类再通过继承IXmlSerializable 接口来实现CDATA节点。参照了官方MSDN文档,写了类似以下的代码:

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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./Articles/43237/How-to-Implement-IXmlSerializable-Correctly

     

      其实跟属性顺序没有关系,而是我们没有把ReadXml的实现正确地实现了。再改成如下就正常了:

      

1
2
3
4
5
6
7
8
9
10
11
12
public void ReadXml(XmlReader reader)
{
    reader.MoveToContent();
    var isEmptyElement = reader.IsEmptyElement;
    reader.ReadStartElement();
 
    if (!isEmptyElement)
    {
        personName = reader.ReadString();
        reader.ReadEndElement();
    }
}

  

终于搞定了,终于可以继续后面的任务!刚过了十二点!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约