DTD & XSD

 

前面提到过的,DTDDocument Type Definition,文档类型定义)就是定义XML文档中元素的结构和内容等。其实DTD就相当于XML中的“词汇”和“语法”,不同的行业可以定义自己的“词汇”和“语法”,以利于解析器验证XML文档的有效性,并且这样也利于行业中和行业之间的交流。就相当于只有当两个人对各自说出的词汇都理解对方的时候才能有顺利的交流。这其实就是对XML文档使用元素的定义的以层抽象,把它的定义独立出一个文件,以利于对信息的隐藏和扩展。这也可以把它想象成程序语言,比如C#中的接口的定义。把DTD文件想象成一个接口,而引用这个DTD文件的XML文档是这个接口的实现类,只要了解了这个DTD文件,就大致知道了和这个DTD文件相链接的XML文档的一些框架信息。

DTD文件也可以看成是一系列XML文档的模板,它定义了相关XML文档的元素,属性,排列方式(元素,属性等),元素的内容类型,以及元素的层次结构等。

 

DTD中元素的声明

<!ELEMENT 元素名(元素描述)>

这里主要介绍元素描述,元素的描述包含两部分:

1.       如果元素是简单元素,即该元素不包含子元素,则描述部分是针对该元素的内容的限制或是规定。这种限制的描述可以是:

#PCDATA:元素的内容只能是可解析的文本数据。

<!ELEMENT 元素名 (#PCDATA)>

EMPTY:元素内容必须为空,但可以包含属性。

<ELEMENT 元素名 EMPTY>

2.       如果元素是复杂元素,即该元素包含子元素,则元素描述包含对子元素名的列表(可用正则表达式表达)。元素描述的括号表示内容描述的组合。

<!ELEMENT book(title, author+, summary | content)>

正则表达式用法:

( )     给元素分组                                (A | B | C), (D | E), F

|              在列出的对象中选择一个           (A | B)

*      对象允许出现0到多次              (A*)

+      对象应出现1到多次                  (A+)

?      对象可以出现01        (A?)

,              对象以指定顺序出现                  (A, B, C)

 

同时,如果不能确定一个元素是否含有子元素或是只能包含文本,那么可以将元素定义为混合类型的。简单的混合类型可以是:

<!ELEMENT 元素名 ANY>

表明元素可以定义为以上的任意一种类型。

典型的,可以将元素的定义通过“,”和“|”组合起来。如:

<!ELEMENT 元素名(#PCDATA | EMPTY | (A*, B?, C+ | D))>

 

DTD中属性的声明

<!ATTLIST 元素名 属性名称 属性类型 属性特点 … >

DTD中,元素中的属性是单独定义的,这里主要介绍属性的类型和属性特点。

属性类型:

1. CDATA       表示属性的值只能是可解析的文本数据。

<!ATTLIST 元素名 属性名 CDATA #REQUIRED>

2. 枚举值      表示属性取值是在()中定义的值

<!ATTLIST 元素名 性别 ( | ) #REQUIRED>

3. ID              表示该属性的取值必须是唯一的,可以用来作为该元素的唯一标识符。并且该值(标识符)必须以字母开头。

<!ATTLIST A ID ID # REQUIRED>

则下列定义是合法的:

<A ID=”a001”>content A</A>

下列定义是不合法的:

<A ID=”001”>content A</A>

4. IDREF/IDREFS 表示属性值指向文档中其他声明的ID类型值。

<!ATTLIST people perID ID #REQUIRED

                          parentID IDREFS #IMPLIED>

则有如下的XML文件定义:

<people perID=”p1” />

<people perID=”p2” />

<perple perID=”p3” parentID=”p1 p2” />

IDREFS中的不同的ID的定义,在XML文件中要空格空开。

5. ENTITY/ENTITIES 表示该属性的值为一个或多个已定义的实体定义,多个实体之间用空格空开。

<!ATTLIST 元素名 属性名 ENTITY #IMPLIED>

6. NMTOKEN/NMTOKENS 表示属性的值只能由字母、数字、下滑下、句点、冒号、连接符(-)这些符号或多个这些符号构成,多个符号之间用空格空开。

<!ATT:LIST 元素名 属性名 NMTOKENS #REQUIRED>

7. NOTATION 表示该属性的取值为<!NOTATION…>中定义的符号。

属性特点:

#REQUIRED 表明该属性在XML文件中必须定义。

#IMPLIED            表明该属性在XML文件中可有可无。

#FIXED value 表明该属性的值是固定的。其值就是value中定义的值。

Default Value   为该属性定义一个默认值。

 

DTD中内部实体的声明

实体的声明格式:

<!ENTITY entity-name “entity-content”>

对实体的引用通过实体名来实现。

实体相当于“宏”,比如C语言中的#define,它用于将一段文本或是数字用一个名字来命名,并在以后引用到该名字的时候默认用那段定义的文本或是数字来替换。对有些太长的文本,可以减少工作量,而对于给一些数字定义名字,可以改善程序的可读性,不至于看到的就是一些赤裸裸的,没有一点意义的数字。这样也相应的提高了维护性,因为一个值的改变只需要改变一处就可以了,而不用在用到这个字符的地方都去改动。

XML中预定义了一些实体,如在“XML 概述”中提到过的特殊字符,以及可以通过#Unicode码或是十六进制数据来定义一个字符。

实体的使用:

&实体名;    (注意是&+实体名+;)

注:实体能用于另外一个实体的定义中,但不能位于元素声明中。

内部实体无需先定义后引用,因而需要避免引用循环。

 

DTD中外部实体的声明

<!ENTITY entity-name SYSTEM/PUBLIC “external entity URI”>

 

DTD中参数实体

内部参数实体声明:

<!ENTITY %entity-name “entity-content”>

外部参数实体:

<!ENTITY %entity-name “URI”>

参数实体的引用:

%实体名;

参数实体类似于实体,它也是用一个名字去替换这个名字已定义的内容;不同于一般的实体,它只能在外部DTD文档中定义和使用,并且它也只能在DTD文档中使用。(言外之意就是一般实体是可以在XML文件中使用的)并且它需要先定义后使用,同时它也可以应用于元素的定义。

如在DTD文档中的定义以及使用:

<!ENTITY % common.attributes
    'id        ID    #IMPLIED
     account   CDATA #REQUIRED'
> 
<!ATTLIST manufacturer %common.attributes;>

 

DTDNotation的定义

Notation定义了一些不是XML类型的数据的文档。我还不是很了解它的具体用处,关于它的介绍很少,即使是在W3C中的文档。

其定义有两种格式:

<!NOTATION name “external_ID”>

<!NOTATION name “public_ID” “URL”>

如:

<!NOTATION GIF system "image/gif">

<!NOTATION GIF public
  "-//IETF/NOSGML Media Type image/gif//EN"
  "http://www.isi.edu/in-notes/iana/assignments/media-types/image/gif">

注:参考http://webdesign.about.com/od/dtds/a/aa101700b.htm

 

DTD文档在XML文件中的引用

XML文件中,DTD文件分为两种:内部DTD和外部DTD。这两种只是DTD文档定义的位置不一样,DTD文档里的内容是一致的。内部DTDDTD文档的定义放到XML文件中;而外部DTDDTD文档独立出一个文件,通过在XML文件中声明DTD文档的位置来获取相应的DTD文件。

 

内部DTDXML文件中的声明

<!DOCTYPE 根元素名[

       DTD文档内容

]>

 

外部DTDXML文件中的声明

<!DOCTYPE 根元素名 SYSTEM/PUBLIC “外部DTD文件名及其外置”>

 

DTD的缺陷与XSD的出现

DTD在一定的阶段推动了XML的发展,但是它本身存在着一些缺陷:

1.       它没有使用XML格式,而是自己定义了一套格式,相对解析器的重用性较差;而且DTD的构建和访问没有标准的编程接口,因而解析器很难简单的解析DTD文档。

2.       DTD对元素的类型限制较少;同时其他的约束力也叫弱。

3.       DTD扩展能力较差。

4.       基于正则表达式的DTD文档的描述能力有限。

针对这些原因,W3C2001年推出了XML Schema标准(XSD)。XSD具有前面介绍的DTD的所有优势和功能。它也用于定义XML文档的结构和内容,同时它还可以定义元素的数据类型。更重要的是:

1.       它本身就是XML文档结构,因而解析器可以很好的解析XSD文档。

2.       它没有自己的一套语法,学习起来相对简单。

3.       它支持一系列的数据类型以及自定义的数据类型,因而具有更强的约束能力。

4.       它具有很好的扩展能力,并且支持命名空间以及属性组等。

个人认为XSD优于DTD的最主要的一点就是XSD使用的是XML语法,因而可以很方便的解析XSD文档,而要解析DTD文档则需要复杂的编程模型,而且效率比较差。

 

XSD文档结构

<?xml version=”1.0”?>

<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>

….

XSD文档定义内容

….

</xsd:schema>

如以下XSD文档的定义:

<?xml version=”1.0”?>

<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>

       <xsd:element name=”products” type=”productsType”>

              <xsd:complexType name=”productsType”>

                     <xsd:sequence>

                     <xsd:element name=”product” type=”productType” />

                     </xsd:sequence>

              </xsd:complexType>

              <xsd:complexType name=”productType”>

                     <xsd:sequenct>

                            <xsd:element name=”productName” type=”xsd:string” />

                            <xsd:element name=”description” type=”xsd:string” />

                            <xsd:element name=”price” type=”xsd:double” />

<xsd:element name=”quantity” type=”xsd:nonNegativeIntergater” />

                     </xsd:sequence>

              </xsd:complexType>

       </xsd:element>

</xsd:schema>

 

XML中对XSD文档的引用

<?xml version=”1.0”?>

<products xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance

       xsi:noNamespaceSchemaLocation=”products.xsd”>

       ….

       ….

</products>

 

XSD数据类型

原始(Primitive)数据类型:

string            字符串

boolean          布尔值

decimal          十进制,用于准确的定义一个值

float               单精度浮点类型

double           双精度浮点类型

timeDuration   持续时间

dateTime       特定时刻时间

time               每天重复的特定时刻时间

date               日期

anyURI          用于定位文件的URI

recurringDuration          重复持续出现的时间间隔

 

派生(Derived)数据类型(由Primitive数据类型或是Derived数据类型导出的数据类型)

integer                         十进制的一个整数序列(由decimal导出)

long                             -2^632^63-1的数

nonNegativeInteger        大于或等于0的整数(由integer导出)

positiveInteger                     大于0的整数(由nonNegativeInteger导出)

int                                -2^312^31-1的数

time                             每天特定时间重复出现的一个实例(由recurringDuration导出)

date                             从午夜到第二天午夜的一个时间段(由timeDuration导出)

 

用户自定义简单数据类型

有些数据仅仅用上述的几种内置的简单数据类型无法完整的表达,比如对电话号码0571-88909090这样的表达,如果只是用string来限制显然不够完整。而这可以通过simpleType元素来组合内置数据类型来实现用户自定义的数据类型,以增强数据类型的定义规则。在定义用户自己的数据类型时,还可以使用一些属性来是表达更加方便完整。

simpleType元素的属性:

enumeration                 在指定的数据值中选择,限制用户的选值

fractionDigits                限定最大的小数位数,用于控制精度

length                           限定数据长度

minLength                    指定最小长度

maxExclusive                指定数据的最大值(小于)

maxInclusive                指定数据的最大值(小于等于)

minExclusive                指定数据的最小值(大于)

minInclusive                 指定数据的最小值(小于等于)

pattern                         指定数据的显示规范

 

用户自定义数据类型的语法规则

<xsd:simpleType name=”自定义数据类型的名称”>

       <xsd:restriction base=”自定义数据类型所基于的数据类型名称”>

              内容模式的定义….

       </xsd:restriction>

</xsd:simpleType>

如上述电话号码的定义:

<xsd:simpleType name=”phoneType”>

       <xsd:restriction base=”xsd:string”>

              <xsd:length value=”13” />

              <xsd:pattern value=”\d{4}-\d{8}” />

       </xsd:restriction>

</xsd:simple>

如果是enumeration类型的,则可定义如下:

<xsd:simpleType name=”enumType”>

<xsd:restriction base=”xsd:string”>

       <xsd:enumeration value=”string1” />

       <xsd:enumeration value=”string2” />

       ….

</xsd:restriction>
</xsd:simpleType>

 

pattern属性值必须是一个正则表达式,用来定义一种匹配模式。正则表达式可以做为一个模板,将某个字符模式与搜索的字符串进行匹配。正则表达式常用的符号及其意义如下:

\             标记为一个特殊字符。

^             匹配字符串的开始位置

$            匹配字符串的结束位置

*            匹配0次或多次

+            匹配1次或多次

           匹配0次或一次

{n}         n是一个非负整数,表示匹配n

{n,}        n是一个非负整数,表示至少匹配n

{n,m}     表示至少匹配n次,至多匹配m

.             匹配出\n之外的任何单个字符

(pattern)  匹配pattern,并获取这一匹配

(?:pattern)匹配pattern,但不获取匹配结果

(?=pattern)正向预查

(?!pattern)负向预查

x|y        匹配xy

[xyz]       匹配xyz

[^xyz]     不匹配任何xyz

[a-z]              字符范围

[^a-z]      非字符范围

\b           匹配一个单词边界,也就是每个单词之间的空格位置。

\B           匹配非单词边界。

\cx          匹配由x指明的控制字符,如\cM匹配一个control-M或回车符。xA~Za~z

\d           匹配一个数字,即[0-9]

\D           匹配一个非字符,即[^0-9]

\f            匹配一个换页符,即\x0c

\n           匹配一个换行符,即\x0a

\r            匹配一个回车符,即\x0d

\s            匹配任何一个空白符,即[\f\n\r\t\v]

\S           匹配任何非空白字符,即[^\f\n\r\t\v]

\t            匹配一个制表符,即\x09

\v           匹配一个垂直制表符,即\x0b

\w          匹配任何包含下划线的单词字符

\W          匹配任何不包含下划线的单词字符

\xn          n为十六进制转义值

\num       num为正整数,对所获取的匹配的引用,如‘(.)\1表示任何两个连续相同字符

\n           标识一个八进制转义值等(也可以是一个向后引用)。

\un          n为四个十六进制表示的Unicode字符。

 

复杂数据类型的声明

复杂数据类型包含其他的元素、属性和混合内容等。其声明如下:

<xsd:complexType name=”复杂数据类型名”>

       内容模式定义….

</xsd:complexType>

如果元素内容既包含文本(简单数据类型?)也包含子元素,则因在定义complexType时把mixed属性设置为true。如:

<xsd:complexType name=”mixedType” mixed=”true”>

       <xsd:sequence>

              <xsd:element name=”firstName” type=”xsd:string” />

       </xsd:sequence>

</xsd:complexType>

则可以在XML文件中定义一下元素:

<contract>

My first name is

<firstName>John</firstName>

</contract>

 

XSD中元素声明

<xsd:element name=”元素名称” type=”数据类型” default=”默认值” minOccurs=”该元素最小出现的次数,默认为0” maxOccurs=”该元素的最多出现次数,默认为unbounded” />

其中minOccurs的值必须为nonNegativeInteger

maxOccurs的值必须为nonNegativeInteger | unbounded

Schema中,一个元素主要由元素名和元素类型决定,元素类型定义一个元素的合法内容。如果元素是简单类型的,则类型因为简单的元素类型;如果元素为复杂元素,则类型因为相应的复杂类型。

 

匿名类型

如果某个类型只被使用到了一次,我们就没有必要为他们定义一个名字,可以直接定义这个类型并使用。如:

<xsd:element name=”city”>

       <xsd:complexType>

              <xsd:element name=”name” type=”xsd:string” />

              <xsd:element name=”state” type=”xsd:string” />

       </xsd:complexType>

</xsd:element>

 

XSD中属性声明

<xsd:attribute name=”属性名” type=”属性类型” default=”默认值” fixed=”固定值” ref=”引用属性名” use=”optional | required | prohibited” />

属性的类型只能是简单类型。

ref为对同一个或其他XML文档中声明的自定义属性的引用。

属性定义的位置在complexType的末尾。

如:

<xsd:complexType name=”stdType”>

       <xsd:sequence>

              <xsd:element name=”name” type=”xsd:string” />

              <xsd:element name=”class” type=”xsd:string” />

       </xsd:sequence>

<xsd:attribute name=”age” type=”xsd:positiveInteger” use=”required” />

</xsd:complexType>

 

全局元素和全局属性

可以把元素和属性在单独的域中定义,然后通过ref属性来引用他们。

<xsd:element / xsd:attributer ref=”要引用的全局元素名/全局属性名” />

对全局元素和全局属性的定义有一些限制:

1.       全局元素/属性不能包含引用,即不能有ref属性。

2.       全局元素/属性也不能包含minOccursmaxOccursuse等属性。

3.       全局元素/属性必须包含typename属性。

如:

<xsd:element name=”Title” type=”xsd:string” />

<xsd:element name=”ID” type=”xsd:string” />

<xsd:element name=”books” type=”booksType” />

<xsd:complexType name=”booksType”>

       <xsd:element name=”book”>

              <xsd:sequence>

                     <xsd:element ref=”Title” />

              </xsd:sequence>

              <xsd:attribute ref=”ID” />

       </xsd:element>

</xsd:complexType>

 

XSD中的元素组

sequence元素:定义组合的元素必须按照定义的顺序显示。

<xsd:sequence>

要组合顺序显示的声明

</xsd:sequence>

 

group元素:使用通用名将一组元素组合在一起。

<xsd:group name=”组名” maxOccurs=”nonNegativeInteger | unbounded” minOccurs=”nonNegativeInteger” ref=”组名”>

       要组合的元素声明…..

</xsd:group>

例如:

<xsd:element name=”Title” type=”xsd:string” />

<xsd:element name=”books” type=”booksType” />

<xsd:complexType name=”booksType”>

       <xsd:element name=”book”>

              <xsd:sequence>

                     <xsd:group ref=”bookInfo” />

              </xsd:sequence>

              <xsd:attribute ref=”ID” />

       </xsd:element>

</xsd:complexType>

<xsd:group name=”bookInfo”>

       <xsd:sequence>

              <xsd:element name=”Title” type=”xsd:string” />

              <xsd:element name=”Author” type=”xsd:string” />

       </xsd:sequence>

</xsd:group>

 

choice元素:允许指定多组中的一个,用于互斥情况。

<xsd:choice id=”ID” maxOccurs=”nonNegativeInteger | unbounded” minOccurs=”nonNegativeInteger”>

       要组合的元素声明…..

</xsd:choice>

 

all元素:允许元素按任意顺序显示。注:all元素必须放在sequencegroupchoice等元素之前声明。

<xsd:all maxOccurs=”nonNegativeInteger | unbounded” minOccurs=”0 | 1”>

       要组合的元素声明…..

</xsd:all>

 

XSD中的属性组

XSD元素组中的group元素,在XSD属性中也有group元素的定义,用来声明一组属性,并可以通过ref属性来引用这组属性。

<xsd:attributeGroup name=”group-name”>

       属性1声明

       属性2声明

       …..

</xsd:attributeGroup>

引用语法:

<xsd:attributeGroup ref=”group-name” />

 

外部导入另一个XSD文档

可以通过include或是import元素导入外部的XSD定义:

<include id=”ID” schemaLocation=”filename” />

<import id=”ID” namespace=”namespace” schemaLocation=”filename” />

这两个元素都具有id属性,它只是作为一个标识符,它是唯一的,也是可选的。

schemaLocation是要导入的XSD文档的名称。Namespace是指被引入XSD文件所属的命名空间。

 

 

参考:

http://www.w3schools.com/XML

XML完全开发指南》 科学出版社 孙更新 裴红义 杨金龙 编著

http://en.wikipedia.org/wiki/XML

进来休假,稍微看了一下XML的内容,不知道这种东东放在首页是否合适。

如果有很多人都认为不合适的话,就把这些弄到其他地方去好了。

posted @ 2008-12-29 01:04  江湖飘  阅读(2421)  评论(3编辑  收藏  举报