当你使用Web Service、SOAP 传递或接受数据进行通讯时,
当你使用Spring、Struts、Maven 等当今流行框架及工具进行搭建配置时,
当你开发中需要解析Html、xls、PDF、Access 等文件时,
你会发现Xml将是这些领域中一项不可或缺的技术。可是你真正的研究过其中的奥秘么?如果一直以来只是一知半解的话,那么接下来就跟我一起扫扫盲吧。
<?xml version="1.0" encoding="UTF-8"?> <itnan xmlns="http://www.it-nan.com/schema/libs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.it-nan.com/schema/libs ../xsd/libs.xsd" > <info>IT男's blog</info> <url>http://www.it-nan.com</url></itnan>
上面这行代码是一个简单的xml格式文档。下面我们来逐一了解其中的含义:
第一行:xml标签,指明这是一个xml文档;version是版本号(指明xml的版本);encoding是编码规则(指明当前文档采用的编码格式 )。
第二行:xmlns是默认命名空间,声明url为“http://www.it-nan.com/schema/libs”的是默认的命名空间(如果后面有:xxx 则表明是定义为xxx的命名空间,如:xmlns:xsi);itnan是默认命名空间中定义的根节点标签(如果前面有类似于xxx: 的前缀,则表明该标签是从xxx命名空间中定义的标签,如:xsi:schemaLocation)。
第三行:这行是声明url为“http://www.w3.org/2001/XMLSchema-instance”的命名空间,由前缀xsi代表。“http://www.w3.org/2001/XMLSchema-instance”这个地址为xml的基础空间,所有的基础属性的定义都来自于这里,如:下面用到的schemaLocation属性,xsi是开发人员约定的一个名字,不是固定的,可以随意定义。
第四行:这行是用于指定命名空间与定义标签结构的XSD(XML Schema Definition)文件的对应关系。schemaLocation属性的值由多个URI引用对组成,两个URI之间以空白符分隔。第奇数个URI是命名空间的名字,第偶数个URI给出模式文档的位置(可以是url地址,也可以是相对路径),编辑器将从这个位置读取XSD文件,并与他的命名空间匹配来限制该空间下的标签结构。
第五、六行:这个是在定义itnan下的标签,而这个标签的结构是根据默认命名空间下的xsd文件定义出来的。下面就让我们看看xsd文件是如何定义的。
<?xml version="1.0" encoding="UTF-8"?><schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.it-nan.com/schema/libs" elementFormDefault="qualified"> <element name="itnan"> <complexType> <sequence> <element name="info" type="string"/> <element name="url" type="string"/> </sequence> </complexType> </element></schema>
上面这行代码是一个简单的xsd文档。下面我们来逐一了解其中的含义:
第一行:由于xsd文档也是符合xml规范的,所以也要在第一行声明这是一个xml文档;version是版本号(指明xml的版本);encoding是编码规则(指明当前文档采用的编码格式 )。
第二行:xmlns也同上面xml文档的一样表示默认的命名空间;而“http://www.w3.org/2001/XMLSchema”这个地址为xsd的基础命名空间,所有的基础属性的定义都来自于这里,如:下面用到的targetNamespace、elementFormDefault、element等。
第三行:由于这个xml文档里的“http://www.w3.org/2001/XMLSchema”为默认命名空间,而targetNamespace就是这个命名空间所定义的属性,所以targetNamespace属性不用加前缀修饰。这个属性是用于定义下面所规定的标签结构服务于哪个命名空间,所以这个值是与引用这个xsd文件的xml文档中声明的schemaLocation属性的命名空间必须要一致。(而这里表示下面的这些定义都是用于“http://www.it-nan.com/schema/libs”命名空间下的标签)
第四行:elementFormDefault有两个值“qualified”和“unqualified”。“qualified”表示:下面定义的所用标签都为targetNamespace设置的命名空间服务,而“unqualified”表示:除了全局元素或者类型将归于目标命名空间外,局部元素将归于无名命空间。(这个属性大部分都设置为“qualified”)
第五行之后:这些就都是xsd用来定义xml文档标签结构的代码,下面统一介绍。
如何写一个最简单的XML Schema文档呢?
首先,我们写出一个最简单的XML文档。
hello.xml:
<?xml version="1.0"?><greeting>Hello World!!</greeting><!--一个根元素:greeting;且这个元素不含属性,无子元素,内容是字符串。-->
hello.xsd:
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="greeting" type="xsd:string"/></xsd:schema>
XML Schema文档后缀名是.xsd,完全符合XML语法,根元素是schema,命名空间xmlns:xsd=”http://www.w3.org/2001/XMLSchema,用元素定义实例文档中的元素,如greeting。
假设实例文档是如下的:
customer.xml:
<customer> <name>teiki</name> <address>No.237, Road Waitan, Shanghai</address></customer>
则可以写出以下的XML Schema文档:
customer.xsd:
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="customer"> <xsd:complexType> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="address" type="xsd:string" /> </xsd:sequence> </xsd:complexType> </xsd:element></xsd:schema>
实例文档customer.xml中,元素含有两个子元素,所以我们在Schema文档中采用ComplexType来定义该元素。sequence表示子元素依次出现的顺序。
这次我们给出一个更加复杂一些的文档:
customer.xml:
<customer> <name>Teiki</name> <address> <!-- address追加一个地址子元素 --> <prefecture>Zhejiang</prefecture> <city>Hangzhou</city> <street>Xilu Road, No.121, 7F</street> </address></customer>
为此,我们需要一个更加复杂一点的Schema文档:
address.xsd:
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="customer"> <xsd:complexType> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <!-- 追加子元素address--> <xsd:element name="address"> <xsd:complexType> <xsd:sequence> <xsd:element name="prefecture" type="xsd:string"/> <xsd:element name="city" type="xsd:string" /> <xsd:element name="street" type="xsd:string" /> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element></xsd:schema>
不过,我们还可以采用ref元素来重新编写这个Schema文档:
address2.xsd:
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="customer"> <xsd:complexType> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element ref="address"/> </xsd:sequence> </xsd:complexType></xsd:element><xsd:element name="address"> <xsd:complexType> <xsd:sequence> <xsd:element name="prefecture" type="xsd:string"/> <xsd:element name="city" type="xsd:string" /> <xsd:element name="street" type="xsd:string" /> </xsd:sequence> </xsd:complexType></xsd:element></xsd:schema>
使用ref元素可以直接将其指向另一个模块,使文档更加具有可读性。
先看这个简单的订购数据实例文档:
order.xml:
<order><orderItem>Accounting Book</orderItem><orderItem>Taxation Book</orderItem></order>
假设元素,即每次的订购书目不能超过10种,那该怎么写这个Schema文档呢?这里要用到的maxOccurs属性。
order.xsd:
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="order"> <xsd:complexType> <xsd:sequence> <xsd:element name="orderItem" type="xsd:string" maxOccurs="10" /> </xsd:sequence> </xsd:complexType></xsd:element></xsd:schema>
第7行中的maxOccurs属性为10,代表orderItem元素可以最大有10个。如果,不设定元素个数,则可以用maxOccurs=”unbounded”来定义。
类似,如果要定义最小值,可以使用minOccurs,比如下面这句:
<xsd:element name="orderItem" type="xsd:string" minOccurs="5" maxOccurs="10"/>
这两个属性缺省值都是1。
假如上面的订书数据中,可以用书名或者书号任一一种订购,则实例文档可能如下:
order2.xml:
<order> <orderItem> <!--书名订购--> <name>Accounting Book</name> </orderItem> <orderItem> <!--书号订购--> <id>7-5058-3496-7</id> </orderItem></order>
这时书写Schema文档还需要使用choice元素。
order2.xsd:
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="order"> <xsd:complexType> <xsd:sequence> <xsd:element ref="orderItem" maxOccurs="10" /> </xsd:sequence> </xsd:complexType></xsd:element><xsd:element name="orderItem"> <xsd:complexType> <xsd:choice> <xsd:element name="name" type="xsd:string"/> <xsd:element name="id" type="xsd:string"/> </xsd:choice> </xsd:complexType></xsd:element></xsd:schema>
稍微更复杂的可选项子元素
再稍微修改一下订书数据的实例文档:
order3.xml:
<order> <orderItem> <name>Accounting Book</name> <quantity>2</quantity> </orderItem> <orderItem> <id>7-5058-3496-7</id> </orderItem></order>
这里假定值为1时,缺省。
如何修改Schema文档呢?
order3.xsd:
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="order"> <xsd:complexType> <xsd:sequence> <xsd:element ref="orderItem" maxOccurs="10"/> </xsd:sequence> </xsd:complexType></xsd:element><xsd:element name="orderItem"> <xsd:complexType> <xsd:sequence> <xsd:choice> <xsd:element name="name" type="xsd:string"/> <xsd:element name="id" type="xsd:string"/> </xsd:choice> <xsd:element name="quantity" type="xsd:string" minOccurs="0"/> </xsd:sequence> </xsd:complexType></xsd:element></xsd:schema>
文档中的quantity最少出现值为0,也就是可以有,也可以没有。
当然,也可以直接在元素中,包含quantity,然后定义它的minOccurs。
具有简单类型的元素只能包含字符数据,不能包含子元素,也不能有属性。XML Schema推荐标准内置了44种简单类型,如例中的xs:string、xs:integer等,这些简单类型可以直接引用。XML Schema内置的数据类型的层次结构如下图所示。
xsd-simpleType
XML Schema支持类型的派生,这和面向对象语言中对象的继承有些类似,但又不完全相同。XML Schema类型的派生分为限制(restriction)和扩展(extension),通过限制派生的新类型的值范围是原类型值范围的子集,通过扩展则可以为现有类型添加新的元素和属性。
对于简单类型,只有限制派生而没有扩展派生,我们只能通过限制一个现有的简单类型(内置的简单类型或派生于内置简单类型的简单类型)来派生一个新的简单类型。那如何对现有的简单类型进行限制呢?XML Schema给我们提供了12个面(facet),用于指定一个值的有效范围、约束值的长度和精度、枚举一系列的有效值,或者指定有效值必须匹配的正则表达式。
面与类型的关系就好像棱镜的面与棱镜的关系,透过不同的面,你看到的景观(内容)是不同的。在XML Schema中,面相当于是对一个现有的简单类型添加某些约束(限制),约束不同,得到的结果就不同。也就是说,你可以把面(facet)看成是对数据类型的约束,目的是为了让它的值限制在一定的范围内。实际上,这些面就是http://www.w3.org/2001/XMLSchema名称空间中的一些元素,只不过这些元素是用来对现有类型的值进行约束的,因而称为面。
要定义新的简单类型,使用xs:simpleType元素,要对现有的基类型进行限制,使用xs:restriction元素,并在该元素的内部使用限制值范围的面(facet)。例如,我们定义一个雇员年龄的类型,雇员年龄要求在18~60岁之间,我们可以从内置的xs:integer类型派生一个新的简单类型ageType,然后使用xs:minInclusive和xs:maxInclusive面来限制年龄值的范围。
例如这个实力文档:
<xs:simpleType name="ageType"> <xs:restriction base="xs:integer"> <xs:minInclusive value="18"/> <xs:maxInclusive value="60"/> </xs:restriction></xs:simpleType>
如果内置简单类型的44种还不能满足要求,怎么办呢?下面学习自定义简单类型。(XML的扩展性充分体现在这里)
例如这个实例文档:
order4.xml:
<order> <orderItem> <id>7-5058-3496-7</id> <quantity>5</quantity> </orderItem></order>
ID是一个标准的ISBN编码,我们怎么定义这个ISBN编码呢?
<xsd:simpleType name="idType"> <xsd:restriction base="xsd:string"> <xsd:pattern value="\d{1}-\d{4}-\d{4}-\d{1}"/> </xsd:restriction></xsd:simpleType>
idType是一个自定义的简单类型。
我们对它做了限制:
<xsd:restriction base=”xsd:string”>代表它是基于一个字符串类型。再用pattern元素来描述该字符串的形式。
value=”\d{1}-\d{4}-\d{4}-\d{1}”这是一个正则表达式,关于正则表达式,以后再介绍。嘻嘻!
利用这个自定义的简单类型,我们可以重新写Schema文档:
order4.xsd:
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="order"> <xsd:complexType> <xsd:sequence> <xsd:element ref="orderItem" maxOccurs="10"/> </xsd:sequence> </xsd:complexType></xsd:element><xsd:element name="orderItem"> <xsd:complexType> <xsd:sequence> <xsd:element name="id" type="idType"/> <xsd:element name="quantity" type="xsd:integer"/> </xsd:sequence> </xsd:complexType></xsd:element><xsd:simpleType name="idType"> <xsd:restriction base="xsd:string"> <xsd:pattern value="\d{1}-\d{4}-\d{4}-\d{1}"/> </xsd:restriction></xsd:simpleType></xsd:schema>
假如我们事先确定好ID只有3个,即只有3个ISBN是可选的,那怎么办?我们可以用enumeration元素来进行列举。
<xsd:simpleType name="idType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="7-5058-3496-7"/> <xsd:enumeration value="7-5005-6450-3"/> <xsd:enumeration value="7-3020-6069-7"/> </xsd:restriction></xsd:simpleType>
再来看订购量quantity的值,如果我们设定其值必须在1-10之间,该怎么办呢?可以这些自定义一个简单类型。
<xsd:simpleType name="quantityType"> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="1"/> <xsd:maxInclusive value="10"/> </xsd:restriction></xsd:simpleType>
其中,minInclusive,maxInclusive分别代表该类型的取值范围。
所以最终修改后的Schema文档如下:
order4-1.xsd:
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="order"> <xsd:complexType> <xsd:sequence> <xsd:element ref="orderItem" maxOccurs="10"/> </xsd:sequence> </xsd:complexType></xsd:element><xsd:element name="orderItem"> <xsd:complexType> <xsd:sequence> <xsd:element name="id" type="idType"/> <xsd:element name="quantity" type="quantityType"/> </xsd:sequence> </xsd:complexType></xsd:element><xsd:simpleType name="idType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="7-5058-3496-7"/> <xsd:enumeration value="7-5005-6450-3"/> <xsd:enumeration value="7-3020-6069-7"/> </xsd:restriction></xsd:simpleType><xsd:simpleType name="quantityType"> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="1"/> <xsd:maxInclusive value="10"/> </xsd:restriction> </xsd:simpleType></xsd:schema>
最后,我们再来讲讲元素的属性如何在Schema文档中定义。
比如上面的order.xml实例文档中:
<order> <orderItem id="7-5058-3496-7" /></order>
对此,我们在Schema文档中采用一个attribute来定义:
order.xsd:
<xsd:element name="orderItem"> <xsd:complexType> <xsd:sequence> ←空元素 </xsd:sequence> <!--定义该元素属性--> <xsd:attribute name="id" type="xsd:string"/> </xsd:complexType></xsd:element>
那么,实例文档中该属性值是必须的还是可有可无的呢?我们可以这样限制:
<xsd:attribute name="id" type="idType" use="required"/>
这里我们讲id属性类型作为一种自定义数据类型idType。
而且,用attribute元素的use属性来定义是否是必须的属性。
required是必须值,optional是可选值,prohibited是无属性值。
那么对于属性的缺省值,我们怎么定义呢?
比如:
<order> <orderItem id="4-8443-1780-6" quantity="3"/></order>
我们还可以用attribute元素的另一个属性default来定义:
<xsd:attribute name="quantity" type="xsd:integer" default="1"/>
所以,我们可以重新写出一个Schema文档:
order2.xsd:
<xsd:element name="orderItem"> <xsd:complexType> <xsd:sequence></xsd:sequence> <xsd:attribute name="id" type="idType" use="required"/> <xsd:attribute name="quantity" type="xsd:integer" default="1"/> </xsd:complexType></xsd:element>
上面的属性我们定义我们还可以采用属性组的办法来重新改写Schema文档。
order3.xsd:
<xsd:element name="orderItem"> <xsd:complexType> <xsd:sequence></xsd:sequence> <xsd:attributeGroup ref="orderItemAttributes"/> </xsd:complexType></xsd:element><xsd:attributeGroup name="orderItemAttributes"> <xsd:attribute name="id" type="idType" use="required"/> <xsd:attribute name="quantity" type="xsd:integer" default="1"/></xsd:attributeGroup>
这个属性组就不详细解释了,不过,大家一看就清楚了吧。
<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="order"> <xsd:complexType> <xsd:sequence> <xsd:element ref="orderItem" maxOccurs="10"/> </xsd:sequence> </xsd:complexType></xsd:element><xsd:element name="orderItem"> <xsd:complexType> <xsd:sequence></xsd:sequence> <xsd:attributeGroup ref="orderItemAttributes"/> </xsd:complexType></xsd:element><xsd:attributeGroup name="orderItemAttributes"> <xsd:attribute name="id" type="idType" use="required"/> <xsd:attribute name="quantity" type="xsd:integer" default="1"/></xsd:attributeGroup><xsd:simpleType name="idType"> <xsd:restriction base="xsd:string"> <xsd:pattern value="\d{1}-\d{4}-\d{4}-\d{1}"/> </xsd:restriction></xsd:simpleType></xsd:schema>