深入理解:XML与对象的序列化与反序列化


Posted in PHP onJune 08, 2013

这篇文章主要讲述XML与对象的序列化与反序列化。并且会附上一些简单的序列化与反序列化方法,供大家使用。
假设我们在一个Web项目中有这样两个类

public class Member 
    {
      public string Num { get; set; }
      public string Name { get; set; }
    }
    public class Team
    {
       public  string Name;
       public  List<Member> Members { get; set; }
    }

假设我们需要把Team类的一个实例POST到一个URL,
当然,使用Form隐藏域提交就可以完成该功能。
如果该Team包括30条数据呢?
为了区分每个Member,我们得给参数的名字加上后缀。这就要一大串的隐藏域来完成:
<!--使用Razor来演示-->
@model Team
<form id="submitForm" action="http://www.johnconnor.com/team" method="post">
<input type="hidden" name="TeamName" value="@Model.Name" />
<input type="hidden" name="MemberNum1" value="@Model.Members[0].Num" />
<input type="hidden" name="MemberName1" value="@Model.Members[0].Name" />
...
<!--省略28X2个input标签-->
<input type="hidden" name="MemberNum30" value="@Model.Members[29].Num" />
<input type="hidden" name="MemberName30" value="@Model.Members[29].Name" />
</form>
<script type="text/javascript">
    document.getElementById("submitForm").submit();
</script>

还敢想象一下如果Team再复杂一些,嵌套再多一些的情况么?
呃,即使你愿意这么传数据,对方看到一坨参数名就够头疼了。
我们都知道对象是不能在网络中直接传输的,不过还有补救的办法。
XML(Extensible Markup Language)可扩展标记语言,本身就被设计用来存储数据,任何一个对象都可以用XML来描述。以Team类为例:
<?xml version="1.0" encoding="utf-8"?>
<Team xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Development</Name>
  <Members>
    <Member>
      <Num>001</Num>
      <Name>Marry</Name>
    </Member>
    <Member>
      <Num>002</Num>
      <Name>John</Name>
    </Member>
  </Members>
</Team>

这样一个XML文档就表示了Team一个实例。
聪明的看官应该已经想到,XML是可以作为对象信息的载体在网络中传输,因为它是文本形式的。
怎么进行XML文档与对象的相互转换呢?

XmlSerializer类就是干这个活的。
      命名空间:System.Xml.Serialization
     程序集:System.Xml(在 system.xml.dll 中)
现在这里展示了一个提供序列化与反序列化方法的EncodeHelper类。
Deserialize方法将XML字符串转换为指定类型的对象;
Serialize方法则将对象转换为XML字符串。

/// <summary>
    /// 提供xml文档序列化 反序列化
    /// </summary>
    public sealed class EncodeHelper
    {
        /// <summary>
        /// 反序列化XML字符串为指定类型
        /// </summary>
        public static object Deserialize(string Xml, Type ThisType)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(ThisType);
            object result;
            try
            {
                using (StringReader stringReader = new StringReader(Xml))
                {
                    result = xmlSerializer.Deserialize(stringReader);
                }
            }
            catch (Exception innerException)
            {
                bool flag = false;
                if (Xml != null)
                {
                    if (Xml.StartsWith(Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble())))
                    {
                        flag = true;
                    }
                }
                throw new ApplicationException(string.Format("Couldn't parse XML: '{0}'; Contains BOM: {1}; Type: {2}.", 
                Xml, flag, ThisType.FullName), innerException);
            }
            return result;
        }
        /// <summary>
        /// 序列化object对象为XML字符串
        /// </summary>
        public static string Serialize(object ObjectToSerialize)
        {
            string result = null ;
            try
            {
            XmlSerializer xmlSerializer = new XmlSerializer(ObjectToSerialize.GetType());            using (MemoryStream memoryStream = new MemoryStream())
            {
                XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding(false));
                xmlTextWriter.Formatting = Formatting.Indented;
                xmlSerializer.Serialize(xmlTextWriter, ObjectToSerialize);
                xmlTextWriter.Flush();
                xmlTextWriter.Close();
                UTF8Encoding uTF8Encoding = new UTF8Encoding(false, true);
                result= uTF8Encoding.GetString(memoryStream.ToArray());
            }
            }
            catch (Exception innerException)
            {
                throw new ApplicationException("Couldn't Serialize Object:" + ObjectToSerialize.GetType().Name, innerException);
            }
            return result;
        }
    }

要使用这个类需要添加以下引用
using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
下面我们用一个控制台程序来演示一下这个类是如何工作的。这里是程序的Main函数。
static void Main(string[] args)
        {
            List<Member> Members = new List<Member>();
            Member member1 = new Member { Name = "Marry", Num = "001" };
            Member member2 = new Member { Name = "John", Num = "002" };
            Members.Add(member1);
            Members.Add(member2);
            Team team = new Team { Name = "Development", Members = Members };
            var xml =EncodeHelper.Serialize(team);//序列化
            Console.Write(xml);//打印序列化后的XML字符串
            Console.ReadLine();
            Team newTeam = EncodeHelper.Deserialize(xml, typeof(Team)) as Team;//反序列化时需要显式的进行类型转换
            Console.WriteLine("Team Name:"+newTeam.Name);//显示反序列化后的newTeam对象
            foreach (var member in newTeam.Members)
            {
                Console.WriteLine("Member Num:" + member.Num);
                Console.WriteLine("Member Name:" + member.Name);
            }
            Console.ReadLine();
        }

在执行完Console.Write(xml)这行代码后,就可以看到打印出来的XML文档了。
<?xml version="1.0" encoding="utf-8"?>
<Team xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Development</Name>
  <Members>
    <Member>
      <Num>001</Num>
      <Name>Marry</Name>
    </Member>
    <Member>
      <Num>002</Num>
      <Name>John</Name>
    </Member>
  </Members>
</Team>

与我在文章开头给出的例子是一模一样的。
最终反序列化出来的newTeam对象打印出来是这样的结果。
Team Name:Development
Member Num:001
Member Name:Marry
Member Num:002
Member Name:John
回到我们开头的Web通信的例子,
利用XML序列化与反序列化来进行对象传递,我们只需要把需要传递的对象序列化为XML字符串,使用一个隐藏域进行form提交就可以搞定咯!
接收方再将接收到的XML字符串反序列化成预设的对象即可。前提是双方必须约定序列化与反序列化的过程一致,且对象相同。

最后我们来看一下怎么利用一些特性来控制序列化与反序列化操作的过程。我们把开始的类改一下:

public class Member
    {
        [XmlElement("Member_Num")]
        public string Num { get; set; }
        public string Name { get; set; }
    }
    [XmlRoot("Our_Team")]
    public class Team
    {
        [XmlIgnore]public string Name;
        public List<Member> Members { get; set; }
    }

然后我们再次执行刚才的控制台程序,序列化结果变成了这样:
<?xml version="1.0" encoding="utf-8"?>
<Our_Team xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Members>
    <Member>
      <Member_Num>001</Member_Num>
      <Name>Marry</Name>
    </Member>
    <Member>
      <Member_Num>002</Member_Num>
      <Name>John</Name>
    </Member>
  </Members>
</Our_Team>

本来的根节点Team变成了Our_Team,Member的子节点Num变成了Member_Num,并且Team的Name子节点被忽略了。
可见特性XmlRoot可以控制根节点的显示和操作过程,XmlElement则针对子节点。如果某些成员被标记XmlIgnore,则在序列化与反序列化过程中会被忽略。
这些特性的具体内容可以在MSDN查看,就不多讲了。
有了这些知识,在网络中传递对象数据应该已经难不倒各位看官了把。^_^
PHP 相关文章推荐
用PHP动态创建Flash动画
Oct 09 PHP
经典的PHPer为什么被认为是草根?
Apr 02 PHP
一漂亮的PHP图片验证码实例
Mar 21 PHP
php检测useragent版本示例
Mar 24 PHP
你可能不知道PHP get_meta_tags()函数
May 12 PHP
关于扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题分析
Jan 08 PHP
Yii2框架引用bootstrap中日期插件yii2-date-picker的方法
Jan 09 PHP
PHP中empty,isset,is_null用法和区别
Feb 19 PHP
php批量修改表结构实例
May 24 PHP
PHP+mysql实现的三级联动菜单功能示例
Feb 15 PHP
php设计模式之工厂模式用法经典实例分析
Sep 20 PHP
php扩展开发入门demo示例
Sep 23 PHP
探讨:使用XMLSerialize 序列化与反序列化
Jun 08 #PHP
解析PHP自带的进位制之间的转换函数
Jun 08 #PHP
深入PHP内存相关的功能特性详解
Jun 08 #PHP
PHP rawurlencode与urlencode函数的深入分析
Jun 08 #PHP
PHP跳转页面的几种实现方法详解
Jun 08 #PHP
利用php递归实现无限分类 格式化数组的详解
Jun 08 #PHP
如何利用php array_multisort函数 对数据库结果进行复杂排序
Jun 08 #PHP
You might like
PHP英文字母大小写转换函数小结
2014/05/03 PHP
PHP命名空间和自动加载类
2016/04/03 PHP
Yii CDBCriteria常用方法实例小结
2017/01/19 PHP
php实现表单提交上传文件功能
2018/05/28 PHP
PHP使用正则表达式实现过滤非法字符串功能示例
2018/06/04 PHP
Laravel框架实现的使用smtp发送邮件功能示例
2019/03/12 PHP
vmware linux系统安装最新的php7图解
2019/04/14 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
2020/02/21 PHP
jQuery实现的网格线绘制方法
2016/06/20 Javascript
微信+angularJS的SPA应用中用router进行页面跳转,jssdk校验失败问题解决
2016/09/09 Javascript
如何提高Dom访问速度
2017/01/05 Javascript
JS实现520 表白简单代码
2018/05/21 Javascript
Vue 实现拖动滑块验证功能(只有css+js没有后台验证步骤)
2018/08/24 Javascript
解决webpack多页面内存溢出的方法示例
2019/10/08 Javascript
layUI的验证码功能及校验实例
2019/10/25 Javascript
JavaScript This指向问题详解
2019/11/25 Javascript
JS实现的定时器展示简单秒表、页面弹框及跳转操作完整示例
2020/01/26 Javascript
如何利用Node.js与JSON搭建简单的动态服务器
2020/06/16 Javascript
Python中的ctime()方法使用教程
2015/05/22 Python
matplotlib绘制动画代码示例
2018/01/02 Python
对python插入数据库和生成插入sql的示例讲解
2018/11/14 Python
对python打乱数据集中X,y标签对的方法详解
2018/12/14 Python
如何利用Python分析出微信朋友男女统计图
2019/01/25 Python
利用Python代码实现一键抠背景功能
2019/12/29 Python
Python使用enumerate获取迭代元素下标
2020/02/03 Python
基于Tensorflow高阶读写教程
2020/02/10 Python
Python基于pandas绘制散点图矩阵代码实例
2020/06/04 Python
CSS3实现粒子旋转伸缩加载动画
2016/04/22 HTML / CSS
CSS中的字体大小设置属性总结
2016/05/24 HTML / CSS
css3 边框、背景、文本效果的实现代码
2018/03/21 HTML / CSS
英国最大的电脑零售连锁店集团:PC World
2016/10/10 全球购物
中专毕业生自荐信
2013/11/16 职场文书
实习教师自我鉴定
2013/12/12 职场文书
市级三好学生事迹材料
2014/08/27 职场文书
你为什么是穷人?可能是这5个缺点造成
2019/07/11 职场文书
Nginx图片服务器配置之后图片访问404的问题解决
2022/03/21 Servers