|
简单明快的 XSD 的入门笔记,希望能让你和我一样,用半天时间步入第一道门槛。 这一篇记录基础知识,第二篇会是些进阶知识和总结,然后你就可以写出自己的第一个 XSD 文档,并用来验证一个 XML 文档了。 XSD 是什么 ? 一个 xml schema 是用来描述 xml 文档结构的,而 XSD 是 xml schema definition , 是继 DTD 后的基于 xml 的 schema 语言,比起 DTD ,它有更好的扩展性,增加了功能,更重要的是,它本身就是以 xml 来写的,而不需要象 DTD 那样重新学一门语言。同时也可以利用所有对 xml 有效的便利。 那么为什么要有 schema 呢, xml 的 well-formed 是不足够的,一个语法上合法的 xml 仍然可能有错误,而这些错误可能导致严重的应用后果。
基础概念 第一印象
以下是一份 xml 文档 <?xml version="1.0"?> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note>
而它对应的一份 xsd 会是这样的:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3schools.com" xmlns="http://www.w3schools.com" elementFormDefault="qualified"> <xs:element name="note"> <xs:complexType> <xs:sequence> <xs:element name="to" type="xs:string"/> <xs:element name="from" type="xs:string"/> <xs:element name="heading" type="xs:string"/> <xs:element name="body" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
简单元素: 简单元素是不包含其他元素和属性的元素。 定义简单元素的语法为: <xs:element name="xxx" type="yyy"/> 常用的内建类型有: xs:string xs:decimal xs:integer xs:boolean xs:date xs:time 可以通过 default 属性和 fixed 属性来修饰。 <xs:element name="color" type="xs:string" default="red"/> <xs:element name="color" type="xs:string" fixed="red"/>
属性: 只有复合元素可以有属性,但属性本身总是被定义为简单类型的。 <xs:attribute name="xxx" type="yyy"/> 除了和简单元素的定义一样可以用 default 和 fixed 来作为属性之外,还可以用 use 属性,如果把 use 属性指定为“ required ”,就说明这个属性在 xml 文档中是必须指明的,默认情况下属性的使用是可选的。
限制 当一个元素或者属性定义了类型( type ), 就可以用 restriction 来限制这个类型, restriction 又叫 facet ,可以为类型增添更多的细节要求。当 xml 文档中对应的元素值违反了这个 restriction 就不能通过检验。限制是 XSD 里比较常用的内容,我们会看大量的例子。
对数值大小的限制:(只能取 0 到 120 的闭区间) <xs:element name="age"> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:minInclusive value="0"/> <xs:maxInclusive value="120"/> </xs:restriction> </xs:simpleType> </xs:element>
将值限制在一组既定值内:(类似于枚举 enumeration ) <xs:element name="car"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="Audi"/> <xs:enumeration value="Golf"/> <xs:enumeration value="BMW"/> </xs:restriction> </xs:simpleType> </xs:element>
限制一定范围的值:(只能取小写的 26 个字母) <xs:element name="letter"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="[a-z]"/> </xs:restriction> </xs:simpleType> </xs:element>
(只能取长度为 3 的大写字母组合) <xs:element name="initials"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="[A-Z][A-Z][A-Z]"/> </xs:restriction> </xs:simpleType> </xs:element>
(只能取长度为 3 的字母,大小写均可) <xs:element name="initials"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="[a-zA-Z][a-zA-Z][a-zA-Z]"/> </xs:restriction> </xs:simpleType> </xs:element>
(只能取 xyz 中的一个) <xs:element name="choice"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="[xyz]"/> </xs:restriction> </xs:simpleType> </xs:element>
(只能取长度为 5 的数字串) <xs:element name="prodid"> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:pattern value="[0-9][0-9][0-9][0-9][0-9]"/> </xs:restriction> </xs:simpleType> </xs:element>
(只能取任意长度的小写字符串,长度可以为 0 ) <xs:element name="letter"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="([a-z])*"/> </xs:restriction> </xs:simpleType> </xs:element>
(有了上一个,你自然也会猜到这一个:只能取长度大于 0 的字符串) <xs:element name="letter"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="([a-z][A-Z])+"/> </xs:restriction> </xs:simpleType> </xs:element>
(选取,其实和前面的枚举式功效类似,只能取其一) <xs:element name="gender"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="male|female"/> </xs:restriction> </xs:simpleType> </xs:element>
(特定长度的字符数字串,用作密码最合适。) <xs:element name="password"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="[a-zA-Z0-9]{8}"/> </xs:restriction> </xs:simpleType> </xs:element>
(如果不需要在 base 上加内容限制,也可以这样来表达长度) <xs:element name="password"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:length value="8"/> </xs:restriction> </xs:simpleType> </xs:element> (设定长度区间) <xs:element name="password"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:minLength value="5"/> <xs:maxLength value="8"/> </xs:restriction> </xs:simpleType> </xs:element>
另外,在 xml 里,空白符的情况比较特别,不小心处理就得不到你要的真正效果。
(保留所有的空白符) <xs:element name="address"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:whiteSpace value="preserve"/> </xs:restriction> </xs:simpleType> </xs:element>
( 所有的回车,过行,制表符,长空白都被替换成相应长度的空格符 ) <xs:element name="address"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:whiteSpace value="replace"/> </xs:restriction> </xs:simpleType> </xs:element> (所有空白符都被变为单空格符,首尾空白都被去掉) <xs:element name="address"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:whiteSpace value="collapse"/> </xs:restriction> </xs:simpleType> </xs:element>
最后,上面说到的所有的限制,还可以以下面这种格式来写,把 simpleType 加上名字,在元素中的 type 引用这个名字,好处就是它不再单独属于这个元素或者属性的定义了,其他元素可以复用这个类型限制,类似于面向对象编程语言中的包装与复用。 <xs:element name="car" type="carType"/> <xs:simpleType name="carType"> <xs:restriction base="xs:string"> <xs:enumeration value="Audi"/> <xs:enumeration value="Golf"/> <xs:enumeration value="BMW"/> </xs:restriction> </xs:simpleType>
复合元素 复合元素的定义就和简单元素的刚好相反了,就是包含其他元素或属性的元素。 细分一下有四种: 空元素; <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> 而这四个同时又都可以有属性。
接下来我们一一详细介绍。 <product prodid="1345" /> 空元素的定义语法: <xs:element name="product"> <xs:complexType> <xs:attribute name="prodid" type="xs:positiveInteger"/> </xs:complexType> </xs:element>
<person> <firstname>John</firstname> <lastname>Smith</lastname> </person> 包含其他元素的复合元素定义: <xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> 用 xs:sequence 来定义这些元素必须按照这个次序出现,类似于 sequence 这样的指示符还有几个,稍后统一介绍。
定义一个只有文本内容和属性的复合元素,我们需要用一个 simpleContent 标记,再用一个 restriction 或者 extension 来限制文本的内容 :
<xs:element name="somename"> <xs:complexType> <xs:simpleContent> <xs:extension base="basetype"> .... .... </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> 或: <xs:element name="somename"> <xs:complexType> <xs:simpleContent> <xs:restriction base="basetype"> .... .... </xs:restriction> </xs:simpleContent> </xs:complexType> </xs:element> 例子: <xs:element name="shoesize"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:integer"> <xs:attribute name="country" type="xs:string" /> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> 注意:extension 的 integer 是限制 shoesize 的文本内容,而 attribute 的 string 是限制 attribute 本身的内容的。 对应这个复合模式的 xml 可以是: <shoesize country="france">35</shoesize>
要描述混合的复合元素: <letter> Dear Mr.<name>John Smith</name>. Your order <orderid>1032</orderid> will be shipped on <shipdate>2001-07-13</shipdate>. </letter> 就可以用: <xs:element name="letter"> <xs:complexType mixed="true"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="orderid" type="xs:positiveInteger"/> <xs:element name="shipdate" type="xs:date"/> </xs:sequence> </xs:complexType> </xs:element> 只是在包含其他元素的同时指定 mixed 等于“ true “,而 sequence 或其他指示符的使用依然有效。你的文本可以穿插于元素之间,但元素的出现次序仍受 sequence 的限制。
记得简单元素里的复用吗,这里同样可以,在 complexType 标记里加上 name 属性,就完成了分离和复用了,对上面所有的复合类型都是通用的。即使写 xsd ,也要象 oop 语言那样,通过复用来提高修改的效率,同时让页面看起来整洁清晰,至少,我是有着这样的偏执的,呵呵。
指示符里有以下几种: 顺序指示符: All 所有元素可以不分顺序出现,但只能出现一次。 Choice 只有其中一个可以出现 Sequence 前面说过了,必须按顺序出现。 上面的限制可以配合次数指示符加以进一步的限制: maxOccurs 最多出现次数 minOccurs 最少出现次数 例如: <xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="full_name" type="xs:string"/> <xs:element name="child_name" type="xs:string" maxOccurs="10" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element> 注意:用了 all 的时候,最大次数还是不能超过 1 ,最小可以是 0 或 1 。
组指示符: Group 元素组 attributeGroup 属性组 通过例子来看看: <xs:group name="persongroup"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> <xs:element name="birthday" type="xs:date"/> </xs:sequence> </xs:group> 定义了一组元素, group 必须包含已经用顺序指示符包含起来的元素。 定义后,别的地方可以用 ref 来引用: <xs:complexType name="personinfo"> <xs:sequence> <xs:group ref="persongroup"/> <xs:element name="country" type="xs:string"/> </xs:sequence> </xs:complexType>
以下这两个是对应的 attribute group 的用法: <xs:attributeGroup name="personattrgroup"> <xs:attribute name="firstname" type="xs:string"/> <xs:attribute name="lastname" type="xs:string"/> <xs:attribute name="birthday" type="xs:date"/> </xs:attributeGroup>
<xs:element name="person"> <xs:complexType> <xs:attributeGroup ref="personattrgroup"/> </xs:complexType> </xs:element>
这一篇到这里为止。 |