很久没有时间写关于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]