XML概述
首先说一下,这一部分咱们重点讲解一下关于在.NET中操作XML,前面好像说过关于LINQ to XML,不知打你们还记得多少?反正楼主是一点都不记得了.哈哈
今天学的知识是为了什么?为了明天的荒废...
这是韩寒说的!
韩寒说的对啊!
这句话是我说的!!!
为啥要有XML呢?
XML----可扩展标记语言.通过名字完全不明白XML是个啥玩意.实际上不用关心XML的名字,你需要明白的是XML是用来干啥的就好.在学一门新东西的时候,你需要问自己三个问题:它是啥?它有啥用?我为啥要学它?
XML的主要用途是用来描述和交换数据的.
先从XML的一个应用说起:应用程序配置文件.应用程序经常需要一些参数,而这些参数与本地计算机的运行环境或用户设置有关.因此,为了方便对应用程序进行部署,需要将这些参数保存在配置文件中供应用程序读取或写入,使得应用程序在部署后不需要重新编译,只需要修改配置文件中的参数就可.常见的配置参数有数据库连接字符串,网络IP和端口设置,日志保存路径等.在.NET应用程序中,这些配置通常保存在一个后缀名为.config的文件中,使用记事本打开应该能看出来是一个标准的XML文件.
所以,应用程序配置文件的作用是描述程序外部的参数信息,并供应用程序所用.
在以前还没有XML的时候,一般是使用纯文本来保存配置信息的,比如新建一个config.txt或config.ini文件(只是后缀不同),然后将这些信息以”key-value”的方式保存起来,例如:
ConnectionString=Data Source=Syx--PC;Initial Catalog=TestDB;User ID=sa;pwd=123456
IP=192.168.3.19
port=8080
LogFolder=D:\LogFiles
使用以上的方式进行保存有这么几个问题:
1.)结构散乱,如果要配置多个连接字符串或者多个TCP端口,文件结构就会变成这样了:
ConnectionString1=...
ConnectionString2=...
IP1=...
Port1=...
IP2=...
Port2=...
2.)读取不方便.如果要读取IP2的值,需要逐行读取,并判断”=”的左边是否是IP2,如果是,区”=”右边的值.
3.)写入不方便.如果在ConnectionString2后面多添加一个ConnectionString3,那么就会非常麻烦.
4.)读写配置文件的API需要自行编号.
大家应该多多少少的了解过HTML或者XHTML吧,为了解决上面的问题,我们就引入了类似HTML的标记语法来重新编写配置文件.对于上面的案例:
<ConnectionStrings>
<ConnectionString name=”SQLLite”>...</ConnectionString>
<ConnectionString name=”MySql”>...</ConnectionString>
<ConnectionString name=”MSSQL”>...</ConnectionString>
</ConnectionStrings>
<TCPSettings>
<ip port=”8001”>192.168.3.3</ip>
<ip port=”8002”>192.168.3.2</ip>
<ip port=”8003”>192.168.3.1</ip>
</TCPSettings>
在HTML中,标记(tag)是关注结构和表现得,而非语义的.例如,<p>...</p>是关注结构的,说明这是一个段落,但是没有说明标记之间是啥内容;<b>...</b>是关注表现得,说明标记之间的字体应该加粗,没说标记之间是啥内容.对于本例的配置文件来说,标记是关注语义的,它本身也具有含义,说明了标记之间包含的是什么内容.例如<TCPSettings/>,说明了标记内是关于TCP的设置.
我们不提倡HTML中使用关注表现的标记,例如<font/>,<center/>,<b/>等,表现应该有CSS去完成.
上面咱们自创了一个配置文件,这个文件就是”XML文档”.XML和HTML不同的是:XML没有任何自己的标记,完全由开发者定义标记.
但是XML也是需要符合规则的.这些规则不多,只要符合了这些规则开发者就可以自由发挥和创作了.
对于HTML来说,不仅规则是固定了,标记也是固定的,不能使用自定义的标记. XML是一组规则,而HTML是基于这组规则的一个应用,适用于描述Web页面,而SVG是XML的另一个应用,适用于描述适量图形.
本例中定义的标记<TCPSettings>,从地位上来所,和HTML,SVG是一样的,只不过是属于我们独立的应用,应用于描述应用程序配置.
HTML和XHTML的最重要的区别是XHTML符合XML的规则,但是HTML不完全符合.
可能会有人问,如果采用了这种XML的写法貌似对采用纯文本的”key-value”还麻烦,别急,我们采用XML的最主要的原因是我们有一套关于操作XML的API.我们通常有以下几种处理方式:
(1).类似ADO.NET中的DataSet,一次性将数据全部读取到DataSet中,然后便可以对DataSet中任意位置的数据进行读取,修改,删除,写入.我们也可以创建一个List<string>用来保存文档内容,先使用StreamReader读取配置文件的每一行,然后添加至List<string>,最后guanbiStreamReader.采用这种方式的特点:在得到List<string>之后,可以使用索引访问List<string>的任意位置,但因为整个文档分成分成行存放在了List<string>中,会比较占用内存.
(2).类似ADO.NET中的DbDataReader,采用单向,只读的方式逐行读取,读取一行的处理一行,从文档头读取到文档末尾.此时,虽然同样是使用StreamReader,但只需要一个string变量保存读取的一行,然后对它进行处理.采用这种方式的特点是:快速,集合不占用什么内存.这种湖区数据的模式也叫做拉模式.
(3).与(2)类似,但使用事件注册,通知机制,即采用推模式(push).由读取文档的类型发布事件,没读到一行,就将读到的数据推给注册事件的客户端对象或程序.
现在读写配置文件的需要很普遍,几乎所有的应用程序都需要用到,所以有一套规范,关于这套规范你自己在网上搜搜吧,我不写了.
注意:在C#中,属性的英文是Property,Attribute通常翻译为特性.但在XML中,属性的英文是Attribute.
与上面三种方式类似的是XML的处理模型
1.XML DOM队里XML文档的方式和前面的1类似,只不过,它不是用List<string>将XML文档分成多个行来保存,而是将XML文档呈现为一个节点树.XML DOM处理XML文档的特点和1也是一样的,可以访问任意节点,可以对节点增删改查,但是需要的内存较大.
2.XmlReader和XmlWrite
.NET中提供了System.Xml.XmlReader和System.Xml.XmlWriter两个基础类型用于单向的,只读/只写的操作.这两个类型的操作方式和前面的2是类似的.区别是StreamReader是逐行读取,XmlReader针对于XML的树形结构,是逐节点读取.
3.SAX
SAX是用于XML文档的事件驱动的推模式,和前面的3类似.虽然不是W3c的标准,但是是一个被广泛认可的API,SAX的缺点是会推送所有的数据过来,不论是需要还是不需要的,因此要在事件处理程序中进行筛选和处理.在.NET中没有对SAX提供支持,但是尅通过包装XmlReader模拟出和SAX一样的效果.
XML验证----XSD,DTD和XDR
XML标准定义了什么样的XML是格式良好的,但是它不一定是有效的.前面说了XML的存储作用,现在来说下XML的另一个作用----交换数据.
假设开发了一个基于XML的影片资料库程序,它可以接受各个影院发来的新近上映的电影信息的XML文档.程序在接受XML文档之后,可以读取其中的数据,然后进行处理,比如存入中心数据库.对于影片数据库,它接受的XML格式为:
<?xml version="1.0" encoding="utf-8" ?>
<movieList>
<moive>
<title>影片名</title>
<director>导演</director>
<starring>主演</starring>
<genre>类型</genre>
<releaseDate>上映日期</releaseDate>
</moive>
<movie>
...
</movie>
</movieList>
显然上面的XML格式是正确的,但它不一定是有效的.啥意思?XML的结构良好与文档有效的关系类似于C#中语法正确(编译通过),但运行时报错.比如这样的语句:
int index=Convert.ToInt32(“abcd”);
从语法上来说,没问题,但是在运行时,就会报错,因为字符串abcd无法转换为int类型.
XML文档也是类似的,尽管结构正确.但对于元素releaseDate来说,可以接受的文本是日期了日行,例如2012-2-2;对于元素genre来说,可以接受的可能是一个枚举,如果没有东西来约束,所有元素的文本,属性的值,都会视为字符串类型.因此,影院实际发来的XML文档,可能与应用程序所期望的不完全一致,比方说,releaseDate的文本为”March 13,2012”.甚至,影院可能会自作主张,修改XML的文档结构,为XML多添加一个元素,比如nation(国家);或者,将starring元素扩展为树形结构,比如:
<starring>
<actor>主演A</actor>
<actor>主演B</actor>
<actor>主演C</actor>
</starring>
解决这个问题大致有三种方式:
(1).将影院管理程序所期望的XML格式写成一份说明书(例如,”影片XL文档结构说明.doc”),然后发给各个影院,要求他们按扎个说明书来生成XML文档.但影院是否照做就是另外一回事了.
(2).在XML的数据处理 程序中朱哥去检查XML的文档结构,每一个元素,属性的值是否正确.这将很麻烦,而且耦合性太高:应用程序本身应有的主要逻辑----获取并处理数据和校验XML结构是否正确,内容是否合法耦合在了一起.
(3).编写一个文档,该文档定义了XML文档的结构,标记,属性,属性值,文本值等一切信息,相当于XML文档的”元数据”.并且,该文档可以由程序进行处理,对目标XML进行验证.有了这个文档之后,就可以在程序中将校验XML文档结构和处理数据的逻辑分离开来,即松耦合.
第三种方式是最好的,为啥?这种定义了XML的结构和内容,用于验证XML有效性的文档,和XML一样,也制定成了标准或者规范,分别是XSD,DTD和XDR.他们和XML文档的关系如下 :
提示:如果设计的XML仅仅是为了自己使用,比方应用程序配置,或者数据存储(将对象序列化为XML进行保存),不存在与第三方进行数据交换,那么,是不需要进行有效性验证的,因为我们没有必要自讨苦处,写入明知道非法的数据.
关于XSD,DTD,XDR的内容如果感兴趣自己去百度吧.
XML格式转换----XSLT
XSLT的作用是将一种格式的XML转换为另一种.通常,我们设计的XML文档只适用于某一特定领域,而如果想要应用于另一领域,则需要进行转换.以影片信息威力,假设另一家公司也需要影片信息,并且也采用XML格式接受数据,但是他们所需要的XML格式与我们定义的完全不同,采用的办法就是XSLT,它也是用XML来描述的.这种关系如下:
类似的,要想将影片信息系那是在浏览器中,由于浏览器领域所接受的格式为HTML,因此,也可以使用XSLT将XML转换为HTML格式.关系和上图一样
XML选择器----XPATH
前面说过采用List<string>来保存XML文档时,如果想访问它的任意一样,可以使用索引,例如list[2].当采用XML DOM时,XML呈现为一棵节点树,由System.Xml.XmlDocument类型表示.那么如何访问XmlDocument中的任意节点?类似于CSS中的选择器,选取XML中的任意节点,可以使用XPATH.
不知道大家还记得CSS选择器吗?语句body{font-size:14px},选择了页面中的body元素,并设置css样式font-size为14px;语句dic.centent p{text-indent:2em;},选择了页面中的所有clas属性为content的dic下的p元素,并设置css样式text-indent为2em.
与CSS选择器类似,XPATH的规则也很多,但常用的就几个,如下表所示:
表达式 | 描述 |
/ | 以根节点为绝对路径选择子节点 /movieList/movie/starring(选择了所有父元素为movie,祖父元素为movieList的starring元素,并且movieList是根元素) |
// | 以相对路径选择所有的子节点 //movie/starring(选择所有父元素为movie的starring元素,不考虑它们在文档中的位置) |
nodename | 从当前节点下,选择名称为”nodename”的子节点 movie(选择了当前节点下名称为movie的子元素) |
. | 选择当前节点 |
.. | 选择当前节点的父节点 |
* | 选择所有节点 |
@ | 选择属性 //movie/@id(选择了所有movie元素的id属性) |
[] | 定义选择条件 //movie[id=”1”](选择了所有id为1的movie元素) |
[index] | 根据位置选择元素 //movie[1](选择了第一个movie元素) |
说实话,关于XML的相关概念楼主本来不想说的,本来想直接进入所操作XML的部分,但是楼主思前想后觉得有些东西还是按部就班的来吧,毕竟咱们和培训班的学生有差别,具体差别是啥我不说,你也明白.