当前位置: 首页 > 图文教程 > Java技术 > Java Web开发 > 孙鑫老师原创:XML Schema初窥(二)
Java Web开发 中的 孙鑫老师原创:XML Schema初窥(二)
4.5.4 复杂类型
具有复杂类型的元素可以有子元素和属性。复杂类型使用xs:complexType元素来定义。
复杂类型要么具有简单内容,要么具有复杂内容。元素的“内容”是指在它的开始标签和结束标签之间的字符数据和子元素。简单内容指的是它只包含字符数据内容,而没有子元素(可以有属性),简单内容使用xs:simpleContent元素来定义;除此之外的元素内容称为复杂内容,复杂内容使用xs:complexContent元素来定义。
例如,对于例4-10所示的具有简单内容的book元素,它的复杂类型定义如例4-11所示。
例4-10 实例文档中的book元素
<book issn= "978-7-121-06812-6">Struts 2深入详解</book>
例4-11 模式文档中的bookType类型定义
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="isbn" type="xs:token"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
简单内容类型的复杂元素要求必须含有文本,可以有属性。
对于例4-12所示的具有复杂内容的student元素,它的复杂类型定义如例4-13所示。
例4-12 实例文档中的student元素
<name>张三</name>
<age>20</age>
</student>
例4-13 模式文档中的studentType类型定义
<xs:element name="book" type="studentType"/>
<xs:complexType name="studentType">
<xs:complexContent>
<xs:restriction base="xs:anyType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
复杂内容类型的复杂元素可以有属性,但不能有文本。
直接在xs:schema元素下声明的元素和属性是全局的,这些元素和属性可以通过xs:element和xs :attribute元素的ref属性来引用。我们看例4-14。
例4-14 book.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book" type="bookType"/>
<xs:element name="title" type="xs:token"/>
<xs:element name="author" type="xs:token"/>
<xs:attribute name="isbn" type="xs:token"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element ref="title"/>
<xs:element ref="author"/>
</xs:sequence>
<xs:attribute ref="isbn"/>
</xs:complexType>
</xs:schema>
在例4-14中,声明的元素book、title和author,以及属性isbn都是全局的,在bookType类型定义中,我们通过xs:element和xs :attribute元素的ref属性来引用全局声明的元素和属性。
要注意的是:(1)全局声明的元素和属性的名称在模式中必须是唯一的。(2)在全局声明中不能使用ref属性。(3)全局声明的元素在实例文档中可以作为根元素出现。
在复杂类型定义内部声明的元素和属性是局部的,由于简单类型不能有子元素和属性,所以局部元素声明和局部属性声明不能出现在简单类型定义内部。我们将例4-14中的title、author元素,以及isbn属性改为局部声明,如例4-15所示。
例4-15 book2.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element name="title" type="xs:token"/>
<xs:element name="author" type="xs:token"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:token"/>
</xs:complexType>
</xs:schema>
现在title、author元素和isbn属性都是在bookType类型定义内部声明的,这些局部声明只能在bookType类型定义内部使用。
如果模式文档中所有声明的元素名都是唯一的,那么可以使用全局声明,然而,当有两个同名但具有不同类型的元素时,你就只能使用局部声明了。例如,你可以声明一个局部元素title,它有xs:token类型,而且它是book元素的子元素,在同一个模式文档中,你还可以声明一个局部元素title,它可带有枚举值“Mr Mrs Ms”。
对于属性而言,属性通常是附属于元素的,因此将属性声明为全局的意义不大,除非多个元素要使用相同的属性。
目标名称空间使用xs:schema元素的targetNamespace属性来指定,如例4-16所示。
例4-16 book3.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.ruanchen.com/"a0" style="margin: 0cm 0cm 0pt">
① 我们在xs:schema元素上使用targetNamespace属性指定目标名称空间为:http://www.ruanchen.com/"font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,即指明了在该模式文档中声明的元素、定义的类型都属于http://www.ruanchen.com/"font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">名称空间。
② 声明名称空间http://www.ruanchen.com/"font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,并为该名称空间绑定前缀book,使用该前缀来引用http://www.ruanchen.com/"font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">名称空间中的类型。
③ 由于指定了目标名称空间,文档中定义的类型都属于目标名称空间,因此在引用类型时,需要加上book前缀。
④ 在指定类型名时,不需要加上任何前缀,当使用了targetNamespace属性后,在模式文档中定义的任何类型都属于目标名称空间。
在模式文档中,我们很容易就能区分出不同名称空间中的元素和类型,带有xs前缀的元素和类型属于http://www.w3.org/2001/XMLSchema名称空间,而其他的元素和类型则属于目标名称空间。需要注意的是,只有模式文档中的全局元素和全局属性才属于目标名称空间,在本例中,声明的全局元素name属于目标名称空间,而局部元素title和author则不属于目标名称空间。
为了简化模式文档对目标名称空间中的元素和类型的引用,我们可以利用默认名称空间来简化引用,例4-16如果使用了默认名称空间,可以修改为如例4-17所示。
例4-17 使用了默认名称空间的book4.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
我们在xs:schema元素上声明了默认名称空间http://www.ruanchen.com/"font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,因此在声明book元素时,引用bookType类型就无须再添加前缀了。
符合上述模式文档的XML实例文档如例4-18所示。
例4-18 book.xml
<?xml version="1.0" encoding="GB2312"?>
<book:book xmlns:book="http://www.ruanchen.com/"http://www.ruanchen.com" style="color: #000">孙鑫</author>
</book:book>
在例4-17的模式文档中,在bookType类型定义中声明的元素title和author是局部元素,没有被目标名称空间所限定,因此在实例文档中,对title和author元素不要添加book前缀。
在例4-17中,局部元素title和author没有被目标名称空间所限定,如果要限定局部元素和属性,可以通过xs:schema元素的elementFormDefault和attibuteFormDefault属性来设置。
为了指定模式文档中局部声明的元素必须被限定,可以将xs:schema元素的elementFormDefault属性的值设为"qualified"。
将例4-17中的xs:schema元素修改为如例4-19所示。
例4-19 book5.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault属性的默认值是unqualified,即对局部声明的元素不加限定。
我们修改了模式文档,相应的就要修改实例文档,如例4-20所示。
例4-20 book2.xml
<?xml version="1.0" encoding="GB2312"?>
<book:book xmlns:book="http://www.ruanchen.com/"MsoNormal" style="text-indent: 21pt; margin: 0cm 0cm 0pt">
在例4-20的实例文档中,所有的元素都属于同一个名称空间,因此我们可以声明一个默认的名称空间,来省略前缀的使用,如例4-21所示。
例4-21 book3.xml
<?xml version="1.0" encoding="GB2312"?>
<book xmlns="http://www.ruanchen.com/"MsoNormal" style="text-indent: 21pt; margin: 0cm 0cm 0pt">
属性的限定和元素的限定是类似的。如果属性被声明为全局属性或者xs:schema元素的attibuteFormDefault属性被设置成"qualified"的话,那么属性就必须被限定,在实例文档中将以带名称空间前缀的方式出现。实际上,需要限定的属性必须明确的加上名称空间前缀,因为XML名称空间推荐标准中并没有给出关于属性的默认名称空间的机制,一个没有前缀的属性将不在任何的名称空间中。属性是附属于元素的,对属性添加名称空间不是很有必要,因此在多数应用中都没有给属性添加限定。
使用了attibuteFormDefault属性的模式文档,如例4-22所示。
例4-22 book6.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
attributeFormDefault属性的默认值是unqualified,即对局部声明的属性不加限定。
一个符合模式(例4-22)的实例文档如例4-23所示。
例4-23 book4.xml
<?xml version="1.0" encoding="GB2312"?>
<book:book xmlns:book="http://www.ruanchen.com/"MsoNormal" style="text-indent: 21pt; margin: 0cm 0cm 0pt">
除了使用xs:schema元素的elementFormDefault和attibuteFormDefault属性来限定局部元素和局部属性外,我们还可以在xs:element和xs:attribute元素上分别使用form属性来限定局部元素和局部属性。我们看例4-24。
例4-24 book7.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
要注意的是,在xs:schema元素上使用elementFormDefault和attibuteFormDefault属性,影响的是整个模式文档中的局部元素和局部属性,而在xs:element和xs:attribute元素上使用form属性,影响的是当前的局部元素和局部属性。
4.5.6.3 未声明的目标名称空间
对于很多不使用名称空间的XML文档,你需要使用没有声明目标名称空间的模式文档。我们看例4-25。
例4-25 book8.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:token"/>
</xs:complexType>
</xs:schema>
在这个模式文档中我们没有声明目标名称空间,因此定义的bookType类型和声明的book元素都是没有名称空间限定的。在引用类型或元素时,不需要添加任何的名称空间前缀。在本例中,声明book元素时,type属性直接引用了bookType类型。与之相对的是,例4-25的模式文档中使用的所有XML Schema元素和类型都是通过与XML Schema名称空间相关联的名称空间前缀“xs”来明确进行限定的。
一个符合模式(例4-25)的实例文档如例4-26所示。
例4-26 book5.xml
<?xml version="1.0" encoding="GB2312"?>
<book isbn="978-7-121-06812-6">
<title>《Struts 2深入详解》</title>
<author>孙鑫</author>
</book>
要注意的是,在没有声明目标名称空间的模式文档中,强烈建议对所有的XML Schema元素和类型使用一个和XML Schema名称空间相关联的名称空间前缀(如xs或xsd)来明确实施限定。如果你对XML Schema的元素和类型使用了默认名称空间,那么对XML Schema类型的引用也许不能和对用户自定义类型的引用相区分,从而导致模式文档出现错误。例4-27错误的使用了默认名称空间,使得对自定义类型的引用和对XML Schema类型的引用不能区分。
例4-27 book9.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="book" type="bookType"/>
<complexType name="bookType">
<sequence>
<element name="title" type="string"/>
<element name="author" type="string"/>
</sequence>
<attribute name="isbn" type="token"/>
</complexType>
</schema>
在XMLSpy中验证这个模式文档时,将提示如下的错误信息:
'bookType' must refer to an existing simple or complex type.
这是因为模式验证器认为对bookType类型的引用(没有前缀的引用),引用的是默认名称空间(即http://www.w3.org/2001/XMLSchema名称空间)中的类型,而XML Schema名称空间中并没有bookType这种类型,因此就报出了错误。
XML Schema提供了两个在实例文档中使用的特殊属性,用于指出模式文档的位置。这两个属性是:xsi:schemaLocation和xsi:noNamespaceSchemaLocation,前者用于声明了目标名称空间的模式文档,后者用于没有目标名称空间的模式文档,它们通常在实例文档中使用。
xsi:schemaLocation属性的值由一个URI引用对组成,两个URI之间以空白符分隔。第一个URI是名称空间的名字,第二个URI给出模式文档的位置,模式处理器将从这个位置读取模式文档,该模式文档的目标名称空间必须与第一个URI相匹配。我们看例4-28。
例4-28 book6.xml
<?xml version="1.0" encoding="GB2312"?>
<book xmlns="http://www.ruanchen.com/"http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance" ②
② 声明XML Schema实例名称空间(http://www.w3.org/2001/XMLSchema-instance),并将xsi前缀与该名称空间绑定,这样模式处理器就可以识别xsi:schemaLocation属性。XML Schema实例名称空间的前缀通常使用xsi。
③ 使用xsi:schemaLocation属性指定名称空间http://www.ruanchen.com/"font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和模式位置http://www.ruanchen.com/"font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">相关。要注意,在这个例子中,book.xsd中声明的目标名称空间要求是http://www.ruanchen.com/"font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。
一个可能的模式文档book.xsd如例4-29所示。
例4-29 book.xsd
实际上,xsi:schemaLocation属性的值也可以由多个URI引用对组成,每个URI引用对之间使用空白符分隔。例4-30的实例文档使用了多个名称空间,xsi:schemaLocation属性的值包含了两对URI。
例4-30 books.xml
<?xml version="1.0" encoding="GB2312"?>
此外,要注意的是,XML Schema推荐标准并没有要求模式处理器必须要使用xsi:schemaLocation属性,某些模式处理器可以通过其他的方式来得到模式文档的位置,而忽略xsi:schemaLocation属性。
4.5.7.2 xsi:noNamespaceSchemaLocation属性
xsi:noNamespaceSchemaLocation属性用于引用没有目标名称空间的模式文档。与xsi:schemaLocation属性不同的是,xsi:noNamespaceSchemaLocation属性的值是单一的值,只是用于指定模式文档的位置。例4-31显示了在实例文档中xsi:noNamespaceSchema Location属性的使用。
例4-31 book7.xml
<?xml version="1.0" encoding="GB2312"?>
<book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="book.xsd"
isbn="978-7-121-06812-6" >
<title>《Struts 2深入详解》</title>
<author>孙鑫</author>
</book>
与xsi:schemaLocation属性一样,xsi:noNamespaceSchemaLocation属性也可以在实例中的任何元素上使用,而不一定是根元素,不过,xsi:noNamespaceSchemaLocation属性必须出现在它要验证的任何元素和属性之前。
此外,要注意的是,XML Schema推荐标准并没有要求模式处理器必须要使用xsi:noNamespaceSchemaLocation属性,某些模式处理器可以通过其他的方式来得到模式文档的位置,而忽略xsi:noNamespaceSchemaLocation属性。
在XML文档中提供附加信息的通常方式是使用注释,即在“<!--”和“-->”之间给出注释信息。在XML Schema中,注释仍然可以使用,不过为了方便其他读者和应用程序来理解模式文档,XML Schema提供了三个元素来为模式提供注解。这三个元素是:xs:annotation、xs:documentation和xs:appinfo,其中xs:documentation和xs:appinfo是作为xs:annotation元素的子元素使用的。xs:documentation元素用于放置适合人阅读的信息,而xs:appinfo元素则用于为工具、样式表和其他应用程序提供信息。
我们看例4-32。
例4-32 hr.xsd
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:documentation xml:lang="zh">
这是一份用于企业雇员信息描述的模式文档
</xs:documentation>
</xs:annotation>
<xs:element name="hr">
<xs:annotation>
<xs:documentation xml:lang="zh">
hr元素是文档的根元素,使用匿名类型定义来声明
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:annotation>
<xs:documentation xml:lang="zh">
根元素hr下可以有多个employee子元素
</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="employee" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
xs:annotation元素常常在元素声明或类型定义的开头使用,用于对元素的作用、类型的定义提供附加的描述信息。为了说明这些描述信息所使用的语言,可以在xs:documentation元素上使用xml:lang属性来指定语言,xml:lang属性的值是在IETF RFC 3066(Tags for the Identification of Languages)或它的后继版本中定义的语言标识符。
xs:appinfo元素用于为计算机自动处理提供信息,它没有且也不需要xml:lang属性。xs:annotation元素和xs:appinfo元素还有一个可选的source属性,它的值是一个URI引用,指向一个包含了描述信息的文档位置。
4.6 在XMLSpy中创建模式文档
要在XMLSpy中创建一个模式文档,可以单击菜单【File】→【New…】,在弹出的“Create new document”对话框中选择“xsd W
图4-2 在XMLSpy中创建模式文档
XMLSpy创建的模式文档如图4-3所示。
图4-3 XMLSpy创建的模式文档
单击主窗口下方的“Text”标签,可以进入文本编辑窗口。
要为现有的XML文档关联一个模式文档,除了手写xsi:schemaLocation属性或xsi:noNamespaceSchemaLocation属性外,在XMLSpy中还可以通过菜单操作来为一个XML文档关联模式文档。在XML文档编辑窗口中,单击菜单【DTD/Schema】→【Assign Schema...】,出现“选择文件”对话框,如图4-4所示。
图4-4 “选择文件”对话框
单击“Browse…”按钮,选择要关联的模式文档。选定模式文档后,单击“OK”按钮,XMLSpy会自动为你在XML文档中添加xsi:schemaLocation属性或xsi:noNamespace SchemaLocation属性信息。
在关联模式文档后,要使用关联的模式文档对XML文档进行验证,可以在XML文档编辑窗口中单击菜单【XML】→【Validate XML】,或者按下功能键F8进行验证(参见2.4节)。
4.7 模式文档的验证
模式文档主要用于验证XML文档(实例文档)的有效性,不过,在XML Schema推荐标准中,也定义了对模式文档本身进行验证的验证规则。要对模式文档进行验证,可以用XMLSpy打开模式文档,然后单击菜单【XML】→【Validate XML】,或者按下功能键F8对模式文档进行验证。
4.8 小结
本章的目的是为了帮助读者快速建立起对模式文档结构的一个整体印象,在本章中介绍过的某些内容,后面还会有专门的章节进行深入而详细的讲解。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.ruanchen.com/"http://www.ruanchen.com/" style="color: #000">http://www.ruanchen.com/ook"
elementFormDefault="qualified">
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
评论 (0) All