什么是 XML Schema?
Schema,即XML Schema,XSD (XML Schema Definition)是W3C于2001年5月发布的推荐标准,指出如何形式描述XML文档的元素。XSD是许多XML Schema 语言中的一支。XSD是首先分离于XML本身的schema语言,故获取W3C的推荐地位。
XML Schema 是基于 XML 的 DTD 替代者。
XML Schema 的作用是定义 XML 文档的合法构建模块,类似 DTD。
XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD)。
注意:XSD只是Schema众多规范中的一种,还有XDR、DCD、SOX、DDML。
XML Scheman功能:
- 定义可出现在文档中的元素
- 定义可出现在文档中的属性
- 定义哪个元素是子元素
- 定义子元素的次序
- 定义子元素的数目
- 定义元素是否为空,或者是否可包含文本
- 定义元素和属性的数据类型
- 定义元素和属性的默认值以及固定值
如何使用
本章主要讲解的是如何定义schema文件,以及如何在xml文件中引入schema约束,定义schema文件,可以定义有命名空间的和没有命名空间,对应的引入方式也有所不同。
1.定义没有命名空间的xsd文件
下面这个例子是名为 “books.xsd” 的schema文件,没有指定命名空间。不指定命名空间,该schema所申明的所有元素会默认归于无命名空间(无命名空间,将在讲解elementFormDefault属性的时候会说,可以先看传送门)
<?xml version='1.0' encoding='UTF-8'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="books">
<xsd:complexType>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="book" >
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"></xsd:element>
<xsd:element name="price" type="xsd:decimal"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
代码解释:
xmlns:xsd=“http://www.w3.org/2001/XMLSchema”
显示 schema 中用到的元素和数据类型来自命名空间 “http://www.w3.org/2001/XMLSchema”。同时它还规定了来自命名空间 “http://www.w3.org/2001/XMLSchema” 的元素和数据类型应该使用前缀 xsd,当然这个前缀可以自定义,xsd就是代表XML Schema Definition,所以很多框架会使用这个前缀。
另外对于任何一个XML Schema架构文档(XSD)都有一个最顶层的schema 元素。而且该schema元素定义必须包含这个名称空间:http://www.w3.org/2001/XMLSchema。即此名称空间是由XML模式规范定义的标准名称空间-所有XML模式元素必须属于该名称空间。
这边还想给大家强调一点就是,xmlns这个属性是XML中的属性(XML Schemal本身就是基于XML编写),主要为了避免命名冲突的(了解xmlns,点击这里),不具有导入功能。如果在xsd中需要导入其他的xsd,需要使用标签<xsd:import namespace=“xxx” schemaLocation=“xxx.xsd”/>,后面会讲,而想在xml引用schema约束,也需要通过xsi:noNamespaceSchemaLocation或者 xsi:schemaLocation属性指出模式文档的位置,引入后可以通过xmlns指定前缀或者默认名称空间来使用。
要注意的是,XML Schema推荐标准并没有要求模式处理器必须要使用xsi:schemaLocation属性,某些模式处理器可以通过其他的方式来得到模式文档的位置,而忽略xsi:schemaLocation属性。如果引入的schema是w3c定义的,一般是不需指定schema文件位置。
2.引用没有名称空间的xsd文件
下面的xml文件会引入上面"books.xsd" 的schema约束,引入没有目标名称空间的模式文档需要用noNamespaceSchemaLocation属性指定文件位置,另外该模式文档的元素都是无命名空间的,所有使用不需要xmlns申明名称空间,直接使用:
<?xml version="1.0" encoding="UTF-8" ?>
<books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="books.xsd">
<book>
<name>java编程思想</name>
<price>11.22</price>
</book>
<book>
<name>head first设计模式</name>
<price>22.44</price>
</book>
</books>
代码解释:
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” 是任何XML实例文档固有的XML模式实例名称空间,它由XML模式规范定义。
xml文件要引入schemal校验,必须使用"http://www.w3.org/2001/XMLSchema-instance"名称空间的schemaLocation或者noNamespaceSchemaLocation属性指出模式文档的位置,前者用于声明了目标名称空间的模式文档,后者用于没有目标名称空间的模式文档
xsi:noNamespaceSchemaLocation=“books2.xsd”
用于引入没有目标名称空间的模式文档,属性的值是单一的值,只是用于指定模式文档的位置,模式处理器将从这个位置读取模式文档
3.定义有命名空间的xsd文件
还是同一个books.xsd文件,在之前基础上,新增targetNamespace=“www.book.com” 和elementFormDefault="qualified"属性:
<?xml version='1.0' encoding='UTF-8'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="www.book.com" elementFormDefault="qualified">
<xsd:element name="books">
<xsd:complexType>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="book" >
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"></xsd:element>
<xsd:element name="price" type="xsd:decimal"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
targetNamespace、elementFormDefault属性是为了申明该schema文件所定义的元素和数据类型所属于的命名空间。
代码解释:
targetNamespace=“www.book.com”
这个targetNamespace属性就是申明了该schema所对应的名称空间的URI。引用该Schema的其它文档(包括自身文档),需要xmlns申明该名称空间才能使用,其URI就是targetNamespace的属性值。(这个URI可以是任意的唯一字符串,只不过很多企业习惯将这个URI定义成可以访问的地址)
注意:如果xmlns申明的schema不是w3c定义的(比如我们自己定义的xsd文件),还必须指定schema文件位置
elementFormDefault=“qualified”
这一属性用来指示 XML Schema 处理程序把这个 XML schema 中定义的元素或者类型放到哪个命名空间。有人觉得很奇怪,已经申明了targetNamespace,那所有的元素不是应该都属于targetNamespace申明的空间吗?
其实这样的,一个schema中声明的元素或者类型是可能归到两个命名空间中的其中一个,这两个是,无名命名空间和由targetNamespace属性指明的目标命名空间。
- 如果没有申明targetNamespace,那么所有元素都属于无命名空间。
- 如果申明了targetNamespace
- 当elementFormDefault=“qualified” 时,全局元素或者类型将归于目标命名空间,局部元素将以缺省方式也归于目标命名空间。
- 而当elementFormDefault=“unqualified” 时,全局元素或者类型将归于目标命名空间,局部元素将归于无名命名空间。
【全局元素指 “schema” 元素的直接子元素!本地元素(Local elements)指嵌套在其他元素中的元素。】
无名称空间元素和有名称空间元素使用的区别:
- 无名称空间元素,是不需要xmlns申明名称空间的(也没有名称空间可以申明),直接使用。
- 有名称空间元素,是需要xmlns申明名称空间,然后通过前缀引用(当然也可以使用默认名称空间,不需要前缀,但是申明了默认名称空间,那么无名称空间的元素就没有方式能够引用了。)
如果已经知道怎么引用有名称空间的xsd文件,可以点击下面传送门,演示无名称空间和有名称空间元素使用的区别:演示传送门
4.引用有名称空间的xsd文件
引用有名称空间的xsd文件,需要使用schemaLocation属性:
<?xml version="1.0" encoding="UTF-8" ?>
<yth:books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="wwww.book.com books.xsd" xmlns:yth="www.book.com">
<yth:book>
<yth:name>java编程</yth:name>
<yth:price>11.22</yth:price>
</yth:book>
<yth:book>
<yth:name>HeadFirst设计模式</yth:name>
<yth:price>44.22</yth:price>
</yth:book>
</yth:books>
代码解释:
xsi:schemaLocation=“www.book.com books.xsd”
schemaLoation属性是"http://www.w3.org/2001/XMLSchema-instance"名称空间的一个属性,用于指出声明了目标名称空间的模式文档的位置
xsi:schemaLocation属性的值由一个URI引用对组成,两个URI之间以空白符分隔。第一个URI是名称空间的名字,第二个URI给出模式文档的位置,模式处理器将从这个位置读取模式文档,该模式文档的目标名称空间必须与第一个URI相匹配。
xsi:schemaLocation属性的值也可以由多个URI引用对组成,每个URI引用对之间使用空白符分隔。
xmlns:yth=“www.book.com”
schemaLocation引入xsd文件后,还需要使用xmlns申明名称空间,其值就是引入的模式文档的目标名称空间,然后通过前缀使用元素。使用xmlns=“www.book.com”,默认名称空间方式也可以,不需要前缀就可以使用元素。
其实使用noNamespaceSchemaLocation属性也可以引入有名称空间的xsd文件,下面这个例子是有效的:
<?xml version="1.0" encoding="UTF-8" ?>
<yth:books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="books.xsd" xmlns:yth="www.book.com">
<yth:book>
<yth:name>java编程</yth:name>
<yth:price>11.22</yth:price>
</yth:book>
<yth:book>
<yth:name>HeadFirst设计模式</yth:name>
<yth:price>44.22</yth:price>
</yth:book>
</yth:books>
5.演示无名称空间元素和有名称空间元素使用区别
如果将elementFormDefault="qualified"值改为unqualified,或者属性移除(默认就是unqualified):
<?xml version='1.0' encoding='UTF-8'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="www.book.com" elementFormDefault="unqualified">
<xsd:element name="books">
<xsd:complexType>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="book" >
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"></xsd:element>
<xsd:element name="price" type="xsd:decimal"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
对应的引入该schema的文档,该文档是正确的:
<?xml version="1.0" encoding="UTF-8" ?>
<yth:books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="books.xsd" xmlns:yth="www.book.com">
<book>
<name>java编程</name>
<price>11.22</price>
</book>
<book>
<name>HeadFirst设计模式</name>
<price>44.22</price>
</book>
</yth:books>
可以看到,全局元素books是属于www.book.com这个名称空间,所以使用yth前缀引用,而book、name、price这些非全局元素,是属于无名称空间的,不需要前缀就能使用。
另外演示一个例子,如果把www.book.com申明了默认名称空间。
可以看到books下的子标签book报错了,因为申明了www.book.com是默认空间,所以默认使用的所有元素都属于www.book.com这个空间,books是属于的,而book、name、price这些元素是属于无名称空间的,申明了默认名称空间就没有方式能够引用了,这里的book其实是希望从www.book.com名称空间找的,但是是没有的,所以报错。
6.XML Schema导入
通常一个很小的xml文档不需要复杂的命名空间来限定作用域。但是当文档复杂性越来越大,对应的命名空间规则也会很复杂,如果要通过XML Schema来创建和修改XML的内容限定的话,很多人会习惯性的在一个文件中储存所有的Schema。但是实际上一个良好的符合标准的规范应当是将文档分成很多个子Schema,这个过程可以叫做XML Schema Binding。命名空间就是一个分割Schema的机制,子schema被包含在一个父schema中,这样就提高了复用性,使得一个schema包可以用在很多的工程中。而且这样能够提高定义的可读性,也使文档易于管理。
语法:
<xsd:import namespace=“xxx” schemaLocation=“xxx.xsd”/>
使用该语法可以在schemal中导入其他schema。导入以后,通过xmlns申明后使用。
举例:
定义author.xsd文件,代表书的作者:
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="author" elementFormDefault="qualified">
<xsd:element name="author">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="xsd:integer"/>
<xsd:element name="gender" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
再看原来的books.xsd如何引用上面的,三步:
<?xml version='1.0' encoding='UTF-8'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="www.book.com" xmlns:a="author"
elementFormDefault="qualified">
<!-- 1.导入author名称空间,指定该空间模式文档的位置 -->
<!-- 2.在schema根标签中申明名称空间ahthor指定别名a -->
<xsd:import
namespace="author"
schemaLocation="author.xsd"/>
<xsd:element name="books">
<xsd:complexType>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="book">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"></xsd:element>
<xsd:element name="price" type="xsd:decimal"></xsd:element>
<xsd:element ref="a:author"/>
<!-- 3. 使用author空间的author元素 -->
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
对应xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<yth:books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="www.book.com books.xsd"
xmlns:yth="www.book.com" xmlns:a="author">
<yth:book>
<yth:name></yth:name>
<yth:price>22.2</yth:price>
<a:author>
<a:name></a:name>
<a:age>11</a:age>
<a:gender></a:gender>
</a:author>
</yth:book>
</yth:books>