780 likes | 1.01k Views
第 3 章 XML 模式语言 ( XML Schema ). DTD 的缺点 : (1) 缺少数据类型和命名空间的支持 ; (2) 语法规则过于简单以至描述能力有限 ; (3) 使用非 XML 的格式等。 XML Schema 是专用于 XML 的模式语言,功能更强大 , 且本身即为 XML 格式。. 3.1 XML 模式语言. XML 模式语言是指用来描述 XML 结构、数据内容、相关约束等方面特征的语言。 XML 模式语言的种类很多: ISO Schematron
E N D
DTD的缺点: (1)缺少数据类型和命名空间的支持; (2)语法规则过于简单以至描述能力有限; (3)使用非 XML 的格式等。 • XML Schema是专用于XML的模式语言,功能更强大,且本身即为XML格式。
3.1 XML 模式语言 • XML 模式语言是指用来描述 XML 结构、数据内容、相关约束等方面特征的语言。 • XML 模式语言的种类很多: • ISO Schematron • XDR (XML-DATA Reduced) • XML Schema • RELAX NG 一种非常独特的 XML 模式语言,无论是结合其他模式语言或者单独使用都具有强大的功能。Schematron 语言允许直接表达规则,而不需要创建完整的语法基础设施。 W3C 的正式推荐标准,提供了 XML 模式声明的完整语法、丰富的数据结构等,目前已成为应用最广泛的 XML 模式语言。 是由 Microsoft 公司提出的 XML 简化模式语言,作为 W3C 在讨论 XML Schema 工作草案过程中提出的一种过渡性 Schema 语言,XDR 已经被业界普遍认可,得到许多产品(例如,MS-BiztalkServer、MS-SQLServer、MS-Office)的广泛支持。 一种基于语法的 XML 模式语言,可用于描述、定义和限制 XML 词汇表。它以简洁性和表达能力著称,并且具有良好的可扩展性。
XML Schema 的特征 1 • 与 DTD 相比,XML Schema 具有特征: • 一致性:XMLSchema 利用 XML 的基本语法规则来定义其文档结构,从而使 XML的模式和实例定义达到统一;继承了XML的自描述性和可扩展性,使其更具有可读性和灵活性。 • 完备性:XML Schema 对 DTD 进行了扩充,引入了数据类型、命名空间,并且支持对其他 XML Schema 的引用,从而使其具备较强的模块性; • 规范性和准确性:XML Schema 提供了更加规范和完备的机制来约束 XML 文档。XML Schema 的语义更加准确,可以完成一些 DTD 不能完成的定义,如对元素出现次数的约束等。
XML Schema 的特征 2 • 面向对象特征:XML Schema 中引入了许多成熟的面向对象机制(比如继承性和多态性),使得数据模式在应用中更加灵活。 • 扩展性:DTD 所描述的文档结构是非常严格的(closed),没有显式声明的内容绝不允许在 XML 实例数据中出现;而 XML Schema 则提供了一些扩展机制(open),允许在事先无法准确描述数据模式的情况下,在 XML 实例数据中根据需要添加相关的数据。
3.1.2 XML Schema 的一个简单示例 • student.xsd • XML Schema 文件的后缀名通常为 .xsd • XML Schema 文件是一个特殊的 XML 文件。 • 注意根元素及命名空间。
实例 XML 文档 <?xml version="1.0" encoding="UTF-8"?> <student> <name>XiaoWang</name> <gender>男</gender> <no>123</no> <telephone>010-12345678</telephone> <gpa>80</gpa> </student> <?xml version="1.0" encoding="UTF-8"?> <student xsi:noNamespaceSchemaLocation="student.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> ...... </student>
XML Schema 中的“注释”元素 • 在 W3C XML Schema 文件中,推荐使用 xsd:annotation 元素来增加注释内容,xsd:annotation 元素可以包含两个子元素 xs:appinfo 和 xs:documentation。 • 前者用于表示计算机应用程序处理的注释,而后者则表示供开发人员阅读的注释。 • 这两个子元素是 W3C XML Schema 中唯一的混合内容模型的元素,其中可以包含任何文本和子元素。
3.2 XML Schema 中的数据类型 • 元素是其中最为重要的组成部分,一个 XML 文档中可能不包含任何属性或者文本数据,但是必须包含元素(至少包含一个根元素)。 • XML Schema 中的数据类型实际上主要是针对 XML 元素而言的,换句话说,是针对各种元素的内容及其结构的。
元素的类型 • 在 W3C 的 XML Schema 规范中,将元素分为两类: • 简单类型:不包含任何子元素和属性的元素。换句话说,简单类型的元素只能包含文本内容,或者为不包含属性的空元素(文本内容为空)。 • 复杂类型:包含子元素和/或属性的元素(其中属性的声明包含在元素的复杂类型定义中)。 <lastname> Jack </lastname> <description/> <product pid="1345"/> <food type="dessert">Ice cream</food>
有关元素类型的说明 • 简单类型元素只能包含文本内容,而复杂类型元素除了包含子元素和/或属性之外,也可以包含文本内容。 • “文本内容”并不是指的字符串数据类型,在 XML Schema 规范中定义了 44 种简单数据类型 ,“文本内容”可以是这些简单数据类型中的任何一种(甚至还可以是派生的简单数据类型)。 • 比如: <xsd:element name=“orderid” type=“xsd:integer”/>。 <orderid>1032</orderid> 正确 <orderid>abc</orderid> 错误
3.2.1 XML Schema 的内置数据类型 • anyType 是 XML Schema 中所有数据类型(包括简单类型和复杂类型、内置数据类型和用户定义数据类型)的基础类型,如果拿 Java 语言来做个类比,那么 xsd:anyType 类似于 Java 中的 java.lang.Object。 • anyType 分为“简单类型”和“复杂类型”。 • anyType 是一种实际的、可用的数据类型,而不仅仅只是在 XML Schema 数据类型层次结构中作为抽象的根节点。 比如: • <element name="Currency" type="anyType" /> • <Currency> USD </Currency> • <Currency><dollars>100</dollars></Currency> • anySimpleType 是所有简单数据类型的基础类型。 • anySimpleType 也是一种实际的、可用的数据类型,它是所有简单数据类型的根节点,与 anyType 不同的是,它只能表示标量数据。 • 比如: • <element name="Currency" type="anySimpleType" /> • <Currency> USD </Currency> • <Currency><dollars>100</dollars></Currency> • 内置基本数据类型(Primitive Datatype):这些类型是独立存在的,而不是在其他数据类型的基础上定义的。比如数学上的十进制数,定义为 decimal。 • 在 XML Schema 规范中,一共定义了 19 中内置的基本数据类型,它们可以单独使用、或者作为其他派生数据类型(包括内置派生数据类型和用户派生数据类型)的基础类型。 • 内置派生数据类型(Derived Datatype):这些内置类型的定义依赖于其他的数据类型(即内置基本数据类型)。 • 比如 decimal 和 nonNegativeInteger,可以将后者理解为满足某种条件(非负整数)的 decimal,实际上,decimal 是 XML Schema 中所有十进制数值类型的基础类型。
3.2.2 XML Schema 中的派生简单数据类型 • 仅使用44种基本数据类型仍然是不够的。比如,假设希望定义一个 email 数据类型、或者 telephone 数据类型,用于约束合法的 email 和 telephone 数据,那又该怎么做呢? • XML Schema 为此提供了自定义简单数据类型、复杂数据类型的机制,以便用户在需要的时候对 XML Schema 类型系统进行扩充。 • 可以通过几种不同的方法(通过限制、列表、或者组合)自定义简单数据类型。
1. 通过限制(restriction)派生简单数据类型 • 通过限制的方式派生简单数据类型的语法格式如下所示,下面的两种形式分别声明了一个无名的、以及一个命名的(名为 SimpleTypeName)简单数据类型: <xsd:simpleType> <xsd:restriction base="BaseType"> ... facets descriptions ... </xsd:restriction> </xsd:simpleType> 或者: <xsd:simpleType name="SimpleTypeName"> <xsd:restriction base="BaseType"> ... facets descriptions ... </xsd:restriction> </xsd:simpleType>
a). 通过设置最大值或最小值,对数值类型取值的范围进行限制 <xsd:elementname="MyIntegerElement" type="MyInteger"/> <xsd:simpleType name="MyInteger"> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="0"/> <xsd:maxInclusive value="100"/> </xsd:restriction> </xsd:simpleType> <xsd:elementname="MyIntegerElement"> <xsd:simpleType> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="0"/> <xsd:maxInclusive value="100"/> </xsd:restriction> </xsd:simpleType> </xsd:element> 与 minInclusive 和 maxInclusive 相对应,还有 minExclusive 和 maxExclusive,后面两种限制方面的取值空间为开区间。
b). 通过枚举,将取值空间限制为一组合法的取值 <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="Audi"/> <xsd:enumeration value="Golf"/> <xsd:enumeration value="BMW"/> </xsd:restriction> </xsd:simpleType> 这个数据类型的基本类型是 xsd:string,在此基础上,通过xsd:enumeration 列举出了若干个合法的取值。
c). 通过给定一个正则表达式,限制字符串内容的模式 <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:pattern value="[a-z]"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="Telephone"> <xsd:restriction base="xsd:string"> <xsd:pattern value="(\d{4}-\d{8})|(\d{3}-\d{8})|(\d{4}-\d{7})"/> </xsd:restriction> </xsd:simpleType>
正则表达式的使用 • 比如我们希望建立一个 email 数据类型,以便验证在用户提交的 XML 文档中,指定的元素中包含合法的电子邮件地址: • 很多文本编辑器(如 EditPlus、Word)中进行内容查找时,可以使用正则表达式作为条件。另外 Java 语言中提供了java.util.regex,其中包含 Matcher 和 Pattern 两个类、以及其他的接口等,借助正则表达式的强大功能,从而极大地增强了面向对象的 Java 语言的文本处理能力。 ([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5}) somthing@someserver.com firstname.lastname@mailserver.domain.comsomename@server.domain-com 可以参考网站 http://regexlib.com
d). 限制文本内容中字符串的长度 • 可以使用 length、maxLength 和 minLength 等 Schema 元素来限制文本内容的长度。 <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:length value="8"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:minLength value="5"/> <xsd:maxLength value="8"/> </xsd:restriction> </xsd:simpleType>
e). 限制文本内容中数值的位数和小数位数 • 可以使用 totalDigits 和 fractionDigits 来限制数值的总位数和小数位数。 <xsd:simpleType> <xsd:restriction base="xsd:decimal"> <xsd:totalDigits value="4"/> <xsd:fractionDigits value="2"/> </xsd:restriction> </xsd:simpleType>
<xsd:simpleType name="minInclusive"> <xsd:restriction base="xsd:float"> <xsd:minInclusive value="10"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="minInclusive2"> <xsd:restriction base="minInclusive"> <xsd:minInclusive value="0"/> </xsd:restriction> </xsd:simpleType> 有关通过限制派生简单数据类型的几项说明 • ①.在通过限制派生简单数据类型时,必须注意取值空间的有效性。 • ②.对于所有的限制方面,不允许在进行限制的同时扩大基本数据类型的值空间。 <xsd:simpleType> <xsd:restriction base="xsd:int"> <xsd:totalDigits value="1"/> <xsd:minInclusive value="10"/> <xsd:maxInclusive value="100"/> </xsd:restriction> </xsd:simpleType>
2.通过列表(List)派生简单数据类型 • 仅有前面介绍的简单类型仍然不够,假设我们希望在某个元素的内容中包含由若干个整数值组成的文本,比如: • 通过列表进行派生,实际上就是在定义列表中每个项目的具体类型的基础上,允许多个项目构成一个列表(其中使用空格进行分隔)。 <MyIntegers>100 101 102</MyIntegers>
通过列表进行派生 1 <xsd:simpleType name="integerList"> <xsd:list itemType="xsd:integer"/> </xsd:simpleType> <xsd:simpleType name="myIntegerList"> <xsd:list> <xsd:simpleType> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="100"/> </xsd:restriction> </xsd:simpleType> </xsd:list> </xsd:simpleType>
通过列表进行派生 2 <xsd:simpleType name="integerGE100"> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="100"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="myIntegerList"> <xsd:list itemType="integerGE100"/> </xsd:simpleType> <xsd:simpleType name="myIntegerList"> <xsd:list> <xsd:simpleType> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="100"/> </xsd:restriction> </xsd:simpleType> </xsd:list> </xsd:simpleType> <xsd:simpleType name="FourIntegerList"> <xsd:restriction base="myIntegerList"> <xsd:length value="4"/> </xsd:restriction> </xsd:simpleType>
3. 通过合并(Union)派生简单数据类型 • 通过列表派生简单数据类型,使得我们可以在文本内容中加入多个项目(比如多个整数值),但是无论有多少个项目,它们的数据类型必须一致,这是通过列表方式派生简单数据类型的基本要求。 • 假设在一个 student 元素中存放学生各门功课(语、数、外三门)的成绩: <student1>70 80 90</student1> <student2>70 80 N/A</student2>
通过合并进行派生 <xsd:simpleType name="integerOrDate"> <xsd:union memberTypes="xsd:integer xsd:date"/> </xsd:simpleType> <xsd:simpleType name="myIntegerUnion"> <xsd:union> <xsd:simpleType> <xsd:restriction base="xsd:integer"/> </xsd:simpleType> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="N/A"/> </xsd:restriction> </xsd:simpleType> </xsd:union> </xsd:simpleType>
3.2.3 XML Schema 中的派生复杂数据类型 • 下面的两种形式分别声明了一个无名的、以及一个命名的(名为 ComplexTypeName)复杂数据类型: <xsd:complexType> ...... </xsd:complexType > 或者: <xsd:complexType name="ComplexTypeName"> ...... </xsd:complexType>
复杂数据类型的几种情况 • 只包含属性、不包含子元素和文本内容; • 比如:<product pid="1345"/> • 只包含子元素,不包含文本内容; • 比如: • <employee> • <firstname>John</firstname> • <lastname>Smith</lastname> • </employee> • 只包含文本内容和属性,不包含子元素; • 比如:<food type="dessert">Ice cream</food> • 同时包含子元素和文本; • 比如: • <description> • It happened on • <date lang="norwegian">03.03.99</date> • .... • </description>
1. 空元素(只包含属性、不包含子元素和文本内容) • 对于包含属性的空元素,定义过程非常简单,只需定义所需的属性及其数据类型即可。 <xsd:complexType name="ComplexType"> <xsd:attribute name="Att1Name" type="someSimpleType1"/> <xsd:attribute name="Att2Name" type="someSimpleType2"/> ...... </xsd:complexType>
2. 只包含子元素,不包含文本内容(可能包含属性) • XML Schema 中提供了几种不同的容器(对应于不同的分组模式),以便表示其中子元素的出现顺序,它们分别是 xsd:sequence、xsd: choice、xsd:all。
xsd:sequence • 表示序列,即元素必须按照声明的顺序出现。 <xsd:complexType name="studentType"> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:element name="student" type="studentType"/> • 表示序列,即元素必须按照声明的顺序出现。 • 元素的声明必须放在某个容器中,而不能直接出现在 xsd:complexType 元素中,即使是只有一个子元素。
xsd: choice • 表示从所包含的内容中选择其一。 <xsd:complexType name="PurchaseOrderType"> <xsd:sequence> <xsd:choice> <xsd:sequence> <xsd:element name="shipTo" type="USAddress"/> <xsd:element name="billTo" type="USAddress"/> </xsd:sequence> <xsd:element name="singleUSAddress" type="USAddress"/> </xsd:choice> <xsd:element name="items" type="Items"/> </xsd:sequence> <xsd:attribute name="orderDate" type="xsd:date"/> </xsd:complexType> <xsd:element name="PurchaseOrder" type="PurchaseOrderType"/>
xsd:all • 表示其中所包含的内容不分先后顺序。 <xsd:complexType name="studentType"> <xsd:all> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd: all> </xsd:complexType> <xsd:element name="student" type="studentType"/>
3. 只包含文本内容和属性,不包含子元素 • 对于这种类型的元素,只包含简单内容(文本和属性),在进行声明时,XML Schema 中引入了一个新的元素,称为 simpleContent(用于表示“文本”、或者“文本+属性”)。
示例 1 • 比如,shoesize 元素只包含属性 country 和文本内容(具体的 shoesize 大小,一个整数值): <shoesize country="france">35</shoesize> <xsd:element name="shoesize"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:integer"> <xsd:attribute name="country" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element>
xsd:extension 和 xsd:restriction • 使用 xsd:extension 元素,可以对基础类型进行扩展;但元素文本内容的类型实际上只能由 base 属性所指定的类型来决定,在 xsd:extension 元素中,只能定义与属性有关的内容(xsd:attribute、xsd:anyAttribute、xsd:attributeGroup)。 • 使用 xsd:restriction 元素,可以对基础类型进行限制;与 xsd:extension 一样,元素文本的类型是由 base 属性所指定的类型来决定,但是可以在 xsd:restriction 元素中使用各种限制方面(Facet)对其进行限制;
4. 同时包含子元素和文本(可能包含属性) • 与 DTD 中一样,我们将这种类型的元素所包含的内容称为混合内容。 • 要定义这种复杂数据类型,需要使用 complexType 的 mixed 属性。
示例 <letter letter_id="123"> Dear Mr.<name>John Smith</name>. Your order <orderid>1032</orderid> will be shipped on <shipdate>2007-07-13</shipdate>. </letter> <xsd:element name="letter"> <xsd:complexType mixed="true"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="orderid" type="xsd:positiveInteger"/> <xsd:element name="shipdate" type="xsd:date"/> </xsd:sequence> <xsd:attribute name="letter_id" type="xsd:positiveInteger"/> </xsd:complexType> </xsd:element>
3.2.4 有关类型声明的完整语法 • 前面介绍了如何声明简单数据类型和复杂数据类型,主要使用的是下面的简单的语法形式: <xsd:simpleType name="simpleTypeName"> ...... </xsd: simpleType> 以及: <xsd:complexType name="complexTypeName"> ...... </xsd:complexType>
3.2.4.1 simpleType 元素的属性 <simpleType final = (#all | List of (list | union | restriction)) id = ID name = NCName> Content: (annotation?, (restriction | list | union)) </simpleType> • final 属性的值表示该数据类型不允许进行的操作的列表,比如本示例中,不允许使用列表对该类型进行派生。但是可以直接使用该类型。 • #all 表示不能对该类型进行任何操作。
3.2.4.2 complexType 元素的属性 <complexType abstract = boolean : false block = (#all | List of (extension | restriction)) final = (#all | List of (extension | restriction)) id = ID mixed = boolean : false name = NCName> Content: (annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))) </complexType> • abstract 属性表示该复杂类型是一个虚类型,只能用作其他类型的父类型。
XML Schema 中的面向对象特性(OO Features)——多态性 <xsd:complexType name="Class1" abstract="true"> <xsd:sequence> <xsd:element name="Class1_subelement" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Class11"> <xsd:complexContent> <xsd:extension base="Class1"> <xsd:attribute name="Class11Attr" type="xsd:string"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:element name="obj" type="Class1"/> <obj Class11Attr="att" xsi:type="Class11"> <Class1_subelement>123</Class1_subelement> </obj>
block 属性 • 如果不希望使用多态性,可以使用 complexType 的 block 属性(它的取值可能为 #all、extension、restriction)。 • extension 和 restriction,分别表示禁止使用任何通过扩展/限制而派生的子类型的实例来代替声明为父类的元素。 • block 和 final 属性是有区别的,因为即使 block=“#all”,仍然可以派生新的子类型,而 final =“#all”则表示禁止派生。对于 block 来说,#all 表示禁止使用任何子类型的实例来代替声明为父类的元素。