转发过来学习学习

作者: 澳门新萄京app  发布:2019-10-22

原著章地址:

第意气风发做个大致的下结论,XML包蕴的要素有XmlElement,XmlAttribute ,InnerText。

开卷目录

  • 开始
  • 最简单易行的施用XML的艺术
  • 类型定义与XML结构的映射
  • 使用 XmlElement
  • 使用 XmlAttribute
  • 使用 InnerText
  • 重命名节点名称
  • 列表和数组的连串化
  • 列表和数组的做为数据成员的体系化
  • 花色承接与反体系化
  • 反连串化的实战演习
  • 反类别化的选拔总计
  • 撤废不需求类别化的积极分子
  • 强制钦定成员的连串化顺序
  • 自定义连串化行为
  • 系列化去掉XML命名空间及申明头
  • XML的行使提出

XML是少年老成种很广泛的数量保存方法,作者平时用它来保存一些数目,只怕是有个别布置参数。 使用C#,我们能够依靠.net framework提供的点不清API来读取也许创设修改那个XML, 然则,区别人采纳XML的点子很有十分的大概率并分歧。 今天本人希图谈谈本身利用XML的大器晚成部分方式,供我们参照他事他说加以考察。

回去顶端

最简便易行的利用XML的情势

由于.net framework针对XML提供了好多API,那么些API依照分裂的使用情形达成了不一致档期的顺序的卷入, 比方,大家得以一向使用XmlTextReader、XmlDocument、XPath来取数XML中的数据, 也得以采纳LINQ TO XML或然反类别化的艺术从XML中读取数据。 那么,使用哪一类办法最简便吗?

本人个人侧向于接受类别化,反类别化的主意来行使XML。 采纳这种方式,小编如果考虑什么定义数据类型就能够了,读写XML各只须要风华正茂行调用就可以产生。 举个例子:

// 1. 首先要创建或者得到一个数据对象
Order order = GetOrderById(123);


// 2. 用序列化的方法生成XML
string xml = XmlHelper.XmlSerialize(order, Encoding.UTF8);


// 3. 从XML读取数据并生成对象
Order order2 = XmlHelper.XmlDeserialize<Order>(xml, Encoding.UTF8);

正是如此轻易的职业,XML结构是何许的,笔者根本并非关注, 笔者只关怀数据是或不是能保留以至下一次是还是不是能将它们读抽出来。

证实:XmlHelper是多个工具类,全体源代码如下: 澳门新萄京app 1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml;

// 此处代码来源于博客【在.net中读写config文件的各种方法】的示例代码
// http://www.cnblogs.com/fish-li/archive/2011/12/18/2292037.html

namespace MyMVC
{
    public static class XmlHelper
    {
        private static void XmlSerializeInternal(Stream stream, object o, Encoding encoding)
        {
            if( o == null )
                throw new ArgumentNullException("o");
            if( encoding == null )
                throw new ArgumentNullException("encoding");

            XmlSerializer serializer = new XmlSerializer(o.GetType());

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.NewLineChars = "rn";
            settings.Encoding = encoding;
            settings.IndentChars = "    ";

            using( XmlWriter writer = XmlWriter.Create(stream, settings) ) {
                serializer.Serialize(writer, o);
                writer.Close();
            }
        }

        /// <summary>
        /// 将一个对象序列化为XML字符串
        /// </summary>
        /// <param name="o">要序列化的对象</param>
        /// <param name="encoding">编码方式</param>
        /// <returns>序列化产生的XML字符串</returns>
        public static string XmlSerialize(object o, Encoding encoding)
        {
            using( MemoryStream stream = new MemoryStream() ) {
                XmlSerializeInternal(stream, o, encoding);

                stream.Position = 0;
                using( StreamReader reader = new StreamReader(stream, encoding) ) {
                    return reader.ReadToEnd();
                }
            }
        }

        /// <summary>
        /// 将一个对象按XML序列化的方式写入到一个文件
        /// </summary>
        /// <param name="o">要序列化的对象</param>
        /// <param name="path">保存文件路径</param>
        /// <param name="encoding">编码方式</param>
        public static void XmlSerializeToFile(object o, string path, Encoding encoding)
        {
            if( string.IsNullOrEmpty(path) )
                throw new ArgumentNullException("path");

            using( FileStream file = new FileStream(path, FileMode.Create, FileAccess.Write) ) {
                XmlSerializeInternal(file, o, encoding);
            }
        }

        /// <summary>
        /// 从XML字符串中反序列化对象
        /// </summary>
        /// <typeparam name="T">结果对象类型</typeparam>
        /// <param name="s">包含对象的XML字符串</param>
        /// <param name="encoding">编码方式</param>
        /// <returns>反序列化得到的对象</returns>
        public static T XmlDeserialize<T>(string s, Encoding encoding)
        {
            if( string.IsNullOrEmpty(s) )
                throw new ArgumentNullException("s");
            if( encoding == null )
                throw new ArgumentNullException("encoding");

            XmlSerializer mySerializer = new XmlSerializer(typeof(T));
            using( MemoryStream ms = new MemoryStream(encoding.GetBytes(s)) ) {
                using( StreamReader sr = new StreamReader(ms, encoding) ) {
                    return (T)mySerializer.Deserialize(sr);
                }
            }
        }

        /// <summary>
        /// 读入一个文件,并按XML的方式反序列化对象。
        /// </summary>
        /// <typeparam name="T">结果对象类型</typeparam>
        /// <param name="path">文件路径</param>
        /// <param name="encoding">编码方式</param>
        /// <returns>反序列化得到的对象</returns>
        public static T XmlDeserializeFromFile<T>(string path, Encoding encoding)
        {
            if( string.IsNullOrEmpty(path) )
                throw new ArgumentNullException("path");
            if( encoding == null )
                throw new ArgumentNullException("encoding");

            string xml = File.ReadAllText(path, encoding);
            return XmlDeserialize<T>(xml, encoding);
        }
    }
}

兴许有人会说:笔者动用XPath从XML读取数据也非常粗略啊。
自家认为这种说法有二个限制条件:只需求从XML中读取一点点的数额。
借使要全套读取,用这种方法会写出一大堆的教条代码出来! 所以,小编相当嫌恶用这种艺术从XML中读取全体多少。

归来顶端

类型定义与XML结构的映照

万风流洒脱是一个新品类,笔者自然会当机立断的选取体系化和反连串化的法子来使用XML, 但是,不时在保养三个老品种时,面临一批独有XML却未有与之相应的C#品类时, 大家就需求基于XML结构来逆向推导C#花色,然后工夫应用种类化和反类别化的法子。 逆向推导的长河是麻烦的,可是,类型推导出来以后,前边的事务就轻松多了。

为了学会依照XML结构逆向推导类型,大家需求关怀一下类型定义与XML结构的映射关系。
在乎:有的时候候大家也会设想XML结构对于传输量及可阅读性的熏陶,所以关心一下XML也许有必不可缺的。

此处有几个XML文件,是作者从Visual Sutdio的设置目录中找到的: 澳门新萄京app 2

<DynamicHelp xmlns="http://msdn.microsoft.com/vsdata/xsd/vsdh.xsd" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:schemaLocation="http://msdn.microsoft.com/vsdata/xsd/vsdh.xsd vsdh.xsd">
    <LinkGroup ID="sites" Title="Venus Sites" Priority="1500">
        <Glyph Collapsed="3" Expanded="4"/>
    </LinkGroup>
    <LinkGroup ID="Venus Private Forums" Title="Venus Private Forums" Priority="1400">
        <Glyph Collapsed="3" Expanded="4"/>
    </LinkGroup>
    <LinkGroup ID="ASP.NET Forums" Title="ASP.NET 1.0 Public Forums" Priority="1200">
        <Glyph Collapsed="3" Expanded="4"/>
    </LinkGroup>
    <Context>
        <Links>
            <LItem URL="http://www.asp.net/venus" LinkGroup="sites">Venus Home Page</LItem>
            <LItem URL="http://www.asp.net" LinkGroup="sites">ASP.NET Home Page</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=77" 
                    LinkGroup="Venus Private Forums">General Discussions</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=83" 
                    LinkGroup="Venus Private Forums">Feature Requests</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=78" 
                    LinkGroup="Venus Private Forums">Bug Reports</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=86" 
                    LinkGroup="Venus Private Forums">ASP.NET 2.0 Related issues</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=11" 
                    LinkGroup="ASP.NET Forums">Announcements</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=15" 
                    LinkGroup="ASP.NET Forums">Getting Started</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=18" 
                    LinkGroup="ASP.NET Forums">Web Forms</LItem>
        </Links>
    </Context>
</DynamicHelp>

什么用反类别化的方法来读取它的数码吧,我在博客的最终将送交完整的兑今世码。
现行反革命,大家照旧看一下那个XML有如何特征吗。

<LinkGroup ID="sites" Title="Venus Sites" Priority="1500">

对于这么些节点的话,它蕴含了多少个数据项(属性):ID,Title,Priority。 那样的LinkGroup节点有多个。
看似的还应该有Glyph节点。

<LItem URL="http://www.asp.net" LinkGroup="sites">ASP.NET Home Page</LItem>

LItem节点除了与LinkGroup有着近乎的多寡(属性)之外,还富含着一个字符串:ASP.NET Home Page , 这是别的意气风发种多少的存放方式。

别的,LinkGroup和LItem都同意再现,我们能够用数组大概列表(Array,List)来精晓它们。

自己还开掘部分嵌套关系:LinkGroup能够包涵Glyph,Context包罗着Links,Links又满含了八个LItem。
不论如何嵌套,笔者开采数目都是含有在三个二个的XML节点中。

若果用专门的学业的单词来汇报它们,大家可以将ID,Title,Priority那三个数据项称为 XmlAttribute, LItem,LinkGroup节点称为 XmlElement,”ASP.NET Home Page“出现的职位能够叫做 InnerText。 基本上,XML正是由那三类数据整合。

上边我来演示怎样利用那二种多少项。

回去最上部

使用 XmlElement

先是,小编来定义叁个门类:

public class Class1
{
    public int IntValue { get; set; }

    public string StrValue { get; set; }
}

上面是系列化与反类别的调用代码:

Class1 c1 = new Class1 { IntValue = 3, StrValue = "Fish Li" };
string xml = XmlHelper.XmlSerialize(c1, Encoding.UTF8);
Console.WriteLine(xml);

Console.WriteLine("---------------------------------------");

Class1 c2 = XmlHelper.XmlDeserialize<Class1>(xml, Encoding.UTF8);
Console.WriteLine("IntValue: " + c2.IntValue.ToString());
Console.WriteLine("StrValue: " + c2.StrValue);

运作结果如下:

<?xml version="1.0" encoding="utf-8"?>
<Class1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <IntValue>3</IntValue>
    <StrValue>Fish Li</StrValue>
</Class1>
---------------------------------------
IntValue: 3
StrValue: Fish Li

结果呈现,IntValue和StrValue那三个属性生成了XmlElement。

总计:暗中认可意况下(不加任何Attribute),类型中的属性也许字段,都会生成XmlElement。

回去最上端

使用 XmlAttribute

再来定义三个等级次序:

public class Class2
{
    [XmlAttribute]
    public int IntValue { get; set; }

    [XmlElement]
    public string StrValue { get; set; }
}

在乎,笔者在三本性情上加码的例外的Attribute.

下边是系列化与反系列的调用代码: 澳门新萄京app 3

Class2 c1 = new Class2 { IntValue = 3, StrValue = "Fish Li" };
string xml = XmlHelper.XmlSerialize(c1, Encoding.UTF8);
Console.WriteLine(xml);

Console.WriteLine("---------------------------------------");

Class2 c2 = XmlHelper.XmlDeserialize<Class2>(xml, Encoding.UTF8);
Console.WriteLine("IntValue: " + c2.IntValue.ToString());
Console.WriteLine("StrValue: " + c2.StrValue);

运转结果如下(作者将结果做了换行管理):

<?xml version="1.0" encoding="utf-8"?>
<Class2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
        IntValue="3">
    <StrValue>Fish Li</StrValue>
</Class2>
---------------------------------------
IntValue: 3
StrValue: Fish Li

结果展现:

  1. IntValue 生成了XmlAttribute
  2. StrValue 生成了XmlElement(和不加[XmlElement]的功效相同,表示正是私下认可行为)。

总括:如若指望项目中的属性恐怕字段生成XmlAttribute,必要在项指标积极分子上用[XmlAttribute]来指出。

归来顶端

使用 InnerText

如故来定义一个品种:

public class Class3
{
    [XmlAttribute]
    public int IntValue { get; set; }

    [XmlText]
    public string StrValue { get; set; }
}

注意,作者在StrValue上扩展的两样的Attribute.

上边是类别化与反类别的调用代码: 澳门新萄京app 4

Class3 c1 = new Class3 { IntValue = 3, StrValue = "Fish Li" };
string xml = XmlHelper.XmlSerialize(c1, Encoding.UTF8);
Console.WriteLine(xml);

Console.WriteLine("---------------------------------------");

Class3 c2 = XmlHelper.XmlDeserialize<Class3>(xml, Encoding.UTF8);
Console.WriteLine("IntValue: " + c2.IntValue.ToString());
Console.WriteLine("StrValue: " + c2.StrValue);

运作结果如下(小编将结果做了换行管理):

<?xml version="1.0" encoding="utf-8"?>
<Class3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    IntValue="3">Fish Li</Class3>
---------------------------------------
IntValue: 3
StrValue: Fish Li

结果相符预期:StrValue属性在增添了[XmlText]而后,生成了四个文件节点(InnerText)

计算:假如期望项目中的属性大概字段生成InnerText,须求在项目标分子上用[XmlText]来指出。

回到顶上部分

重命名节点名称

看过后边多少个示范,大家应该能发掘:通过系列化拿到的XmlElement和XmlAttribute都与类型的数额成员要么项目同名。 但是不经常候我们得以期望让属性名与XML的节点名称不平等,那么快要动用【重命名】的魔法了,请看之下示例:

[XmlType("c4")]
public class Class4
{
    [XmlAttribute("id")]
    public int IntValue { get; set; }

    [XmlElement("name")]
    public string StrValue { get; set; }
}

体系化与反类别的调用代码前面早就三回九转看来,这里就总结它们了。
运作结果如下(小编将结果做了换行管理):

<?xml version="1.0" encoding="utf-8"?>
<c4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    id="3">
    <name>Fish Li</name>
</c4>
---------------------------------------
IntValue: 3
StrValue: Fish Li

寻访输出结果中的红字粗体字,再看看类型定义中的四个Attribute的多少个字符串参数,小编想你能觉察规律的。

计算:XmlAttribute,XmlElement允许选择一个小名用来决定转换节点的名号,类型的重命名用XmlType来落实。

归来最上部

列表和数组的种类化

后续看示例代码:

Class4 c1 = new Class4 { IntValue = 3, StrValue = "Fish Li" };
Class4 c2 = new Class4 { IntValue = 4, StrValue = "http://www.cnblogs.com/fish-li/" };

// 说明:下面二行代码的输出结果是一样的。
List<Class4> list = new List<Class4> { c1, c2 };
//Class4[] list = new Class4[] { c1, c2 };

string xml = XmlHelper.XmlSerialize(list, Encoding.UTF8);
Console.WriteLine(xml);

// 序列化的结果,反序列化一定能读取,所以就不再测试反序列化了。

运作结果如下:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfC4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <c4 id="3">
        <name>Fish Li</name>
    </c4>
    <c4 id="4">
        <name>http://www.cnblogs.com/fish-li/</name>
    </c4>
</ArrayOfC4>

前段时间c4节点已经重新现身了,显著,是我们盼望的结果。

不过,ArrayOfC4,那个节点名看起来太难以置信了,能或无法给它也重命名呢?
持续看代码,小编能够定义二个新的连串:

// 二种Attribute都可以完成同样的功能。
//[XmlType("c4List")]
[XmlRoot("c4List")]
public class Class4List : List<Class4> { }

接下来,改一下调用代码:

Class4List list = new Class4List { c1, c2 };

运作结果如下:

<?xml version="1.0" encoding="utf-8"?>
<c4List xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <c4 id="3">
        <name>Fish Li</name>
    </c4>
    <c4 id="4">
        <name>http://www.cnblogs.com/fish-li/</name>
    </c4>
</c4List>

总计:数组和列表都能平素体系化,假若要重命名根节点名称,须要创立二个新类型来达成。

回到顶端

列表和数组的做为数据成员的体系化

首先,依然定义三个项目:

public class Root
{
    public Class3 Class3 { get; set; }

    public List<Class2> List { get; set; }
}

连串化的调用代码:

Class2 c1 = new Class2 { IntValue = 3, StrValue = "Fish Li" };
Class2 c2 = new Class2 { IntValue = 4, StrValue = "http://www.cnblogs.com/fish-li/" };

Class3 c3 = new Class3 { IntValue = 5, StrValue = "Test List" };

Root root = new Root { Class3 = c3, List = new List<Class2> { c1, c2 } };

string xml = XmlHelper.XmlSerialize(root, Encoding.UTF8);
Console.WriteLine(xml);

运行结果如下:

<?xml version="1.0" encoding="utf-8"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Class3 IntValue="5">Test List</Class3>
    <List>
        <Class2 IntValue="3">
            <StrValue>Fish Li</StrValue>
        </Class2>
        <Class2 IntValue="4">
            <StrValue>http://www.cnblogs.com/fish-li/</StrValue>
        </Class2>
    </List>
</Root>

若是这里需求为List和Class2的节点重命名,该如何做呢?
假定持续应用前边介绍的方法,是无用的。

下边包车型客车代码演示了怎样重命名列表节点的称呼:

public class Root
{
    public Class3 Class3 { get; set; }

    [XmlArrayItem("c2")]
    [XmlArray("cccccccccccc")]
    public List<Class2> List { get; set; }
}

种类化的调用代码与前边完全平等,获得的出口结果如下:

<?xml version="1.0" encoding="utf-8"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Class3 IntValue="5">Test List</Class3>
    <cccccccccccc>
        <c2 IntValue="3">
            <StrValue>Fish Li</StrValue>
        </c2>
        <c2 IntValue="4">
            <StrValue>http://www.cnblogs.com/fish-li/</StrValue>
        </c2>
    </cccccccccccc>
</Root>

想不想把cccccccccccc节点去掉吧(直接出现c2节点)?
下边包车型地铁类型定义格局达成了这一个主张:

public class Root
{
    public Class3 Class3 { get; set; }

    [XmlElement("c2")]
    public List<Class2> List { get; set; }
}

出口结果如下:

<?xml version="1.0" encoding="utf-8"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Class3 IntValue="5">Test List</Class3>
    <c2 IntValue="3">
        <StrValue>Fish Li</StrValue>
    </c2>
    <c2 IntValue="4">
        <StrValue>http://www.cnblogs.com/fish-li/</StrValue>
    </c2>
</Root>

总括:数组和列表都在连串化时,暗中认可情形下会依据项目中的数据成员名称更换一个节点, 列表项会生成子节点,借使要重命名,能够使用[XmlArrayItem]和[XmlArray]来兑现。 还足以一向用[XmlElement]决定不生成列表的父节点。

重回顶端

种类承接与反系列化

列表成分得以是同等系列型,也得以不是平等种类型(有些项指标派生类)。
举个例子下边包车型大巴XML:

<?xml version="1.0" encoding="utf-8"?>
<XRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <List>
        <x1 aa="1" bb="2" />
        <x1 aa="3" bb="4" />
        <x2>
            <cc>ccccccccccc</cc>
            <dd>dddddddddddd</dd>
        </x2>
    </List>
</XRoot>

想像一下,上边这段XML是透过哪些项目获得的啊?

答案如下(注意深中绿粗体部分):

public class XBase { }

[XmlType("x1")]
public class X1 : XBase
{
    [XmlAttribute("aa")]
    public int AA { get; set; }

    [XmlAttribute("bb")]
    public int BB { get; set; }
}

[XmlType("x2")]
public class X2 : XBase
{
    [XmlElement("cc")]
    public string CC { get; set; }

    [XmlElement("dd")]
    public string DD { get; set; }
}

public class XRoot
{
    [XmlArrayItem(typeof(X1)),
    XmlArrayItem(typeof(X2))]
    public List<XBase> List { get; set; }
}

连串化代码:

X1 x1a = new X1 { AA = 1, BB = 2 };
X1 x1b = new X1 { AA = 3, BB = 4 };
X2 x2 = new X2 { CC = "ccccccccccc", DD = "dddddddddddd" };
XRoot root = new XRoot { List = new List<XBase> { x1a, x1b, x2 } };

string xml = XmlHelper.XmlSerialize(root, Encoding.UTF8);
Console.WriteLine(xml);

计算:同时为列表成员钦赐多个[XmlArrayItem(typeof(XXX))]可实现四种派生类型混在共同输出。

回来顶端

反类别化的实战演习

接下去,大家将依照前边介绍的知识点,用反序列化的艺术来深入分析本文起先处贴出的这段XML: 澳门新萄京app 5

<DynamicHelp xmlns="http://msdn.microsoft.com/vsdata/xsd/vsdh.xsd" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:schemaLocation="http://msdn.microsoft.com/vsdata/xsd/vsdh.xsd vsdh.xsd">
    <LinkGroup ID="sites" Title="Venus Sites" Priority="1500">
        <Glyph Collapsed="3" Expanded="4"/>
    </LinkGroup>
    <LinkGroup ID="Venus Private Forums" Title="Venus Private Forums" Priority="1400">
        <Glyph Collapsed="3" Expanded="4"/>
    </LinkGroup>
    <LinkGroup ID="ASP.NET Forums" Title="ASP.NET 1.0 Public Forums" Priority="1200">
        <Glyph Collapsed="3" Expanded="4"/>
    </LinkGroup>
    <Context>
        <Links>
            <LItem URL="http://www.asp.net/venus" LinkGroup="sites">Venus Home Page</LItem>
            <LItem URL="http://www.asp.net" LinkGroup="sites">ASP.NET Home Page</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=77" 
                    LinkGroup="Venus Private Forums">General Discussions</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=83" 
                    LinkGroup="Venus Private Forums">Feature Requests</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=78" 
                    LinkGroup="Venus Private Forums">Bug Reports</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=86" 
                    LinkGroup="Venus Private Forums">ASP.NET 2.0 Related issues</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=11" 
                    LinkGroup="ASP.NET Forums">Announcements</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=15" 
                    LinkGroup="ASP.NET Forums">Getting Started</LItem>
            <LItem URL="http://www.asp.net/Forums/ShowForum.aspx?tabindex=1&amp;ForumID=18" 
                    LinkGroup="ASP.NET Forums">Web Forms</LItem>
        </Links>
    </Context>
</DynamicHelp>

这段XML的根成分是DynamicHelp,由此,大家须要定义三个项目,类名为DynamicHelp。
再观看那段XML,它应该包括二个LinkGroup列表,和多少个Context属性,所以可以如此定义那多个品类:

public class DynamicHelp
{
    [XmlElement]
    public List<LinkGroup> Groups { get; set; }

    public Context Context { get; set; }
}

public class LinkGroup { }

public class Context { }

再来看LinkGroup,它包蕴四个数据成员,以致三个子节点:Glyph,由此得以这么定义它们:

public class LinkGroup 
{
    [XmlAttribute]
    public string ID { get; set; }
    [XmlAttribute]
    public string Title { get; set; }
    [XmlAttribute]
    public int Priority { get; set; }

    public Glyph Glyph { get; set; }
}

public class Glyph
{
    [XmlAttribute]
    public int Collapsed { get; set; }
    [XmlAttribute]
    public int Expanded { get; set; }
}

LItem节点也简要,它就含有了U大切诺基L,LinkGroup和三个文本节点,由此能够那样定义它:

public class LItem
{
    [XmlAttribute]
    public string URL { get; set; }
    [XmlAttribute]
    public string LinkGroup { get; set; }

    [XmlText]
    public string Title { get; set; }
}

Context节点也不复杂,就只蕴含了八个LItem列表,因而得以如此定义它:

public class Context 
{
    public List<LItem> Links { get; set; }
}

好了,类型都定义好了,再来试试反连串化:

DynamicHelp help = XmlHelper.XmlDeserializeFromFile<DynamicHelp>("Links.xml", Encoding.UTF8);

foreach( LinkGroup group in help.Groups )
    Console.WriteLine("ID: {0}, Title: {1}, Priority: {2}, Collapsed: {3}, Expanded: {4}",
        group.ID, group.Title, group.Priority, group.Glyph.Collapsed, group.Glyph.Expanded);

foreach( LItem item in help.Context.Links )
    Console.WriteLine("URL: {0}, LinkGroup: {1}, Title: {2}",
        item.URL.Substring(0, 15), item.LinkGroup, item.Title);

显示器展现:

未处理的异常:  System.InvalidOperationException: XML 文档(4, 2)中有错误。 
---> System.InvalidOperationException: 不应有 
<DynamicHelp xmlns='http://msdn.microsoft.com/vsdata/xsd/vsdh.xsd'>。

嗯,抛相当了。
别急,看看这个说哪些。
恍如是在说命名空间无法辨别。
听新闻说卓殊的汇报,小编还要修改一下DynamicHelp的概念,改成这么:

[XmlRoot(Namespace = "http://msdn.microsoft.com/vsdata/xsd/vsdh.xsd")]
public class DynamicHelp

再也运营,结果如下:

ID: sites, Title: Venus Sites, Priority: 1500, Collapsed: 3, Expanded: 4
ID: Venus Private Forums, Title: Venus Private Forums, Priority: 1400, Collapsed: 3, Expanded: 4
ID: ASP.NET Forums, Title: ASP.NET 1.0 Public Forums, Priority: 1200, Collapsed: 3, Expanded: 4
URL: http://www.asp., LinkGroup: sites, Title: Venus Home Page
URL: http://www.asp., LinkGroup: sites, Title: ASP.NET Home Page
URL: http://www.asp., LinkGroup: Venus Private Forums, Title: General Discussions
URL: http://www.asp., LinkGroup: Venus Private Forums, Title: Feature Requests
URL: http://www.asp., LinkGroup: Venus Private Forums, Title: Bug Reports
URL: http://www.asp., LinkGroup: Venus Private Forums, Title: ASP.NET 2.0 Related issues
URL: http://www.asp., LinkGroup: ASP.NET Forums, Title: Announcements
URL: http://www.asp., LinkGroup: ASP.NET Forums, Title: Getting Started
URL: http://www.asp., LinkGroup: ASP.NET Forums, Title: Web Forms

计算:依照XML结构推导类型时,要力保项目标等级次序结构与XML相称, 数据的寄存形式得以经过[XmlElement],[XmlAttribute],[XmlText]办法来提出。

归来顶上部分

反类别化的选拔总计

假诺XML是由项目体系化获得那的,那么反系列化的调用代码是很简单的,
反之,要是要面临一个未有项目标XML,就要求大家先规划一个(大概局地)类型出来,
那是三个逆向推导的进程,请仿照效法以下步骤:

  1. 第活龙活现要剖判任何XML结构,定义与之合营的连串,
  2. 假诺XML结构有嵌套档案的次序,则供给定义七个类型与之相称,
  3. 概念具体品种(三个层级下的XML结构)时,请参见以下表格。

XML形式

拍卖措施

填补表明

XmlElement

概念三个属性

属性名与节点名字相配

XmlAttribute

[XmlAttribute] 加到属性上

 

InnerText

[XmlText] 加到属性上

三个项目只可以利用叁回

节点重命名

根节点:[XmlType("testClass")]
要凉秋点:[XmlElement("name")]
属性节点:[XmlAttribute("id")]
列表子成分节点:[XmlArrayItem("Detail")]
列表成分自个儿:[XmlArray("Items")]

 

回来最上部

免除无需连串化的积极分子

暗中认可情形下,类型的具有公开的多寡成员(属性,字段)在类别化时都会被输出, 假诺希望化解有个别成员,能够用[XmlIgnore]来指出,例如:

public class TestIgnore
{
    [XmlIgnore]    // 这个属性将不会参与序列化
    public int IntValue { get; set; }

    public string StrValue { get; set; }

    public string Url;
}

连串化调用代码:

TestIgnore c1 = new TestIgnore { IntValue = 3, StrValue = "Fish Li" };
c1.Url = "http://www.cnblogs.com/fish-li/";

string xml = XmlHelper.XmlSerialize(c1, Encoding.UTF8);
Console.WriteLine(xml);

输出结果如下:

<?xml version="1.0" encoding="utf-8"?>
<TestIgnore xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Url>http://www.cnblogs.com/fish-li/</Url>
    <StrValue>Fish Li</StrValue>
</TestIgnore>

归来最上部

强制内定成员的系列化顺序

前面包车型地铁示范很想得到,笔者掌握先定义的StrValue,后定义的Url,可是在输出时的各样并是笔者梦想的。
后生可畏经你指望调控种类化的出口顺序,能够参见上边包车型大巴演示代码(注意紫灰粗体文字):

public class TestIgnore
{
    [XmlIgnore]    // 这个属性将不会参与序列化
    public int IntValue { get; set; }

    [XmlElement(Order = 1)]
    public string StrValue { get; set; }

    [XmlElement(Order = 2)]
    public string Url;
}

最后的出口结果如下:

<?xml version="1.0" encoding="utf-8"?>
<TestIgnore xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <StrValue>Fish Li</StrValue>
    <Url>http://www.cnblogs.com/fish-li/</Url>
</TestIgnore>

再次回到顶上部分

自定义连串化行为

出于种种原因,大概需求我们团结决定种类化和反连串化的经过, 对于这种须求, .net framework也是永葆的,下边小编来演示怎么样这么些进度。

若果笔者昨天有如此的类型定义:

public class TestClass
{
    public string StrValue { get; set; }

    public List<int> List { get; set; }
}

public class ClassB1
{
    public TestClass Test { get; set; }
}

测量试验代码:

TestClass test = new TestClass { StrValue = "Fish Li", List = new List<int> { 1, 2, 3, 4, 5 } };
ClassB1 b1 = new ClassB1 { Test = test };

string xml = XmlHelper.XmlSerialize(b1, Encoding.UTF8);
Console.WriteLine(xml);

Console.WriteLine("-----------------------------------------------------");

ClassB1 b2 = XmlHelper.XmlDeserialize<ClassB1>(xml, Encoding.UTF8);
Console.WriteLine("StrValue: " + b2.Test.StrValue);
foreach( int n in b2.Test.List )
    Console.WriteLine(n);

这时候前后相继的出口结果如下:

<?xml version="1.0" encoding="utf-8"?>
<ClassB1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Test>
        <StrValue>Fish Li</StrValue>
        <List>
            <int>1</int>
            <int>2</int>
            <int>3</int>
            <int>4</int>
            <int>5</int>
        </List>
    </Test>
</ClassB1>
-----------------------------------------------------
StrValue: Fish Li
1
2
3
4
5

先天我说不定会想:TestClass那些类太轻巧了,但它输出的XML长度复杂了点,能还是无法再短小一些,让网络传输地越来越快吗?

在此边,作者想开了自定义系列化行为来落实,请看下边前境遇TestClass的重复定义。

public class TestClass : IXmlSerializable
{
    public string StrValue { get; set; }

    public List<int> List { get; set; }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        StrValue = reader.GetAttribute("s");

        string numbers = reader.ReadString();
        if( string.IsNullOrEmpty(numbers) == false )
            List = (from s in numbers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                    let n = int.Parse(s)
                    select n).ToList();
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("s", StrValue);
        writer.WriteString(string.Join(",", List.ConvertAll<string>(x => x.ToString()).ToArray()));
    }
}

继续使用前面包车型客车测量试验代码,以后的出口结果如下:

<?xml version="1.0" encoding="utf-8"?>
<ClassB1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Test s="Fish Li">1,2,3,4,5</Test>
</ClassB1>
-----------------------------------------------------
StrValue: Fish Li
1
2
3
4
5

很分明,今后的类别化结果要比在此早先的结果小非常多。
还要,测量检验代码中的反类别化的呈现也标志,大家依然能够经过反种类化来读取它。

回来顶上部分

系列化去掉XML命名空间及注脚头

在前方的身体力行中,大家会发掘一时很简短的XML在加了命名空间及注明头以往,结构变复杂了,内容也变长了。 某人会见它们只怕总是以为格外别扭,比方:

<?xml version="1.0" encoding="utf-8"?>
<ClassB1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Test s="Fish Li">1,2,3,4,5</Test>
</ClassB1>

能或不能够只显示成下边那样呢?

<ClassB1>
    <Test s="Fish Li">1,2,3,4,5</Test>
</ClassB1>

答案是不容争辩的,按上边包车型客车章程修改本文的示范代码:

private static void XmlSerializeInternal(Stream stream, object o, Encoding encoding)
{
    if( o == null )
        throw new ArgumentNullException("o");
    if( encoding == null )
        throw new ArgumentNullException("encoding");

    XmlSerializer serializer = new XmlSerializer(o.GetType());

    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.NewLineChars = "rn";
    settings.Encoding = encoding;
    settings.IndentChars = "    ";

    // 不生成声明头
    settings.OmitXmlDeclaration = true;

    // 强制指定命名空间,覆盖默认的命名空间。
    XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
    namespaces.Add(string.Empty, string.Empty);

    using( XmlWriter writer = XmlWriter.Create(stream, settings) ) {
        serializer.Serialize(writer, o, namespaces);
        writer.Close();
    }
}

表达:去掉XML命名空间及注解头不影响反类别化。

再次来到最上端

XML的施用建议

在服务端,C#代码中:

  1. 提议并不是采取低端别的XML API来选择XML,除非你是在安顿框架大概通用类库。
  2. 建议利用系列化、反种类化的秘技来扭转依旧读取XML
    3. 当必要思索选择XML时,先不要想着XML结构,先应该定义好数据类型。
    4. 列表节点不要使用[XmlElement]澳门新萄京app,,它会让全体子节点【进级】,显得结构混乱。
    5. 黄金年代旦期望体系化的XML长度小一些,能够接收[XmlAttribute],大概钦点二个更加短小的别称。
  3. 毫不在一个列表中输出区别的数据类型,那样的XML结构的可读性倒霉。
  4. 尽量选拔UTF-8编码,不要选拔GB2312编码。

在顾客端,JavaScript代码中,作者不建议选拔XML,而是提出使用JSON来代表XML,因为:
1. XML文件的尺寸比JSON要长,会攻克越来越多的互联网传输时间(究竟数据保存在服务端,所以传输是免不了的)
2. 在JavaScritp中应用XML相比艰辛(还可能有浏览器的宽容难点),反而各类浏览器对JSON有万分好的支撑。

本文由澳门新萄京app发布于澳门新萄京app,转载请注明出处:转发过来学习学习

关键词:

上一篇:基础数据类型之列表
下一篇:没有了