通过上一章的学习,可以知道开发Schema文档的过程实际是声明XML元素的过程,而XML文档的元素又分为简单元素和复杂元素两类,简单元素的声明是复杂元素的声明的基础。本章主要讲述如何声明简单元素。
声明简单元素需要用到XML Schema的简单类型。简单类型又可以分为两类,即基本数据类型和自定义简单类型。自定义简单类型的都是直接或间接由基本数据类型衍生出来的,因此,理解基本数据类型是学好自定义简单类型的基础。
4.1 基本数据类型的使用
基本数据类型指的是Schema内置的44种数据类型,在上一章已经对其进行了简要讨论。本节就其中主要的几种从反面进行详细讨论。
4.1.1 字符型的使用
字符型是最松散的文本约束。其唯一要求是不能含有特殊字符(如&、<)。下面是一个典型的Schema文档,如清单4-1所示。
清单4-1 利用字符型声明简单元素
<?xml version="1.0" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="name" type="xs:string" />
</xs:schema>
下面是一个违反了字符型定义的XML文档,如清单4-2所示。
清单4-2 含有非法字符的XML实例
<?xml version="1.0" ?>
<name>张三&</name>
将XML文档与Schema关联后对其进行验证,可以得到如下错误提示。
3-2.xml:2,139: FATAL ERROR: Expected entity name for reference
3-2.xml第二行第139列:致命错误:缺少实体引用名。
★ 说明 ★
为了方便观察XML元素与Schema定义的关系,在此特地省略了关联代码。
使用“&”来代替“&”符号,验证通过。代码如下所示。
<?xml version="1.0" ?>
<name>张三&</name>
4.1.2 日期型的使用
日期型的格式为YYYY-MM-DD。下面是一个典型的Schema文档,如清单4-3所示。
清单4-3 日期型的使用
<?xml version="1.0" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ship_date" type="xs:date" />
</xs:schema>
下面是一个违反日期型定义的XML文档,如清单4-4所示。
清单4-4 违反日期型约束的XML实例
<?xml version="1.0" ?>
<ship_date>1998-13-15</ship_date>
在Stylus Studio中验证,可以得到如下错误提示。
Datatype error: Type:SchemaDateTimeException, Message:The month must have values 1 to 12! '1998-13-15' .
数据类型错误:类型SchemaDateTime异常,消息:“1998-13-15”中的月份值必须在1~12之间。修改月份值为可用值,该问题即可解决。
4.1.3 数值型的使用
数值型约束要求文本内容必须能转换为数字,其中不能含有字母或其他非数字字符。以xs:integer为例,下面是一个典型的Schema文档,如清单4-5所示。
清单4-5 数值型的使用
<?xml version="1.0" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="quantity" type="xs:integer" />
</xs:schema>
下面是一个违反了数值型约束的XML文档,如清单4-6所示。
清单4-6 违反数值型约束的XML实例
<?xml version="1.0" ?>
<quantity>ab1323</quantity>
在Stylus Studio中验证,可以得到如下错误提示。
Datatype error: Type:InvalidDatatypeValueException, Message:Value 'ab1323' does not match regular expression facet '[+\-]?[0-9]+'.
数据类型错误:不可用数据类型异常,消息:值“ab1323”不匹配正则表达式“[+\-]? [0-9]+”。将字符“ab”去掉,则“123”可以正确地转换为整型。
4.1.4 布尔型的使用
布尔型要求文本内容只能取true、false、1、0中的一个。下面是一个典型的Schema文档,如清单4-7所示。
清单4-7 布尔型的使用
<?xml version="1.0" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="closed" type="xs:boolean" />
</xs:schema>
下面是一个违反了布尔型定义的XML文档实例,如清单4-8所示。
清单4-8 违反布尔型约束的XML实例
<?xml version="1.0" ?>
<closed>TRUE</closed>
经Stylus Studio验证,出现如下错误提示。
Datatype error: Type:InvalidDatatypeValueException, Message:The unary operation node had a binary node type.
数据类型错误:不可用的数据类型异常,消息:一元运算节点有二元节点的类型。
在Schema定义中指定了元素<closed>的数据类型为布尔型,错误消息中的一元节点即指布尔型元素<closed>;XML元素的实际值“TRUE”不是布尔型,而被处理器当做了一个普通字符串,这里的二元节点类型即指字符串“TRUE”。
4.2 自定义简单类型的使用
上一节讲述了内置数据类型的使用。虽然Schema的内置数据类型有44种之多,但仍无法满足定义简单元素的需求。例如,奥运奖牌只能有金、银、铜三种,单纯使用xs:string来定义是无法满足要求的;小学生功课成绩只能从0~100,用xs:integer来约束,范围又太广。当然,还有许许多多其他情况需要解决。
为此,Schema提供了另外一种机制——自定义简单类型,以解决上述类似问题。自定义简单类型是通过对一个已有简单类型进行约束派生出来的。Schema提供了15种元素用于自定义简单类型。本节将介绍其中最常用的几种。
4.2.1 枚举型——enumeration
为了解决奥运奖牌的约束问题,可以使用enumeration(自定义枚举型)。enumeration可以创建一组基于简单类型的选项。所谓基于简单类型,是指这些选项在本质上都是某种简单类型。创建一组枚举选项,只是为了在基类型的基础上有更强的约束。该简单类型需要用到的关键字是enumeration。enumeration的使用语法如下所示。
<xs:enumeration value="value"/>
清单4-9演示了一个使用enumeration的Schema文档。
清单4-9 enumeration的使用
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="medal">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="gold"/>
<xs:enumeration value="sliver"/>
<xs:enumeration value="copper"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
代码说明:
声明元素的一般形式为<xs:element name="elementName" type="elementType"/>。在上例中,使用xs:simpleType——自定义简单类型,来代替原来的xs:string等内置数据类型。
自定义简单类型的定义一般写作如下形式。
<xs:simpleType>
<!--The defination of simpleType -->
</xs:simpleType>
<xs:restriction base="xs:string">说明新类型是一个基于xs:string类型的约束。
<xs:enumeration value="gold"/>向选项组中添加选项gold。
该段代码创建了一个新的类型,该类型是一个枚举型。该枚举型包含了三个选项 (gold、sliver和copper)。
清单4-10所示的XML文档可以通过验证。
清单4-10 奖牌实例XML文档
<?xml version="1.0"?>
<medal>gold</medal>
★ 说明 ★
使用枚举型进行验证,是将元素<medal>的文本内容作为一个整体,并在枚举型的选项组中搜索。如果找到,则可通过有效性验证。
1.选项重复无效性
在枚举选项组中,定义重复选项没有任何意义,重复的选项只会被添加一次。清单4-11所示的Schema文档定义了重复选项sliver。
清单4-11 含有重复值的枚举型
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="medal">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="gold"/>
<xs:enumeration value="sliver"/>
<xs:enumeration value="copper"/>
<xs:enumeration value="sliver"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
2.选项无序性
枚举选项组中各选项的定义顺序没有要求。清单4-12所示的Schema文档和清单4-9所示的Schema文档具有相同的效果。
清单4-12 顺序颠倒的枚举列表
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="medal">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="sliver"/>
<xs:enumeration value="copper"/>
<xs:enumeration value="gold"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
枚举型的基类型可以是除布尔型外的几乎所有内置数据类型。这是因为布尔型(xs:boolean)本是就是一种enumeration(枚举型)。
3.匿名类型与命名类型
在清单4-9中,因为<xs:simpleType>直接位于<xs:element>元素声明之内,所以<xs:simpleType>无需name属性。此处的自定义简单类型称为匿名类型。
其实<xs:simpleType>可以独立于<xs:element>存在。这时需要设定其name属性,以标识该自定义简单类型,这就是命名类型。在进行元素声明时,通过type属性来引用该命名类型。清单4-13演示了这种处理方法。
清单4-13 独立的<xs:simpleType>
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="medal" type="medalType"/>
<xs:simpleType name="medalType">
<xs:restriction base="xs:string">
<xs:enumeration value="gold"/>
<xs:enumeration value="sliver"/>
<xs:enumeration value="copper"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
4.2.2 限制长度——minLength、maxLength
如果需要制作一张员工表,而员工名字要限制在2~4个字符。此时定义一个基于xs:string的限制长度的简单类型,是一个良好的解决方案。定义简单类型需要用到的两个关键字为minLength和maxLength。minLength的使用语法如下所示。
<xs:minLength value="xxx"/>
maxLength的使用语法为如下所示。
<xs:maxLength value="yyy"/>
value属性指定了最小长度和最大长度的值。清单4-14演示了一个使用minLength和maxLength的Schema实例。
清单4-14 基于string的限制长度的简单类型
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="personName">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="2"/>
<xs:maxLength value="4"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
代码说明:
<xs:minLength>用于指定字符串最小长度;<xs:maxLength>用于指定字符串最大长度。
在字符串中,无论是中文字符还是英文字符,都被当做一个字符来看待。
如清单4-15和清单4-16所示的XML文档都可以通过验证。
清单4-15 中文字符XML文档
<?xml version="1.0"?>
<personName>张军</personName >
清单4-16 英文字符XML文档
<?xml version="1.0"?>
<personName>SUN</personName >
4.2.3 取值范围——minInclusive、maxInclusive
为了限定学生成绩的分数从0~100,可以使用限定取值范围的自定义简单类型。该简单类型需要用到的关键字为minInclusive和maxInclusive。注意,此时的取值范围包括边界值。
minInclusive的使用语法如下所示。
<xs:minInclusive value="xxx"/>
maxInclusive的使用语法如下所示。
<xs:maxInclusive value="yyy"/>
value属性指定了最小值和最大值。清单4-17演示了使用minInclusive和maxInclusive限制取值范围的Schema文档。
清单4-17 限制取值范围的自定义简单类型
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="mark">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
代码说明:
<xs:minInclusive>用于指定临界最小值;<xs:maxInclusive>用于指定临界最大值。
为了保证取值范围非空,maxInclusive的值必须大于等于minInclusive的值。
如清单4-18所示的XML文档可以通过验证。
清单4-18 限定学生分数的XML文档
<?xml version="1.0"?>
<mark>64</mark>
另有两个关键字minExclusive和maxExclusive,表示元素的值必须大于最小值且小于最大值。minExclusive的使用语法如下所示。
<xs:minExclusive value="xxx"/>
maxExclusive的使用语法如下所示。
<xs:maxExclusive value="yyy"/>
一个典型的Schema实例如清单4-19所示。
清单4-19 minExclusive和maxExclusive的使用
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="mark">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minExclusive value="0"/>
<xs:maxExclusive value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
代码说明:
<xs:minExclusive>用于指定最小临界值;<xs:maxExclusive>用于指定最大临界值。
为了保证取值范围非空,maxExclusive的值必须大于minExclusive的值。
★ 注意与说明 ★
要注意Inclusive和Exclusive的区别。Inclusive包含临界值,而Exclusive不包含临界值。
4.2.4 小数位数限定——totoalDigits和fractionDigits
银行结账或缴税清单往往对数字位数有明确要求。限定小数位数的自定义简单类型需要用到的关键字为totalDigits和fractionDigits。totalDigits用来定义数字的数字总位数;fractionDigits用来定义数字的小数部分位数。totalDigits的使用语法如下所示。
<xs:totalDigits value="xxx"/>
fractionDigits的使用语法如下所示。
<xs:fractionDigits value="yyy"/>
value属性指定了数字总位数和小数部分的位数。清单4-20演示了限定小数位数的Schema实例。
清单4-20 小数位数限定
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="salary">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="8"/>
<xs:fractionDigits value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
代码说明:
<xs:totalDigits>用于限定数字总位数,这其中不包括小数点。
位数仅指有效位数,即会去除前导“0”和后继“0”。如00 122.134 000会先被转换为122.134,再进行验证。
清单4-21和清单4-22演示了可以通过验证的XML文档实例。
清单4-21 符合清单4-20小数位数限定的XML文档实例
<?xml version="1.0"?>
<salary>1345.98</salary>
清单4-22 符合清单4-20小数位数限定的XML文档实例
<?xml version="1.0"?>
<salary>0003305.1320000</salary>
4.2.5 模式匹配——pattern
电话号码是日常生活中最常用到的数据类型之一,为了约束这种格式的数据,可以使用模式匹配的自定义简单类型。该简单类型需要用到的关键字为pattern。pattern的使用语法如下所示。
<xs:pattern value="regularExpression"/>
value属性指定了模式的正则表达式。清单4-23演示了使用模式匹配来约束电话号码的Schema实例。
清单4-23 pattern约束电话号码格式
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="telephone">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="\d{3,4}-\d{7,8}"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
代码说明:“\d{3,4}-\d{7,8}”是正则表达式,表示3位到4位数字,后面跟一个“-”,再后面是7位或8位的数字。
清单4-24和清单4-25演示了含有正确的电话号码格式的XML文档。
清单4-24 含有正确电话号码的XML文档
<?xml version="1.0"?>
<telephone>0756-2299178</telephone>
清单4-25 含有正确电话号码的XML文档
<?xml version="1.0"?>
<telephone>010-42379866</telephone>
4.2.6 原子类型——atomic
以上介绍的简单类型——包括内置简单类型和自定义简单类型,其实都包含了一个隐含的特点,即不可分割性。例如,对于xs:string类型的一个字符串“sony”,单独拿出其中的“s”或“o”或其他任意字符,都没有什么明确的意义;对于xs:enumeration类型的一个实例“gold”,单独拿出其中的任何字符也没有什么意义。即整个元素的内容具有不可分割性,这样的元素定义类型称为原子类型。在Schema的简单类型中,除了原子类型,还有列表类型和联合类型两种类型。
4.2.7 列表类型——list
列表类型同样是简单类型的一种。不过,它所定义的元素或属性的值可以含有多个原子值,这些并列的原子值之间利用空格分隔。该类型需要用到关键字list。list使用的语法如下所示。
<xs:list itemType="simpleType"/>
itemType属性用于指定列表类型中元素的数据类型。清单4-26演示了使用列表类型的Schema文档实例。
清单4-26 列表类型的使用
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="fruitList">
<xs:simpleType>
<xs:list itemType="fruitType"/>
</xs:simpleType>
</xs:element>
<xs:simpleType name="fruitType">
<xs:restriction base="xs:string">
<xs:enumeration value="apple"/>
<xs:enumeration value="pear"/>
<xs:enumeration value="peach"/>
<xs:enumeration value="cherry"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
代码说明:<xs:list itemType="fruitType"/>定义了一个列表类型。ItemType="fruitType"为列表项(原子值)指定数据类型,fruitType类型必须是已经定义了的简单类型。
清单4-27和清单4-28演示了可以通过验证的XML文档。
清单4-27 仅含一个列表项的XM文档实例
<?xml version="1.0"?>
<fruitList>apple</fruitList>
清单4-28 含有两个列表项的XML文档实例
<?xml version="1.0"?>
<fruitList>apple cherry</fruitList>
清单4-29和清单4-30演示了无法通过验证的XML文档。
清单4-29 含有一个列表项的但无法通过验证XML文档实例
<?xml version="1.0"?>
<fruitList>banana</fruitList>
清单4-30 没有空格分隔的被当做一个列表项
<?xml version="1.0"?>
<fruitList>applecherry</fruitList>
★ 注意 ★
注意区分enumeration和list。enumeration虽然也限定了一个枚举选项列表,但是其定义的元素或属性内容只能含有其中一个原子值;而list所定义的元素或属性的内容可以含有多个原子值。当然二者都属于简单类型的范畴。
4.2.8 联合类型
联合类型和列表类型非常类似。联合类型所定义的元素或属性的值同样可以含有多个原子值。同时,联合类型可以一次定义多种简单类型。联合类型的使用语法如下所示。
<xs:union memberTypes="simpleType1 simpleType2.. "/>
memberTypes属性为联合类型指定成员类型。清单4-31演示了使用联合类型的Schema实例。
清单4-31 联合类型的使用
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="union">
<xs:simpleType>
<xs:union memberTypes="enumerationType listType"/>
</xs:simpleType>
</xs:element>
<xs:simpleType name="enumerationType">
<xs:restriction base="xs:string">
<xs:enumeration value="girl"/>
<xs:enumeration value="boy"/>
<xs:enumeration value="man"/>
<xs:enumeration value="woman"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="listType">
<xs:list itemType="fruitType"/>
</xs:simpleType>
<xs:simpleType name="fruitType">
<xs:restriction base="xs:string">
<xs:enumeration value="apple"/>
<xs:enumeration value="pear"/>
<xs:enumeration value="peach"/>
<xs:enumeration value="cherry"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
<xs:simpleType name="enumerationType">定义了一个枚举型(原子类型)。其值要求是girl、boy、man或woman中的一个。
<xs:simpleType name="fruitType">定义了一个枚举型(原子类型)。其值要求是apple、pear、peach或cherry中的一个。
<xs:simpleType name="listType">定义了一个列表类型。<xs:list itemType="fruitType">表明该列表类型所约束的值,可以含有多个fruitType类型的原子值。
<xs:union memberTypes="enumerationType listType">表明联合类型允许的值是enumer ation Type或listType中的一种。
一个联合类型的XML实例元素(属性)的值不可以出现两种或两种以上的memberType。
清单4-32和4-33演示了可以通过验证的XML实例。
清单4-32 仅含enumerationType的XML文档实例
<?xml version="1.0"?>
<union>man</union>
清单4-33 仅含listType的XML文档实例
<?xml version="1.0"?>
<union>apple peach</union>
清单4-34~4-36演示了无法通过验证的XML实例。
清单4-34 含有非法enumeration的XML文档实例
<?xml version="1.0"?>
<union>girl woman</union>
清单4-35 含有enmuerationType和listType的XML文档实例
<?xml version="1.0"?>
<union>girl apple</union>
清单4-36 含有enmuerationType和listType的XML文档实例
<?xml version="1.0"?>
<union>boy peach cherry</union>
★ 说明 ★
清单4-34的错误原因和清单4-35、清单4-36的错误原因不同。清单4-34是因为元素内容不符合任何一种memberType;而清单4-35、清单4-36是因为元素内容混合了两种memberType。<xs:list itemType="simpleType"/>中的itemType是单数;而<xs:union memberTypes="simpleType1.."/>中的memberTypes为复数。从这一点可以很明确地看出list和union的区别。
4.2.9 分析type属性值的特殊性
清单4-37演示了一个普通的XML文档。该文档的内容是关于一种食肉动物的名称。
清单4-37 关于一种食肉动物的XML文档
<?xml version="1.0"?>
<flesh-eater>tiger</flesh-eater>
如果只约束其元素<flesh-eater>为字符型,而没有其他特殊要求,那么相应的Schema定义可以写成清单4-38所示的样子。
清单4-38 约束食肉动物的数据类型
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="flesh-eater" type="xs:string"/>
</xs:schema>
单纯从XML文档的角度观察上面的Schema文档,可以得到以下结论。
该文档声明了一个名称空间http://www.w3.org/2001/XMLSchema,而且仅此一个名称空间。
属于xs所代表的名称空间的元素有<xs:schema>、<xs:element>和<xs:string>。
name和type属性依附于元素<xs:element>。
name属性的值“flesh-eater”,没有名称空间,因为它只是作为一个字符串出现的,表现的是某个XML元素的名称。名称只用字符串来表示已经足够。
属性type的值“xs:string”则不然。可以看到同样是属性值,“xs:string”有明确的名称空间。这表明属性type的值不是简单的字符串,而是一个引用(元素或属性)。
分析name和type的属性值可以知道,虽然表面看起来,这两个属性的值都是字符串,却有着极大的不同。
4.2.10 type属性与名称空间
xs:string是内置简单类型,如果使用自定义简单类型,又该如何看待呢?假设限定了该食肉动物只能是tiger、wolf、lion和leopard中的一种。对于同样的XML文档,Schema定义应该如清单4-39所示。
清单4-39 进一步限定flesh-eater
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="flesh-eater" type="eaterType"/>
<xs:simpleType name="eaterType">
<xs:restriction base="xs:string">
<xs:enumeration value="tiger"/>
<xs:enumeration value="wolf"/>
<xs:enumeration value="lion"/>
<xs:enumeration value="leopard"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
根据名称空间的意义,可以对上面的Schema做如下分析。
属于名称空间xs的元素有<xs:schema>、<xs:element>、<xs:simpleType>、<xs:restriction>、<xs:string>和<xs:enumeration>。
根据对清单4-38所示文档的分析可知,<xs:simpleType name="eaterType">中的“eater Type”仅为一个字符串。
另外<xs:restriction base="xs:string">中的属性base的值“xs:string”也是一个引用,该引用来自名称空间xs。
<xs:element name="flesh-eater"type="eaterType">中属性type的值“eaterType”也应该是一个引用,那么该引用又来自哪个名称空间呢?在清单4-39中查看名称空间的声明可以知道,除了http://www.w3.org/2001/XMLSchema外,找不到其他名称空间,所以eaterType应该不在任何名称空间内。
eaterType是否不处在任何名称空间内呢?可以通过改变Schema文档和XML文档中的名称空间声明来验证这个问题。为了叙述方便,将不处于任何名称空间视作“无名称空间”。可以看到<xs:simpleType name="eaterType">是对eaterType的定义。也就是说<xs:simpleType>的定义,会把eaterType放入无名称空间。到底情况是否这样呢?下面将清单4-39改写为清单4-40所示的样子。
清单4-40 改写后的Schema文档
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www. extralNamespace.com">
<xs:element name="flesh-eater" type="eaterType"/>
<xs:simpleType name="eaterType">
<xs:restriction base="xs:string">
<xs:enumeration value="tiger"/>
<xs:enumeration value="wolf"/>
<xs:enumeration value="lion"/>
<xs:enumeration value="leopard"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
代码分析如下:在清单4-40中,除名称空间http://www.w3.org/2001/XMLSchema外,又声明了一个默认名称空间xmlns="http://www.extralNamespace.com"。此时再次对原XML文档进行验证,得到如下错误提示。
Schema Representation Constraint: Namespace 'http://www.extralNamespace.com' is referenced without <import> declaration
该错误提示表明:处理器对XML文档进行验证时寻找名称空间http://www.extral Namespace.com,但没有找到。名称空间http://www.extralNamespace.com是默认名称空间,处理器一定是在引用默认名称空间中的对象时发生了错误。属于默认名称空间的只有两个可能,一个是<xs:simpleType name="eaterType">中的eaterType,另一个是<xs:element name="flesh-eater" type="eaterType">中的eaterType。那么,到底是哪一个呢?
为了验证是哪一个,将Schema文档修改为清单4-41所示的样子。
清单4-41 第二次改写的Schema文档
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www. extralNamespace.com">
<xs:element name="flesh-eater" type="xs:string"/>
<xs:simpleType name="eaterType">
<xs:restriction base="xs:string">
<xs:enumeration value="tiger"/>
<xs:enumeration value="wolf"/>
<xs:enumeration value="lion"/>
<xs:enumeration value="leopard"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
代码分析如下:在清单4-41中,保留了默认名称空间,而将原来的<xs:element name="flesh-eater" type= "eaterType"/>改为<xs:element name="flesh-eater" type="xs:string"/>。重新验证原来的XML文档,会得到如下提示。
The XML document 4-37.xml is valid
这证明修改代码之后验证通过,同时也说明<xs:simpleType name="eaterType">跟默认名称空间没有任何关系。那么唯一的可能就是<xs:element name="flesh-eater" type="eaterType"/>中的eaterType引用来自默认名称空间。
为了确认上面的想法,可以将Schema文档修改为如清单4-42所示的样子。
清单4-42 第三次改写的Schema文档
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xt="http://www. extralNamespace.com">
<xs:element name="flesh-eater" type="eaterType"/>
<xs:simpleType name="eaterType">
<xs:restriction base="xs:string">
<xs:enumeration value="tiger"/>
<xs:enumeration value="wolf"/>
<xs:enumeration value="lion"/>
<xs:enumeration value="leopard"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
代码分析:在清单4-42所示的Schema文档中,重新恢复了<xs:element name="flesh-eater" type= "eaterType"/>中对eaterType的引用,但将原来的默认名称空间声明修改为绑定了xt前缀的名称空间。此时,已经没有元素或属性的引用属于名称空间xt了,而<xs:element name="flesh-eater" type="eaterType"/>中的eaterType只能属于无名称空间。
再次对清单4-37所示的XML文档进行验证时,会得到如下提示。
The XML document 4-37.xml is valid
这表明验证通过,并且没有任何引用来自xt名称空间。此时,将XML源文档修改为清单4-43所示的样子。
清单4-43 第一次修改后的XML文档
<?xml version="1.0"?>
<flesh-eater>fox</flesh-eater>
对清单4-43所示的XML文档进行验证,会得到如下错误提示。
Datatype error: Type:InvalidDatatypeValueException, Message:Value 'fox' is not in enumeration .
产生该错误的原因为“fox”不是枚举类型中的一员。这证明<xs:simpleType name= "eaterType">将其定义的简单类型eaterType放在了某个名称空间内,而<xs:element name ="flesh-eater" type="eaterType"/>中的eaterType引用就来自该名称空间。毫无疑问,这个名称空间就是无名称空间。
为了直观起见,以上的XML文档并未包含与Schema的关联代码。如果将关联代码也显示出来,实际的XML文档应该如清单4-44所示。
清单4-44 带关联代码的XML文档
<?xml version="1.0"?>
<flesh-eater xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceschemaLocation="4-42.xsd">tiger</flesh-eater>
代码分析如下:在清单4-44所示的XML文档中xsi:noNamespaceschemaLocation= "4-42.xsd",用来关联XML文档与Schema文档。其关键字“noNamespaceSchemaLocation”(无名称空间位置)直接指向了Schema的物理地址。“noNamespaceSchemaLocation”其实已经表明了Schema文档所声明的元素都处在无名称空间中。而Schema文档所定义的元素又是XML文档中的元素,在本例中为元素<flesh-eater>。所以XML文档中的<flesh-eater>也只能处于无名称空间中。为了验证该结论,将清单4-44修改为如清单4-45所示的样子。
清单4-45 第二次修改XML文档
<?xml version="1.0"?>
<flesh-eater xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespace SchemaLocation=" 4-42.xsd" xmlns="http://www.auto.com"/>tiger</flesh-eater>
代码分析如下:在清单4-45中,定义了一个默认名称空间http://www.auto.com,那么元素<flesh-eater>属于该默认名称空间。重新验证该XML文档,得到如下错误提示。
Unknown element 'flesh-eater'
该错误提示表明找不到元素<flesh-eater>。处理器根据xsi:noNamespaceSchemaLocation找到XML对应的Schema,却发现该Schema中并不存在http://www.auto.com的名称空间。在一个不存在的名称空间中自然更找不到名称为flesh-eater的元素了。
通过以上分析,可以得到以下结论。
(1)对于一个Schema文档,其自定义简单类型<xs:simpleType name="eaterType">定义后,该类型置于无名称空间中。当文档中有元素定义<xs:element type="eaterType">时,处理器会在eaterType所处的名称空间中,搜索该类型引用。当然,就目前所讲述的知识来看,eaterType处于无名称空间。这是Schema内部的相互引用。
(2)对于一个XML文档,当其与Schema关联起来,并使用处理器验证时,应先确定XML元素的名称空间,然后在所指定的Schema搜索相应名称空间的相应元素,再进行验证。
事实上,<xs:element name="flesh-eater" type="eaterType"/>的元素< flesh-eater >声明后,也是放在无名称空间中。所以名称空间在XML与Schema验证的过程中起到了一个纽带的作用。
4.2.11 使用比喻来解释type属性和名称空间关系
最后,结合本节的例子,使用一个比喻来结束本节的内容。
Schema文档如下所示。
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="flesh-eater" type="eaterType"/>
<xs:simpleType name="eaterType">
<xs:restriction base="xs:string">
<xs:enumeration value="tiger"/>
<xs:enumeration value="wolf"/>
<xs:enumeration value="lion"/>
<xs:enumeration value="leopard"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
在前面的内容中,曾经将名称空间声明与一家公司的全称联系起来,并把Schema文档比做大厦的模型,现在就来看一下这个模型是如何建造的。
首先,声明一家最原始的原材料公司“W3C”,假设原材料都是从那里来的。那么用不用去找W3C公司的地址呢?不用,已经有一个神通广大的人做这些工作了,这个人就是处理器。只要告知“我需要字符型原材料”或“我要自己创建一个新的材料,请给我一些基础的东西”,他就会拿来。于是,有了xs:string等原材料。
现在,可以使用<xs:element>来创建模型的一个部件了,可以给该部件起个名字叫flesh-eater。flesh-eater创建之后,应该打个商标啊,很遗憾,因为创建者可能是个小作坊,连公司名字都没有呢(无名称空间)。部件flesh-eater创建好,就直接放在生产车间里。
在flesh-eater创建的过程中,可能要用到一个表明该部件技术指标的标牌或铭牌——而且可能其他的部件也有可能用到(自定义简单类型或内置简单类型)。有的铭牌直接使用W3C的(内置简单类型),所以上面一定有该公司的标签(xs);有的铭牌是自己生产的(自定义简单类型),因为本身也没有正式的公司名字,只给该铭牌起个名字吧,就叫eaterType(仍然处于无名称空间中)。自己用的时候,就直接在车间里拿就好了,反正没有商标的都是自产的(type="eaterType")。
通过以上步骤,模型就做好了。
XML文档如下所示。
<?xml version="1.0"?>
<flesh-eater xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="4-42.xsd">tiger</flesh-eater>
好了,现在该验收工程师(验证器)出场了。他首先查看了大厦(XML文档)的结构,发现只有一个部件需要验收(flesh-eater),而且该部件没有标明生产厂商。在这种情况下,他就用无公司名称时的定位规则(noNamespaceSchemaLocation)去寻找厂商的实际地址(4-42.xsd)。找到了生产厂商的车间,要求flesh-eater部件的模型,他发现这个模型也是没有商标的(属于无名称空间)。当然,要是厂商提供的模型有商标,那就对不上号了。验收工程师根据模型上的参数和指标来查看实际的工程(XML文档)是否合格。
再来考察一下清单4-41中声明默认名称空间的情形。代码如下所示。
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www. extralNamespace.com">
<xs:element name="flesh-eater" type="xs:string"/>
<xs:simpleType name="eaterType">
<xs:restriction base="xs:string">
<xs:enumeration value="tiger"/>
<xs:enumeration value="wolf"/>
<xs:enumeration value="lion"/>
<xs:enumeration value="leopard"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
首先声明没有打商标的部件一律都是由extralNamespace公司生产的,所以对于自己生产的部件flesh-eater的参数铭牌(type="eaterType")引用自extralNamespace公司。注意部件flesh-eater仍然没有商标,也就是说仍然处于无名称空间中;虽然自己也生产了参数铭牌(<xs:simpleType name="eaterType">)但也没有商标(处于无名称空间中)。
以上操作都没有什么问题。但当验收工程师到来时,他会索要extralNamespace公司的那个参数铭牌,甚至要extralNamespace公司的实际地址。在<xs:element name="flesh-eater" type="eaterType"/>中,除了说明该部件参数指标见extralNamespace公司的名为eaterType的铭牌外,什么都没说明。因为不知道该铭牌到底标记了哪些参数,甚至连该公司的地址都不知道。验收工程师自然在验收报告上注明:该模型中引用了extralNamespace公司的技术指标,但是并未见其真的跟该公司有何联络。无法验收。XML文档验收提示如下:
Schema Representation Constraint: Namespace 'http://www.extralNamespace.com' is referenced without <import> declaration
★ 说明 ★
XML Schema的定义语法并不复杂。真正的问题在于如何理解整个Schema文档,如何理解XML文档与Schema文档之间的联络,Schema文档是如何验证XML文档的。这中间名称空间起到了非常重要的作用。读者可以注意揣摩。
事实上无名称空间是不存在的。在上例中,处理器主要是通过Schema文档中声明的元素名与XML实例元素名之间的对应来进行验证的。使用无名称空间的说法不过是为了对名称空间的作用进行说明,而且还可以与下一章将要讲述的有名称空间的关联在概念上统一起来。
在此之前的XML和Schema文档中,一直使用的是无名称空间。其实,最常用的是有确定的名称空间,也就是说,生产模型的厂商有自己的名字(商标)。这就需要用到target Namespace关键字,它将在下一章介绍。
4.2.12 简单数据类型小结
本节主要讲述了Schema的简单数据类型。简单数据类型的主要作用是用来定义简单元素。简单类型按照不同的方式可以分为不同的类型。
1.内置简单类型和自定义数据类型
(1)内置简单类型是指Schema的名称空间中所定义的44种数据类型。它们以xs为前缀。
(2)自定义简单类型是指由开发者自行定义的数据类型。一般用<xs:simpleType>进行定义。
2.原子类型、列表类型和联合类型
(1)原子类型是指所定义的数据无法进行分割的类型。
(2)列表类型是指所定义的数据每一个子项都有明确的意义。
(3)联合类型是指所定义的数据符合若干类型中的一种。
下表是来自W3C的关于简单类型的总结。在该表中,第一列显示了所有的内置简单类型,第二列显示了可用于内置简单类型的约束。读者可以在这里查找到有关简单类型的定义信息。
|
{base type definition} |
applicable {facets} |
|
If {variety} is list, then |
|
|
[all datatypes] |
length, minLength, maxLength, pattern, enumeration, whiteSpace |
|
If {variety} is union, then |
|
|
[all datatypes] |
pattern, enumeration |
|
else if {variety} is atomic, then |
|
|
string |
length, minLength, maxLength, pattern, enumeration, whiteSpace |
|
boolean |
pattern, whiteSpace |
|
float |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
double |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
decimal |
totalDigits, fractionDigits, pattern, whiteSpace, enumeration, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
duration |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
dateTime |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
time |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
date |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
gYearMonth |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
gYear |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
gMonthDay |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
gDay |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
gMonth |
pattern, enumeration, whiteSpace, maxInclusive, maxExclusive, minInclusive, minExclusive |
|
hexBinary |
length, minLength, maxLength, pattern, enumeration, whiteSpace |
|
base64Binary |
length, minLength, maxLength, pattern, enumeration, whiteSpace |
|
anyURI |
length, minLength, maxLength, pattern, enumeration, whiteSpace |
|
QName |
length, minLength, maxLength, pattern, enumeration, whiteSpace |
|
NOTATION |
length, minLength, maxLength, pattern, enumeration, whiteSpace |
4.3 元素的默认值和固定值
前面,着重介绍了简单元素的定义。简单元素的一般定义形式为<xs:element name="elementName" type="elementType"/>。其中name和type是必需的属性,其实还有另外两个可选的属性——default(默认值)和fixed(固定值)。
★ 注意 ★
严格意义上,type属性也是可选的。但是一旦元素声明中不含有type属性,元素就成为任意类型,即可以含有任意的内容,从而就对XML实例元素没有任何约束,这就失去了Schema定义的基本意义。因此,绝大多数情况下,type属性也是必需的。
4.3.1 元素默认值
元素的默认值是在Schema中预先设定元素内容。当元素内容为空时,处理器会将该元素的值当做预设值。元素默认值的使用语法如下所示。
<xs:element name="elementName" type="elementType" default="defaultValue"/>
例如,想要定义家用电压,当不进行特殊说明时,家用电压为220V。相应XML Schema文档如清单4-46所示。
清单4-46 定义家用电压的XML Schema
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="voltage" type="xs:string" default="220V"/>
</xs:schema>
XML实例文档如代码4-47所示。
清单4-47 表示家用电压的XML文档
<?xml version="1.0"?>
<voltage></voltage>
代码说明:
在清单4-47的XML文档中,元素<voltage>没有内容,处理器在验证时,就会将该元素内容视为字符串“220V”。
如果在XML文档中,元素<voltage>的内容不为空,则默认值的设置失效。
如果在某个复杂的XML文档中,并未出现某个元素,那么,即使为该元素设置了默认值,处理器也不会将其内容视为默认值。
★ 说明 ★
默认值的使用仍未超出简单元素的范围,复杂元素不存在默认值。
4.3.2 元素默认值的用途
上一节讲到default属性为XML元素预设值。当XML中的某个简单元素的文本内容为空时,处理器在进行有效性验证时会将该元素的值视为默认值。在这里,处理器只是将元素的值视为默认值,并不会改变XML文档的内容。这是一定要明确的概念。
处理器使用type属性所设定的数据类型来验证default属性所设定的数据,这似乎已经跟XML文档脱离了关系。其实不然,根据笔者的经验,default有时会发挥不可或缺的作用。
当元素的数据类型不是字符型,元素内容为空时,处理器认为该元素的内容是一个空字符串。若未设默认值,处理器将使用空字符串进行验证。这时,有的XML文档将无法通过有效性验证。
例如,有一个名为quantity的表示数量的元素。在没有数量信息的时候,quantity暂时为空。
XML实例代码如下所示。
<quantity></quantity>
或者如下所示。
<quantity/>
未设定default属性的Schema代码如下所示。
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="quantity" type="xs:integer" />
</xs:schema>
代码说明:
<xs:element name="quantity" type="xs:integer"/>是一个元素声明。其中“quantity”是元素的名字,xs:integer指定元素数据类型为整型。
在元素声明中,并未指定默认值。对XML文档进行有效性验证,得到如下错误提示。
Value '' does not match regular expression facet '[+\-]?[0-9]+'.
该消息表明:处理器将一个空字符去匹配一个表示整数的正则表达式,无法通过验证。也就是说,对于整型,XML元素不能为空。
元素声明加入默认值设定后的代码如下所示。
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="quantity" type="xs:integer" default="0"/>
</xs:schema>
这样即使元素quantity的内容为空,XML仍能通过有效性验证。
★ 说明 ★
产生该问题的原因是因为空元素的内容被视为一个字符串",该字符串自然无法通过非字符串类型的验证。此时利用default属性是一个很好的选择。
4.3.3 元素固定值
元素的固定值也是在Schema文档中预设XML元素的值。默认值只有当元素出现,但内容为空时起作用。而与默认值不同的是,固定值限定XML元素出现时,其值必须和固定值相等。固定值的使用语法如下所示。
<xs:element name="elementName" type="elementType" fixed="fiexedValue"/>
例如,要设定冰点的温度必须为0度,XML Schema定义如清单4-48所示。
清单4-48 固定值Schema实例
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ice_temperature" type="xs:integer" fixed="0"/>
</xs:schema>
XML实例文档如代码4-49所示。
清单4-49 固定值XML实例
<?xml version="1.0"?>
<ice_temperature>0</ice_temperature>
代码说明:
在清单4-49所示的XML文档中,元素<ice_temperature>的值必须为0。
fixed属性和default属性互斥,如果二者出现在同一个元素定义中,处理器将抛出如下错误。
Element 'ice_temperature' cannot have both 'fixed' and 'default' present at the same time.
4.4 本章小结
简单元素是指没有子元素,只含有文本的元素。声明简单元素要用到Schema的简单类型,而Schema的简单类型又可以分为内置简单类型和自定义简单类型。内置简单类型有44种,是XML Schema提供的用于定义元素类型的最基本“原材料”。通过内置简单类型,可以派生新的简单类型,这就是自定义简单类型。
在本章所列举的Schema文档中,声明的元素都是没有名称空间的。处理器验证通过文件物理地址获得具体XML Schema文档,并通过元素名称的对应关系进行验证。尤其要清晰的概念是,无名称空间不是一个实际的名称空间。元素默认值和元素固定值是元素声明中的可选属性,但要注意二者同时出现会发生冲突。






