很久没有时间写关于xml的相关代码了,今天写一个第三方的充值接口,又熟悉了下。 搞了半天怎么都搞不出来想要的结果,最后才发现时转码有问题造成的。所以一定要看清楚是utf-8还是gb2312! 关于xml反序列化,我网上搜了很久,都没有比较透彻的讲解的。好不容易找到一篇比较全面的文章,摘抄下,算是自己的总结。 摘抄来源:
http://blog.csdn.net/lazyleland/article/details/6665681 xml在项目中的应用非常广泛,比如可以用来作为不同模块之间接口交互的数据格式,或用来对数据进行本地化的存储(如配置文件)。命名空间System.Xml.Serialization提供了对xml进行反序列化及对对象序列化的功能,使用进来非常方便。 这里举一个简单的例子进行说明。假如在需求中有一个关于"学校"的定义,这间学校的数据结构可能是这样子的:
此外,我们还需要定义学生、老师及校长的数据结构。
有了数据模型后,相应的xml也可以写出来了。一间学校的xml数据可能是这样子的。 [code lang="xml"] <School> <Headmaster IsAssistant="false"> <Name>LazyLeland</Name> <Sex>I</Sex> <Age>27</Age> </Headmaster> <Classes> <Class> <Teacher> <Name>June</Name> <Sex>O</Sex> <Age>30</Age> </Teacher> <Students> <Student> <Name>Student1</Name> <Sex>I</Sex> <Age>10</Age> </Student> </Students> </Class> <Class> <Teacher> <Name>Sam</Name> <Sex>I</Sex> <Age>32</Age> </Teacher> <Students> <Student> <Name>Student2</Name> <Sex>O</Sex> <Age>10</Age> </Student> <Student> <Name>Student3</Name> <Sex>I</Sex> <Age>10</Age> </Student> <Student> <Name>Student4</Name> <Sex>O</Sex> <Age>10</Age> <Skill>DB</Skill> <Skill>C#</Skill> </Student> </Students> </Class> </Classes> </School> [/code] 注意xml中Student4的多个技能(Skill)没有使用Skills作为父节点,这是不规范的,但考虑到实际情况有可能数据是从已有的老系统中导出来,虽然不规范,但也需要正确地对其进行序列化。 接下来我们使用c#来定义数据的实体类。System.Xml.Serialization命名空间下提供了多个attribute(属性),通过这些attribute控制实体类的序列化过程。 Person.cs: [code lang="csharp"]</pre> [Serializable] [XmlRoot("Person")] public class Person { /// <summary> /// 需要定义无参数的构造函数,否则无法通过XmlSerializer进行序列化。 /// </summary> public Person() { } public Person Parse(string aName, SexDef aSex, int aAge) { _name = aName; _sex = aSex; _age = aAge; return this; } private string _name = string.Empty; [XmlElement("Name")] public string Name { get { return _name; } set { _name = value; } } private SexDef _sex = SexDef.I; [XmlElement("Sex")] public SexDef Sex { get { return _sex; } set { _sex = value; } } private int _age; [XmlElement("Age")] public int Age { get { return _age; } set { _age = value; } } private List<Skill> _skills = new List<Skill>(); [XmlElement("Skill")] public List<Skill> Skills { get { return _skills; } } [XmlIgnore()] public bool _isOlderThen30 { get { return _age > 30; } } #region Nested Types [Serializable] public enum SexDef { O = 0x00, I = 0x01 } public class Skill { /// <summary> /// 需要定义无参数的构造函数,否则无法通过XmlSerializer进行序列化。 /// </summary> public Skill() { } public Skill Parse(string aName) { _name = aName; return this; } private string _name; [XmlText()] public string Name { get { return _name; } set { _name = value; } } } #endregion } [Serializable] [XmlRoot("Headmaster")] public class Headmaster : Person { public Headmaster Parse(string aName, SexDef aSex, int aAge, bool aIsAssistant) { base.Parse(aName, aSex, aAge); _isAssistant = aIsAssistant; return this; } private bool _isAssistant; [XmlAttribute("IsAssistant")] public bool IsAssistant { get { return _isAssistant; } set { _isAssistant = value; } } } public class Teacher : Person { } public class Student : Person { } <pre> [/code] Class.cs: [code lang="csharp"]</pre> [Serializable] public class Class { private Teacher _teacher; [XmlElement("Teacher")] public Teacher Teacher { get { return _teacher; } set { _teacher = value; } } private List<Student> _students = new List<Student>(); [XmlArray("Students")] [XmlArrayItem("Student")] public List<Student> Students { get { return _students; } } } <pre> [/code] School.cs [code lang="csharp"]</pre> [Serializable] [XmlRoot("School")] public class School { private Headmaster _headmaster; [XmlElement("Headmaster")] public Headmaster Headmaster { get { return _headmaster; } set { _headmaster = value; } } private List<Class> _classes = new List<Class>(); [XmlArray("Classes")] [XmlArrayItem("Class")] public List<Class> Classes { get { return _classes; } } } <pre>[/code]
上面的代码中用到了以下的attribute:
[Serializable]:用于标志这个类是可进行序列化的。注意此属性只能用于类定义上,另外类也可以通过实现System.Runtime.Serialization.ISerializable进行自定义序列化控制。
[XmlRoot]:用于定义xml根节点的节点名称。
[XmlElement]:用于定义类属性在序列化中对应节点的名称。
[XmlIgnore]:标志此属性不参与序列化。
[XmlArray]:通常与[XmlArrayItem]配合使用,定义数组的父节点名称与子节点名称。
此外,.net还提供了其它控制序列化的attribute,此例子不涉及,需要了解可进一步参考MSDN,一般情况下用这几个attribute就够了。
现在定义好了xml的格式与数据的实体类,接下来就是使用System.Xml.Serialization.XmlSerializer类进行序列化/反序列化了。 把对象序列化成xml的代码如下: [code lang="csharp"] // 这里是实例化对象的代码,可以跳过。 Student student1 = new Student().Parse("Student1", Person.SexDef.I, 10) as Student; Student student2 = new Student().Parse("Student2", Person.SexDef.O, 10) as Student; Student student3 = new Student().Parse("Student3", Person.SexDef.I, 10) as Student; Student student4 = new Student().Parse("Student4", Person.SexDef.O, 10) as Student; student4.Skills.Add(new Person.Skill().Parse("DB")); student4.Skills.Add(new Person.Skill().Parse("C#")); Teacher teacher1 = new Teacher().Parse("June", Person.SexDef.O, 30) as Teacher; Teacher teacher2 = new Teacher().Parse("Sam", Person.SexDef.I, 32) as Teacher; Headmaster headmaster1 = new Headmaster().Parse("LazyLeland", Person.SexDef.I, 27, false); Class class1 = new Class(); class1.Teacher = teacher1; class1.Students.Add(student1); Class class2 = new Class(); class2.Teacher = teacher2; class2.Students.Add(student2); class2.Students.Add(student3); class2.Students.Add(student4); School school = new School(); school.Headmaster = headmaster1; school.Classes.Add(class1); school.Classes.Add(class2); // 序列化成xml的代码。 System.IO.StringWriter stringWriter = new System.IO.StringWriter(); System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(School)); xmlSerializer.Serialize(stringWriter, school); // return stringWriter.ToString(); [/code] 根据xml反序列化成对象的代码如下: [code lang="csharp"] // System.IO.StringReader stringReader = new System.IO.StringReader(aXml); System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(School)); // return xmlSerializer.Deserialize(stringReader) as School; [/code]