• c#操作Xml(八)


    前言

        呃,已经是第八篇了,怎么感觉Xml还有好多东西没讲。。。还是先挑比较重要的东西讲一下吧,今天的主角是.net的Xml序列化。

        在主角出现前,先回想一下,平时什么地方用了Xml序列化吧:

        第一个想到的当然是Web Service和更进一步的WCF,没有Xml序列化的话,就需要手动处理Soap协议的各种输入和输出,其复杂性将会成倍的增长。

        第二个想到的就是Xml序列化其实就是一个Xml与对象之间的桥梁,可以把一个实例Xml变成一个实例对象,也可以把一个实例对象变成一个实例Xml,这在需要持久化的场合非常有用。

    工具

        工欲善其事,必先利其器。首先来看看关于Xml序列化的工具吧。

        这些工具通常在X:\Program Files\Microsoft SDKs\Windows\v6.0A\bin目录下,其中和Xml序列关系比较大的有xsd.exe、wsdl.exe、svcutil.exe。当然其他工具在.net里面也是非常重要的,可以在这里察看所有工具的用途和使用方式。这里重点要用到的是xsd.exe。

        当然这个工具有三种用法,分别是:

    • Xml First,先有Xml实例,适合先想好Xml是什么样,或者已经有Xml实例的情况
    • Xsd First,先有Xsd,适合于可以获得Xsd,或者熟悉Xsd的人,并且对Xml有很强的控制欲的人(某人飘过)
    • Class First,先有c#类型,适合于先有c#代码的情况

        接下来将分别介绍这3种方式的。

    Xml First

        这种情况首先有一个Xml实例,例如:

    <?xml version="1.0" encoding="utf-8" ?>
    <persons>
      <person name="Zhenway, Yan">
        <goodat>Xml</goodat>
        <goodat>Reflection</goodat>
      </person>
      <person name="Allen, Lee">
        <goodat>Ruby</goodat>
        <goodat>F#</goodat>
        <goodat>Windows Mobile</goodat>
        <goodat>Linq</goodat>
      </person>
    </persons>

        利用Xsd命令:“xsd XmlFirst.xml”,就可以根据这个实例获得xsd(当然不会是非常精确的,但基本上能用):

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema id="persons" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
      <xs:element name="persons" msdata:IsDataSet="true" msdata:Locale="en-US">
        <xs:complexType>
          <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="person">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="goodat" nillable="true" minOccurs="0" maxOccurs="unbounded">
                    <xs:complexType>
                      <xs:simpleContent msdata:ColumnName="goodat_Text" msdata:Ordinal="0">
                        <xs:extension base="xs:string">
                        </xs:extension>
                      </xs:simpleContent>
                    </xs:complexType>
                  </xs:element>
                </xs:sequence>
                <xs:attribute name="name" type="xs:string" />
              </xs:complexType>
            </xs:element>
          </xs:choice>
        </xs:complexType>
      </xs:element>
    </xs:schema>

        当然,如果对这个Xsd不太满意的话,还可以修改一下。这样就把Xml First转换成Xsd First。

    Xsd First

        这里首先需要一个Xsd(某个控制欲极强的人重新写了一下xsd)

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema id="persons" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:complexType name="Person">
        <xs:sequence>
          <xs:element name="goodat" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string"/>
      </xs:complexType>
      <xs:complexType name="Persons">
        <xs:sequence>
          <xs:element name="person" type="Person" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
      </xs:complexType>
      <xs:element name="persons" type="Persons"/>
    </xs:schema>

        这里要求每个person的goodat至少要有一项。

        然后利用xsd命令:“xsd XsdFirst.xsd /c”,这样就可以获得一个cs文件,整理后,如下:

    using System;
    using System.CodeDom.Compiler;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    
    [GeneratedCodeAttribute("xsd", "2.0.50727.1432")]
    [SerializableAttribute()]
    [DebuggerStepThroughAttribute()]
    [DesignerCategoryAttribute("code")]
    [XmlRootAttribute("persons", Namespace = "", IsNullable = false)]
    public partial class Persons
    {
        private Person[] personField;
    
        [System.Xml.Serialization.XmlElementAttribute("person", Form = XmlSchemaForm.Unqualified)]
        public Person[] person
        {
            get { return this.personField; }
            set { this.personField = value; }
        }
    }
    
    [GeneratedCodeAttribute("xsd", "2.0.50727.1432")]
    [SerializableAttribute()]
    [DebuggerStepThroughAttribute()]
    [DesignerCategoryAttribute("code")]
    public partial class Person
    {
        private string[] goodatField;
    
        private string nameField;
    
        [XmlElementAttribute("goodat", Form = XmlSchemaForm.Unqualified)]
        public string[] goodat
        {
            get { return this.goodatField; }
            set { this.goodatField = value; }
        }
    
        [XmlAttributeAttribute()]
        public string name
        {
            get { return this.nameField; }
            set { this.nameField = value; }
        }
    }

        这样就可以获得一个类型与这个Xsd对应,在对象实例与这个Xsd实例之间建立一座桥梁。

    Class First

        这种情况适合于先有类型,然后想持久化的情况,例如拥有一个下列的类型:

    [XmlRoot("persons")]
    public class ClassFirst
    {
        [XmlElement("person")]
        public Person[] PersonCollection { get; set; }
    }
    
    public class Person
    {
        [XmlAttribute("name")]
        public string Name { get; set; }
        [XmlElement("goodat")]
        public string[] GoodAt { get; set; }
    }
    

        Build以后,执行命令:“xsd ClassFirstSample.dll”,就可以获得这样一个xsd:

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="persons" nillable="true" type="ClassFirst" />
      <xs:complexType name="ClassFirst">
        <xs:sequence>
          <xs:element minOccurs="0" maxOccurs="unbounded" name="person" type="Person" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="Person">
        <xs:sequence>
          <xs:element minOccurs="0" maxOccurs="unbounded" name="goodat" type="xs:string" />
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" />
      </xs:complexType>
      <xs:element name="Person" nillable="true" type="Person" />
    </xs:schema>

        这个xsd就是序列化出来的xml的Schema,基本上与。

    XmlSerializer

        前面的三种方式都只是在OOP与Xml之间建立一个契约,现在来介绍这个桥梁——XmlSerializer

        废话就不说了,先来看看如何把对象转换成xml:

    XmlSerializer serializer = new XmlSerializer(typeof(Persons));
    serializer.Serialize(Console.Out, new Persons
    {
        person = new Person[]
        {
            new Person
            {
                name = "Zhenway, Yan",
                goodat = new string[] { "Reflection", "Xml" },
            },
            new Person
            {
                name = "Allen, Lee",
                goodat = new string[] { "Ruby", "F#", "Windows Mobile", "Linq" },
            },
        }
    });

        来看看输出:

    image

        很好,接下来看看如何反过来,从Xml获得对象实例:

    XmlSerializer serializer = new XmlSerializer(typeof(Persons));
    using (var reader = File.OpenText("XmlFirst.xml"))
    {
        Persons ps = (Persons)serializer.Deserialize(reader);
        foreach (var p in ps.person)
        {
            Console.WriteLine("name='{0}', good at={1}",
                p.name, string.Join(", ", p.goodat));
        }
    }
    

        看看输出:

    image

        不过需要注意的一点是,如果需要反序列化对象的话,需要对临时目录(根据Windows的TEMP环境变量定义)的写入权限。

        另外,XmlSerializer会自动生成一个Assembly用于加速序列化和反序列化,不过要注意由于AppDomain无法单独卸载一个Assembly的特性,所以当产生过多的Assembly时,就会导致内存占用过多。

        尽管XmlSerializer也会尽量利用现有的Assembly,不过这仅仅发生在(Type)构造函数,和(Type,String)构造函数时才会发生,而其他构造函数将再次创建Assembly,如果放置在循环中,这样将导致AppDomain中Assembly数量激增,因此缓存XmlSerializer在某些场合下是非常必要的。

        另外msdn上对XmlSerializer的描述有一处非常特别的地方,“此类型是线程安全的”,这在整个msdn中并不多见,也就是说,不用对缓存的XmlSerializer对象做任何的同步处理。

    更多控制

        XmlSerializer本身支持很多扩展,其中包括使用属性控制 XML 序列化,和更加可定制化的IXmlSerializable接口,这里限于篇幅就省略相关的内容。

    下集预告?

        第八篇了,还要下集?这个系列暂时就到这里吧,虽然感觉还有很多内容要讲。。。之后将推出难度较高的进阶系列。

    系列目录

    另外整理出本系列之前几篇连接和主要内容:

    (一)——Dom

    (二)——Dom with Namespace

    (三)——Linq to Xml

    (四)——Linq to Xml with Namespace

    (五)——XStreamingElement

    (六)——XmlWriter

    (七)——XmlReader

  • 相关阅读:
    spring 包的依赖关系
    菜鸟程序猿之IDEA快捷键
    eclipse的svn插件
    SVN使用教程总结
    Oracle 11g安装步骤详谈
    C3P0连接池的配置与使用
    Java课程设计
    201621123057 《Java程序设计》第14周学习总结
    201621123057 《Java程序设计》第13周学习总结
    201621123057 《Java程序设计》第12周学习总结
  • 原文地址:https://www.cnblogs.com/vwxyzh/p/1660109.html
Copyright © 2020-2023  润新知