立体的萌 | 作者
Java技术迷 | 出品
前言
XML Schema与DTD一样,都是用来定义XML文档结构的,不过与DTD不同的是,XML Schema相对复杂一些,使用更加的灵活,可读性好,可扩展性强,功能也更加强大!
XML Schema可以视为是DTD的替代品,其中很重要的一点就在于XML Schema支持数据结构,并且允许开发者自己定义数据结构,这让我想起我在学习J2SE的时候,既可以实用性现成的8种基本类型,也可以自己写一个引用类;
就如同我们学习J2SE时大部分都是在跟类库打交道,使用XML Schema很大程度上也是在跟它所支持的数据类型打交道
XML Schema好在哪里?
XML Schema有着比DTD更强大的语义约束,换成人话就是不仅可以规范XML文档的结构,还可以规范其中的内容,比如说要把某个XML元素的内容只能是日期型数据,DTD就做不到,这时候就需要XML Schema出马,如果把两者的功能比喻成两个集合,那么DTD包含于XML Schema,因为XML Schema本身就是XML文档;
关于XML Schema的优点的官方解释:
其实内置类型也分两种,一个是基础类型,一个是派生类型,基础类型就是原本已经存在的数据类型,而派生类型则是在其他数据类型的基础上定义的,而派生又分为两种:限制和扩展,通过限制派生的新类型的值范围包含于原类型值范围,而通过扩展则可以为现有的类型添加新的元素和属性,扩展类型才是开发者从无到有创建的;
先说点题外话-模式
英文里很多单词一样的单词区分首字符的大小写,例如:polish是指甲油,而Polish是波兰,march是行军,March是三月,may时刻可能,May是五月……Schema特指W3C XML Schema规范制定的模式,而schema则泛指包括DTD在内的所有的模式;
说到XML怎么就扯到模式上了呢?依然用表格来呈现
talk is cheap.show me your code
模式文档(使用XSDL编写XML文档)以schema元素作为根元素,通常以.xsd结尾
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root" type="xs:string"
</xs:schema>
现在servlet已经把DTD替换成XML Schema了(从servlet2.4开始);
<!--servlet2.5规范的XML格式,引用XML Schema作为语义约束-->
<?xml version="1.0" encoding="UTF=8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
废话不多说了,开始吧
放两个解析器的网址:第一个是Apache XML计划的Xersec-j:http://xml.apache.org 第二个是Oracle的XML Parser for java v2:http://tachnet.oracle.com/tech/xml/ 因为XML Schema操作的是信息集合定义的抽象数据类型,而不是文档中的实例把要使用的解析器下载好,磨刀不误砍柴工;
XML 根元素
XML Schema是完全遵守XML规则的,根元素是<schema.../>,只是个最简单的例子
<?xml version="1.0" encoding="UTF-8"?>
<!--xmlns[:xxx]用于为XML文档引入语义约束,-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...
<xs:schema>
XML Schema组件
这是对组成模式的抽象据类型的文档快的通俗说法
主要组件
第一个,元素和属性的声明
元素的声明用element
<!--元素和属性从来都是用的声明,
代码就是这样写,
只是名字是我瞎写的,
后面定义了类型,
元素的内容就成了“YYYY-MM-DD”格式了-->
<xsd:element name="dataRequest" type="data"/>
元素的声明用人话来讲就是把元素的内容与格式关联起来的过程;
属性的声明用attribute;
<xsd:attribute name="datarequest" type="boolean"/>
<xsd:attribute···/>
第二个,简单类型和复杂类型的定义
简单类型
所谓简单类型就是XML Schema中的原子信息,具有简单类型的元素是不能包含子元素的,也不能拥有属性,只能包含字符数据;
注:图片里有的字打错了,结果改也不好改了,说明一下内建就是内置,一个意思,以下不再使用内建,全部使用内置,名表内建和内置就是一个意思就好;
内置简单类型
XML Schema里主要定义了三类简单类型:原子数据类型、列表数据类型、联合数据类型;
原子数据类型
<myElement>inalienable </myElement>
再增加一个属性,
<myElement attribute="simppleType"/>
列表数据类型
首先,生成列表
<listFromOneToTenType> 2 3 5 6 7 4</listFromOneToTenType>
然后再通过这样来生成
<xsd simpleType name="listFromOneToTenType">
<xsd:list itemType="onetoTen">
</xsd:simpleType>
联合数据类型
还是刚才那个例子
<xsd:simpleType name="NumberUnion">
<xsd:number bookTypes="booksnumber oneToTen"/>
<xsd:simpleType>
以上都是XML Schema的内置类型以及内置类型的派生,就好比我们学完了指数函数、对数函数、幂函数以及三角函数之后有学习这几个初等函数的杂交,也就是基本初等函数,如果XML Schema对于数据结构的支持到此为止那可能只是优秀,还达不到卓越,真正强大之处在于开发者可以自己创建简单类型;
自定义简单类型
首先,先来了解一下face(面),XML Schema规范一共有12个面,面的作用在于对简单类型的值进行约束;
代码示例
<!--限制简单类型,假设有age和maleage两个元素-->
<xs:element name="age" type=“ageType”/>
<xs:simpleType name="ageType">
<!--使用base属性来指定要限制的基类型-->
<xs:restriction base ="xs:integer">
<xs:maxInclusive value="60"/>
<xs:minInclusive value="18"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="maleAge" type="maleAgeType"/>
<xs:simpleType name="maleAgetype">
<xs:restriction>
<!--使用匿名简单类型作为要限制的基类型-->
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="18"/>
</xs:restriction>
<xs;simpletype>
<!--使用xs:maxInclusive面对匿名简单类型的最大取值进行限制-->
<xs:maxExclusive value="55"/>
<xs:restriction>
<xs;simpleType>
派生列表数据类型
XML Schema允许任何类型派生出对应的列表类型,而且这种列表类型不仅可以用于指定属性类型,还可以用于指定元素的类型
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/schema"
elementFormDefault="quelified"
attributeFormDafault="unquelified">
<!--定义一个age_list_type列表类型-->
<xs:simpleType name="age_list_type">
<xs:list>
<!--通过simpleType子元素指定列表元素的类型-->
<xs:simpleType>
<!--以int类型为基类型-->
<xs:restriction base="xs:int">
<!--规定最大值和最小值-->
<xs:maxExclusive value="100"/>
<xs:minExliusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:list>
</xs:simpleType>
<!--定义一个age_list_type类型的元素-->
<xs:element name="age-list" type="age_list_type"/>
</xs:schema>
派生联合数据类型
任意数量的原子类型或者是列表类型都可以联合成联合类型
<?xml version="1.0 encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<!--定义一个price_type类型-->
<xs:simpleType name="price_type">
<!--以decimal为基础-->
<xs:restriction base="xs:decimal">
<!--定义最大值和最小值-->
<xs:maxExclusive value="100"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
<!--定义一个publish_date_type类型-->
<xs:simpleType name="publish_date_type">
<!--以date为基础-->
<xs:restriction base="xs:date">
<!--定义最大值和最小值-->
<xs:maxExclusive value="2021-06-16"/>
<xs:minExclusive value="1997-05-27"/>
</xs:restriction>
</xs:simpleType>
<!--定义price_publish_type类型-->
<xs:simpleType name="price_publish_type">
<!--把以上两个类型联合成新类型-->
<xs:union memberTypes="price_type publish_date_type"/>
</xs:simpleType>
<xs:element name="price_name" type="price_publish_type"/>
</xs:schema>
还没完,水稻都能杂交,技术为何不以?以上都是原子操作,或者是原子操作的叠加,真正的强大之处在于杂交:XML Schema允许<list.../>元素由已有的联合类型派生出对应的对应的列表类型,也允许<union.../>元素把一个或多个列表类型联合成联合类型,这种的讲起来很繁琐,还不如直接上代码,毕竟单纯地说教比实实在在的代码要好很多,我喜欢“talk is cheap,show me your code”,能用代码说明白的就尽量不用文字;
<?xml version ="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<!--从int类型派生的ageType-->
<xs:simpleType name="ageType">
<xs:restriction: base="xs;decimal">
<xs:maxExclusive value="100"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
<!--从string类型派生的nameType-->
<xs:simpleType name="nameType">
<xs:restriction base="xs:string">
<xs:maxLength value=="20"/>
<xs:minLength value="4">
</xs:restriction>
</xs:simpleType>
<!--以ageType和nameType联合成联合类型-->
<xs:simpleType name="ageType_nameType">
<xs:union memberTypes="ageType nameType"/>
</xs:simpleType>
<!--由ageType派生出的对应的列表类型-->
<xs:simpleType name="ageListType">
<xs:list itemType="ageType"/>
</xs:simpleType>
<!--由nameType派生出对应的列表类型-->
<xs:simpleType name="nameListType">
<xs:list itemType="nameType"/>
</xs:simpleType>
<!--将两个列表类型联合一个联合类型-->
<xs:simpleType name="ageList_nameList_Type">
<!--两个成员类型都是列表类型-->
<xs:union memberTypes="ageListType nameListType"/>
</xs:simpleType>
<!--把两个联合类型联合成一个新的联合类型-->
<xs:simpleType name="further_mix_Type">
<!--两个成员类型都是联合类型-->
<xs:union memberTypes="ageType_nameType ageList_nameList_Type"/>
</xs:simpleType>
<!--把一个联合类型和一个列表类型联合成一个新的联合类型-->
<xs:simpleType name="further_mix_Type">
<!--一个成员是列表类型,一个成员是联合类型-->
<xs:union memberTypes="nameListType ageList_nameList_Type"/>
</xs:simpleType>
<!--由ageType和nameType派生出对应的列表类型-->
<xs:simpleType name="ageList_nameList_List_Type">
<!--列表元素是联合类型-->
<xs:List itemType="ageType_nameType"/>
</xs:simpleType>
<xs:simpleType name="further_Type">
<!--成员类型是其列表元素是混合类型的列表类型-->
<xs:union memberTypes="ageList_nameList_List_Type"/>
</xs:simpleType>
</xs:schema>
复杂类型
复杂类型可以有子元素和属性,复杂类型还可以生成元素内容模型,复杂类型可以有简单内容,也可以有复杂内容,这里的复杂内容指的是他的开始标签和结束标签之间的字符数据和子元素,简单内容指的是他的开始标签和结束标签之间的字符数据,也就是说简单内容和复杂内容之间差别就在于有没有子元素,简单内容用xs:simpleContent元素来定义,复杂内容用xs:complexContent元素来定义;
<xs:element name="book" type="bookType"/>
<xs:complexType name="booktype">
<xs:simpleContent>
<xs:extension base="xs;string">
<xs:attribute name="isbn" type="token"/>
<xs:extension>
<xs:simpleContent>
<xs:complxType>
anyType
anyType就如同java里的Object一样,由他可以派生出所有的简单类型和复杂类型,用起来相当自由,因为anyType类型对其所包含的内容没有任何限制和约束,下面定义一个anyType类型的元素
<xs:element name="employee" type="xs:anyType"/>
然后,我们就可以为所欲为了:
<!--元素内容为字符数据-->
<employee>lmc</employee>
<!--元素可以有任意属性-->
<employee number="001">lmc</employee>
<!--元素可以有子元素-->
<employee>
<number>001</number>
<name>lmc</name>
</employee>
<!--元素内容可以包含混合内容,也就是既可以是子元素又可以是字符数据-->
<employee>
<number>001</number>
lmc
</employee>
anyType是默认类型,所以对employee元素的声明还可以这样写
<xs:element name="employee"/>
纯元素内容
纯元素内容的意思是元素内容中是没有字符数据的,只包含子元素,用于构建纯元素内容的内容模型一共有三种:sequence(序列)、choice(选择)、all(全部);
Sequence(序列)
Sequence组中的所有的子元素必须按照指定的顺序出现,使用xs:sequence来进行定义;
<?xml version ="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="employeetype"/>
<xs:complexType name="employeeType">
<!--使用xs:complexContent元素来定义复杂内容-->
<xs:complexContent>
<!--从xs:anyType类型限制派生,
复杂内容的限制派生使用的基类型是xs:anyType类型,或者他的派生类型-->
<xs:restriction base="xs:anyType">
<!--使用sequence组,
在xs:sequence元素内部子元素声明的顺序,也就是实例文档中子元素出现的顺序-->
<xs:sequence>
<!--声明name元素-->
<xs:element name="name" type="xs:token"/>
<!--声明age元素-->
<xs:element name="age">
<xs:simpleType>
<xs:restriction base="xs:positiveInteger">
<!--定义最大值和最小值-->
<xs:maxInclusive value="18"/>
<xs:minInclusive value="70"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<!--声明gender元素-->
<xs:element name="gender">
<xs:simpleType>
<xs:restriction base ="token">
<!--定义性别-->
<xs:enumeration value="male"/>
<xs:enumeration value="female"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:schema>
choice(选择)
choice组中的所有的子元素可以选择使用任意一个,注意必须只能是一个;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs;element name="employee" type="employeeType"/>
<xs:complexType name="employeeType">
<xs:choice>
<xs:element name="telephone">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:pattern value="\d{3,4}-\d{6,8}"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="mobile">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:pattern value="\d{11}"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:schema>
all(全部)
all在这里表示任意次序,all组中的所有的子元素都可以按照任意的顺序出现,注意,all组是不能和另外两个组一起使用的,而且必须出现在内容模型的顶部;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="employeeType"/>
<xs:complexType name="employeeType">
<xs:all>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:token"/>
</xs:all>
</xs:complexType>
</xs:schema>
元素的出现指示符
出现指示符一共有两个属性:指定元素可以出现最大次数的maxoccurs、指定元素出现最小次数的minOccurs,minOccurs必须小于等于maxOccurs,并且两者的默认值都是1,也就是不使用这两个属性的话,声明元素只能出现一次;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="employeeType"/>
<xs:complexType name="employeeType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
<xs:choice>
<xs:element name="telephone" type="xs:token"/>
<xs:element name="mobile" type="xs:token"/>
</xs:choice>
<xs:sequence>
<xs:element name="interest" type="xs:token"
minxOccurs="0" maxOccurs="unbounded"/>
<xs:element name="skill" type="xs:token"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:sequence>
</xs:schema>
元素的默认值和固定值
默认值属性是:defauled;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="document">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:token"/>
<!--定义了PDF格式-->
<xs:element name="format" type="xs:token" default="PDF"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
固定值是:fixed
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="document">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:token"/>
<xs:element name="format" type="xs:token" fixed="PDF"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
空元素
没有内容只有属性
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="student">
<xs:complexType>
<xs:complexContent>
<xs:restriction base="xs:anyType">
<xs:attribute name="number" type="xs:token"/>
<xs:attribute name="name" type="xs:token"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:schema>
混合内容
既包含子元素又包含元素数据的元素
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="employeeType"/>
<!--定义具有混合内容的类型-->
<xs:complexType name="employeeType" mixed="true">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
元素组
元素组用xs:group来定义
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="company" type="companyType"/>
<!--定义元素组-->
<xs:group name="employeeGroup">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:group>
属性组
用attributeGroup元素来进行定义
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="order" type="orderType"/>
<!--定义属性组-->
<xs:attributeGroup name="attributeGroup">
<xs:attributeGroup name="number"
type="xs:token"
use="required"/>
<xs:attributeGroup name="totalprice"
type="xs;decimal"
use="required"/>
</xs:attributeGroup>
元素通配符
在模式文档中,xs:any元素是可以作为占位符来使用的,他的属性:控制元素出现最少次数的minOccurs、控制元素出现最多次数的maxOccurs;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:any processContents="skip"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
属性通配符
属性包括指定替换元素所属的命名称空间namespace和指示模式处理器对替换元素的认证的processContents;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:token"/>
</xs:sequence>
<xs:anyattribute processContents="skip"
namesoace="##local"/>
</xs:complexType>
</xs:element>
总结
数据类型的确太重要了,在java里可以合理分配内存,提高内存的利用率,在XML里,直接让XML Schema打败了DTD,正所谓“我消灭你,与你无关”!
本文作者:立体的萌 为Java技术迷专栏作者 投稿,未经允许请勿转载。
点击下方公众号
回复关键字【电子书】领取资料