zl程序教程

您现在的位置是:首页 >  后端

当前栏目

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

对象XML 深入 理解 序列化
2023-06-13 09:15:01 时间

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

复制代码代码如下:

publicclassMember
   {
     publicstringNum{get;set;}
     publicstringName{get;set;}
   }
   publicclassTeam
   {
      public stringName;
      public List<Member>Members{get;set;}
   }

假设我们需要把Team类的一个实例POST到一个URL,
当然,使用Form隐藏域提交就可以完成该功能。
如果该Team包括30条数据呢?
为了区分每个Member,我们得给参数的名字加上后缀。这就要一大串的隐藏域来完成:
复制代码代码如下:

<!--使用Razor来演示-->
@modelTeam
<formid="submitForm"action="http://www.johnconnor.com/team"method="post">
<inputtype="hidden"name="TeamName"value="@Model.Name"/>
<inputtype="hidden"name="MemberNum1"value="@Model.Members[0].Num"/>
<inputtype="hidden"name="MemberName1"value="@Model.Members[0].Name"/>
...
<!--省略28X2个input标签-->
<inputtype="hidden"name="MemberNum30"value="@Model.Members[29].Num"/>
<inputtype="hidden"name="MemberName30"value="@Model.Members[29].Name"/>
</form>
<scripttype="text/javascript">
   document.getElementById("submitForm").submit();
</script>

还敢想象一下如果Team再复杂一些,嵌套再多一些的情况么?
呃,即使你愿意这么传数据,对方看到一坨参数名就够头疼了。
我们都知道对象是不能在网络中直接传输的,不过还有补救的办法。
XML(ExtensibleMarkupLanguage)可扩展标记语言,本身就被设计用来存储数据,任何一个对象都可以用XML来描述。以Team类为例:
复制代码代码如下:
<?xmlversion="1.0"encoding="utf-8"?>
<Teamxmlns: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>
   publicsealedclassEncodeHelper
   {
       ///<summary>
       ///反序列化XML字符串为指定类型
       ///</summary>
       publicstaticobjectDeserialize(stringXml,TypeThisType)
       {
           XmlSerializerxmlSerializer=newXmlSerializer(ThisType);
           objectresult;
           try
           {
               using(StringReaderstringReader=newStringReader(Xml))
               {
                   result=xmlSerializer.Deserialize(stringReader);
               }
           }
           catch(ExceptioninnerException)
           {
               boolflag=false;
               if(Xml!=null)
               {
                   if(Xml.StartsWith(Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble())))
                   {
                       flag=true;
                   }
               }
               thrownewApplicationException(string.Format("Couldn"tparseXML:"{0}";ContainsBOM:{1};Type:{2}.",
               Xml,flag,ThisType.FullName),innerException);
           }
           returnresult;
       }
       ///<summary>
       ///序列化object对象为XML字符串
       ///</summary>
       publicstaticstringSerialize(objectObjectToSerialize)
       {
           stringresult=null;
           try
           {
           XmlSerializerxmlSerializer=newXmlSerializer(ObjectToSerialize.GetType());

           using(MemoryStreammemoryStream=newMemoryStream())
           {
               XmlTextWriterxmlTextWriter=newXmlTextWriter(memoryStream,newUTF8Encoding(false));
               xmlTextWriter.Formatting=Formatting.Indented;
               xmlSerializer.Serialize(xmlTextWriter,ObjectToSerialize);
               xmlTextWriter.Flush();
               xmlTextWriter.Close();
               UTF8EncodinguTF8Encoding=newUTF8Encoding(false,true);
               result=uTF8Encoding.GetString(memoryStream.ToArray());
           }
           }
           catch(ExceptioninnerException)
           {
               thrownewApplicationException("Couldn"tSerializeObject:"+ObjectToSerialize.GetType().Name,innerException);
           }
           returnresult;
       }
   }

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

在执行完Console.Write(xml)这行代码后,就可以看到打印出来的XML文档了。
复制代码代码如下:
<?xmlversion="1.0"encoding="utf-8"?>
<Teamxmlns: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对象打印出来是这样的结果。
TeamName:Development
MemberNum:001
MemberName:Marry
MemberNum:002
MemberName:John
回到我们开头的Web通信的例子,
利用XML序列化与反序列化来进行对象传递,我们只需要把需要传递的对象序列化为XML字符串,使用一个隐藏域进行form提交就可以搞定咯!
接收方再将接收到的XML字符串反序列化成预设的对象即可。前提是双方必须约定序列化与反序列化的过程一致,且对象相同。

最后我们来看一下怎么利用一些特性来控制序列化与反序列化操作的过程。我们把开始的类改一下:
复制代码代码如下:
publicclassMember
   {
       [XmlElement("Member_Num")]
       publicstringNum{get;set;}
       publicstringName{get;set;}
   }
   [XmlRoot("Our_Team")]
   publicclassTeam
   {
       [XmlIgnore]publicstringName;
       publicList<Member>Members{get;set;}
   }

然后我们再次执行刚才的控制台程序,序列化结果变成了这样:
复制代码代码如下:
<?xmlversion="1.0"encoding="utf-8"?>
<Our_Teamxmlns: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查看,就不多讲了。
有了这些知识,在网络中传递对象数据应该已经难不倒各位看官了把。^_^