强大的XML
2018-04-23 20:29:26
XML:Extensible Markup Language,也就是可扩展标记语言。XML和HTML格式是古老的标记通用语言SGML的衍生语言。
XML文件是可以用来作为配置文件的,相比于其他配置文件的规范,XML的好处在于通过自定义的标记,程序可以利用标记寻找相应的配置信息,这样就可以随意调整配置信息的位置,标记也能帮助用户理解配置信息的含义。
我们常常会遇到不同的商业伙伴之间会有密切的商务往来,彼此之间的信息系统需要对接,但是有可能双方使用的是不同的数据库产品,虽然这些数据库都支持SQL92标准,但是经过演变,各种各样的数据库或多或少的发展了自己的方言,这样在不同的数据库之金啊交换数据,变成了令人头疼的问题。比如,中国移动使用的是Oracle的工具,而银行使用的是DB2,那么这两者的数据交互就会称为令人头疼的问题。另外,在企业间合并的时候,多种不同的数据库之间的合并也会成为麻烦。现在有了XML,一切都变得很容易,因为XML被广泛的支持,所以XML成为了不同数据库之间数据迁移的工具。
除了在数据库领域XML利用自身标准帮助迁移数据,在非数据库领域,XML也能用来协调不同计算机语言,不同服务器平台等这些场合的数据融合。
尽管XML和HTML同宗同源,但是两者之间存在着重要的区别:
- 与HTML不同,XML是大小写敏感的,例如<H1>和<h1>是不同的XML标签。
- 在HTML中,如果从上下文可以分清哪里是段落或者列表项的结尾,那么结尾标签如</p>可以省略,而XML中结束标签绝对不能省略。
- 在XML中,只有单个标签而没有相对应的结束标签的元素必须以/结尾。这样解析器就不需要查找形如</p>的标签了。
- 在XML中,属性值必须用引号括起来。在HTML中,引号是可有可无的。例如,<applet code = "CodeDemo.class" width = 300>,这在HTML中是合法的,但是在XML中则是不被允许的,需要加上引号进行约束。所以在XML中应该写成<applet code = "CodeDemo.class" width = “300”>
- 在HTML中,属性名可以没有值。例如,<input type = "radio" cheacked>。在XML中所有的属性都必须要有属性值。比如,<input type = "radio" cheacked=“true”>
一、XML文档的结构
1、XML应该以一个文档头开始,例如:<?xml version="1.0" encoding="UTF-8"?>。encoding不是必须的,?与xml之间不能有空格,XML语法规定是相当严格的。
2、文档头之后通常是文档的文档类型定义(Document Type Definition,DTD)。
3、XML的标记以<>为开头,以</>为结尾,完整的这样一个结构被称为元素,和html不同的是,html里的元素都是事先规定好的,而XML的标记是作者自己规定的。
XML文档的正文包含根元素,根元素包含一些其他的元素。元素可以有子元素(child element),文本或者两者皆有。在下述的例子中,font元素有两个子元素,它们是name和size。
<?xml version="1.0"?> --文档头 <!DOCTYPE configuration ...> --文档的类型定义DTD <configuration> <title> <font> <name>Java</name> <size>36</size> </font> </title> ... </configuration>
4、XML其他的一些指令
- 字符引用
字符引用的形式是&#十进制值,或者&#x十六进制值。例如,字符a,a,或者a。
- 实体引用
实体引用的形式是&name,例如<;>;&;";&apos,都有预订的含义:小于,大于,&,引号,省略号。
- CDATA部分
CDATA部分用<![CDATA[...]]>来限定其界限。它们是字符数据的一种特殊形式。你可以用来囊括那些含有<,>,&之类的字符的字符串,而不用将它们解释为标记,例如:
<![CDATA[<&>是很常用的]]>。但是这里的字符串是不能包含]]>的,这也可以理解。
- 处理指令
处理指令是那么专门用来处理XML文档的应用程序中使用的指令,它们将用<? 和 ?>来限定其界限。例如:
<?xml version="1.0"?>
- 注释
注释是用<!-- -->限定的文本,例如:
<!-- This is a comment -->
另外,注释中是不能包含--的。注释只能用来给读者提供信息,其中绝对不能包含隐藏的命令,命令应该是用处理指令来实现的。
二、文档类型定义 DTD
前面提到XML的标记不是语言事先规定的,作者可以自己来定义标记,但是这样也出现了问题,就是别人如何理解自定义的标记,更主要的是在别人修改的时候,如何遵守原始作者的定义。
从另一个角度来看,我们将XML看作一种轻量级的数据库使用,数据库操作事实上存在两个阶段,数据定义阶段和数据操作阶段,在数据操作前,通常要定义表的结构,以便数据可以按照设定有条不紊的存放。
那么,DTD就是数据类型定义(Document Type Definition)文件,DTD文件用于说明特定XML文件的规则。DTD并不是强类型定义语言,在DTD中只有两个数据类型#PCDATA和EMPTY,有数据和没有数据,对于XML的主要应用方向之一的配置文件,这样设计DTD无可厚非,因为配置文件对数据类型并没有太多的要求。
然而,在某些情况下,当我们需要更精确的数据类型定义的时候,DTD就显得束手无策了,比如我们定义的元素性别,我们希望其数据类型为男/女,这个时候DTD就无法实现,只能简单的设置成#PCDATA。
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT 学校 (学生+)> <!ELEMENT 学生 (姓名,性别)> <!ELEMENT 姓名 (#PCDATA)> <!ELEMENT 性别 (#PCDATA)>
在XML文件中使用<!DOCTYPE>来将XML文件和DTD文件进行绑定,只能是大写字母,后面是根元素标记名字。SYSTEM表示DTD在文件系统中,如果是PUBLIC则表示将使用互联网上的DTD,此时除了地址还需要额外指定DTD的名字。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE 学校 SYSTEM "C:\school.dtd"> <学校> <学生> <姓名>张三</姓名> <性别>男</性别> </学校>
三、Schema
Schema是DTD的替代品,它的作用也是来约束XML文件的,XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD)。
那么既然有了DTD为什么还需要Schema呢,我们认为 XML Schema 很快会在大部分网络应用程序中取代 DTD。理由如下:
- XML Schema 可针对未来的需求进行扩展
- XML Schema 更完善,功能更强大
- XML Schema 基于 XML 编写
- XML Schema 支持数据类型
- XML Schema 支持命名空间
Schema本身也是基于XML编写的,可使用 XML 编辑器来编辑 Schema 文件,使用 XML 解析器来解析 Schema 文件,并且通过 XML DOM 来处理 Schema。
一个简单的 XML 文档:
请看这个名为 "note.xml" 的 XML 文档:
<?xml version="1.0"?> <note> <to>George</to> <from>John</from> <heading>Reminder</heading> <body>Don't forget the meeting!</body> </note>
XML Schema
下面这个例子是一个名为 "note.xsd" 的 XML Schema 文件,它定义了上面那个 XML 文档( "note.xml" )的元素:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3schools.com" xmlns="http://www.w3schools.com" elementFormDefault="qualified"> <xs:element name="note"> <xs:complexType> <xs:sequence> <xs:element name="to" type="xs:string"/> <xs:element name="from" type="xs:string"/> <xs:element name="heading" type="xs:string"/> <xs:element name="body" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
首先,需要注意的是Schema也是个XML文件,所以它也有自己的命名空间。
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3school.com.cn" xmlns="http://www.w3school.com.cn" elementFormDefault="qualified"> ... ... </xs:schema>
其中,下面这句表示给这个XML中Schema定义了一个命名空间http://www.w3.org/2001/XMLSchema
,xs为使用时的前缀。
xmlns:xs="http://www.w3.org/2001/XMLSchema"
显示被此 Schema 定义的元素 (note, to, from, heading, body) 来自命名空间: "http://www.w3school.com.cn"
,即这个schema是为”http://www.w3school.com.cn“命名空间所提供约束的,也就是被声明为http://www.w3school.com.cn命名空间的xml文件所引用。
targetNamespace="http://www.w3school.com.cn"
下面是用来指出 Schema 中元素的默认的命名空间是 "http://www.w3school.com.cn"
。
xmlns="http://www.w3school.com.cn"
四、命名空间
有时在一个团队中,不同任务的人都需要使用XML,各自设计约束难免会有元素重复的问题,使用命名空间就是用来解决这个问题的。
XML 命名空间属性被放置于元素的开始标签之中,并使用以下的语法,用于标示命名空间的地址不会被解析器用于查找信息。其惟一的作用是赋予命名空间一个惟一的名称。一个元素可以有多个命名空间,里面带前缀的是特地的命名空间,不带前缀的是默认命名空间。
xmlns:namespace-prefix="namespaceURI"
当命名空间被定义在元素的开始标签中时,所有带有相同前缀的子元素都会与同一个命名空间相关联。
很多公司使用URL作为命名空间名称,这是因为这里的URL肯定是唯一的,其实这个道理和Java包名的命名为反向域名是同一个道理。
XML 中对 Schema 的引用
此文件包含对 XML Schema 的引用:
<?xml version="1.0"?> <note xmlns="http://www.w3school.com.cn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3school.com.cn note.xsd"> <to>George</to> <from>John</from> <heading>Reminder</heading> <body>Don't forget the meeting!</body> </note>
在根元素中指定了默认命名空间为http://www.w3school.com.cn
。
xmlns="http://www.w3school.com.cn"
又定义了一个命名空间xsi(官方叫XML Schema 实例命名空间)。定义这个命名空间的原因是,schemaLocation 属性在这个命名空间下,也就是说,只有先定义了这个命名空间,才能使用schemaLocation 属性。上文已经提到了,命名空间的URI是只是作为区分字符串使用的,并不包含真正的XSD文件,真正的XSD文件的位置需要通过xsi下的schemaLocation属性进行定义。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
设置xsi前缀代表的命名空间中的一个属性schemaLocation为"http://www.w3school.com.cn note.xsd"。
XML Schema 实例命名空间下的schemaLocation属性,实际语法其实是, xsi:schemaLocation = "key" "value"。
也就是说
xsi 命名空间下 schemaLocation 元素的值为一个由空格分开的键值对。前一个“键” http://www.w3school.com.cn
指代 namespace, 只是一个全局唯一字符串而已。后一个值指代 【XSD location URI】 , 这个值指示了前一个命名空间所对应的 XSD 文件的位置, xml parser 可以利用这个信息获取到 XSD 文件, 从而通过 XSD 文件对所有属于命名空间 http://www.w3school.com.cn
的元素结构进行校验, 因此这个值必然是可以访问的, 且访问到的内容是一个 XSD 文件的内容。
xsi:schemaLocation="http://www.w3school.com.cn note.xsd"
五、XML文件设计
- 在设计XML的时候,应该尽量使元素要么包含子元素,要么包含文本。换句话说,你应该避免以下的情况:
<font> Java <size>36</size> </font>
在XML规范里,这叫做混合式内容(mixed content)。如果包含混合式的内容那么在树形遍历子节点的时候就会出现需要进行判别的情况。所以要避免混合式内容,这样可以简化解析的过程。
- 何时使用元素,何时使用属性
这个问题在XML设计人员中存在着分歧。例如将font做如下的描述:
<font name="Java" size="36"/>
似乎要比下面的更简单一些:
<font> <name>Java</name> <size>36</size> </font>
但是属性的灵活性要差很多,假设你想把单位添加到size中去。如果使用属性,那么必须把单位添加到属性值中去:
<font name="Java" size="36 pt">
o no!这时候就需要对字符串“36 pt”进行解析,而这正是XML设计用来避免的麻烦。但是,如果把属性加到size元素中就会非常的方便:
<font> <name>Java</name> <size unit="pt">36</size> </font>
一个常用的经验法则是,属性值应该用来修改值的解释,而不是用来指定值。在HTML中属性的使用规范很简单:凡是不显示在网页上的都是属性。
六、XML解析
用程序读写XML,要说这不该是问题,因为大多数编程语言都有IO流的支持,但是深入的看就会发现,写XML用IO流相对容易,可以读取却并不那么容易,因为我们的需求往往不仅仅要有读取文件内容的能力,在大多数情况下,我们需要获取某一个特定元素的值,如果单纯依赖IO流,每次都需要写比较复杂的分析程序,而这些代码完全可以复用。
因此W3C提出了一个统一的标准DOM,文档对象模型(Document Object Model,简称DOM)。DOM的思想是将XML文件读到内存中,使其形成一个对象,这个对象内在映射着XML文件的树形结构,我们可以通过调用对象的成员方法来访问这些内容。
W3C做这件事还有一个巨大的好处,DOM不是建立在某个编程语言的基础上的,作为一个国际标准,几乎所有的编程语言都实现了这个标准,这样不同的语言利用DOM访问XML的做法就基本一致了。
XML技术的有趣之处在于总是有两个相同功能的不同技术,比如DTD和Schema、CSS和XSL,现在是DOM和SAX,DOM和SAX的功能一样,都是用来解析XML文件的,不同之处在于DOM一次性将整个XML文件读入到内存中,并且包装成对象,而SAX每次只读取一行,处理完后将这一行抛弃然后处理下一行,这样做的好处是不占用太多的内存,如果XML作为数据库应用,那么有可能内容过多,文件很大,使用DOM或许会超出内存的大小,这时就只能使用SAX,但是这样也说明SAX应用不如DOM频繁,因为读取很大的XML文件的机会并不多,SAX的另外一个缺点就是,因为数据会被丢弃,所以和DOM相比无法再次使用数据。