1. 文档类型定义(DTD)
XML需要有一个文档来定义标记的含义、元素相关的属性等,这样解析器能检查输入的数据是否正确,我们称其为文档类型定义(Document Type Definition),简称DTD。
2.
如何生成一个DTD文档,请看如下示例:
<?xml version=”1.0” encoding=”GB2312” ?>
<!DOCTYPE home [
<!ELEMENT home (person+, pet*)>
<!ELEMENT person EMPTY>
<!ELEMENT pet EMPTY>
<!ATTLIST person
name CDATA #REQUIRED
sex (male|female) #REQUIRED
age CDATA #REQUIRED
hobby CDATA #IMPLIED
>
<!ATTLIST pet
name CDATA #REQUIRED
mount CDATA #REQUIRED
instruction CDATA #IMPLIED
>
]>
<home>
<person name=”ZhangSan” sex=”male” age=”25” />
<person name=”LiSi” sex=”male” age=”26” hobby=”music” />
<pet name=”cat” mount=”1” />
</home>
几点解释:
· 该文档从第二行开始文档类型声明,包含了文档元素 home的名称
· “+”表示一个home包含一个或一个以上的person
· “*”表示一个 home 包含零个或多个 pet
· “#REQUIRED”表示与其对应的属性是必须的
· “#IMPLIED”表示与其对应的属性可有可没有。
如果采用外部DTD的话,就有两个文档,一个是关于DTD的,另一个就是遵守DTD规定的XML内容文档。实际上,可以建立多个遵守此DTD的XML内容文档。把DTD文档和XML内容文档分开,示例如下:
DTD文档Home.dtd
<?xml version=”1.0” encoding=”GB2312” ?>
<!DOCTYPE home [
<!ELEMENT home (person+, pet*)>
<!ELEMENT person EMPTY>
<!ELEMENT pet EMPTY>
<!ATTLIST person
name CDATA #REQUIRED
sex (male|female) #REQUIRED
age CDATA #REQUIRED
hobby CDATA #IMPLIED
>
<!ATTLIST pet
name CDATA #REQUIRED
mount CDATA #REQUIRED
instruction CDATA #IMPLIED
>
]>
遵守DTD格式的内容文档 Home.xml
<?xml version=”1.0” encoding=”GB2312” ?>
<!DOCTYPE home SYSTEM “home.dtd”>
<home>
<person name=”ZhangSan” sex=”male” age=”25” />
<person name=”LiSi” sex=”male” age=”26” hobby=”music” />
<pet name=”cat” mount=”1” />
</home>
3. DTD语法
DTD文档是由元素组成的,而元素可能会包含属性,所以定义DTD文档的关键是如何定义它的元素和属性。
以下是定义属性的语法:
<!ATTLIST ElementName
AttributeName Type Default
AttributeName Type Default
…
>
几点解释:
· ATTLIST 是XML语法关键字
· ElementName表示元素名称,类似于变量
· 一个元素的属性由三部分组成:AttributeName 属性名称、Type属性类型、Default表明属性的特点
XML中定义的属性的类型如下:
类型 |
含义 |
CDATA |
表明属性只能包含字符数据,如 “123” “ZhangSan”。 |
ID |
表明属性的取值必须唯一。 |
IDREF, IDREFES |
指向文档中其它地方声明的ID值。 |
ENTITY, ENTITIES |
ENTITY 的值必须对应一个在DTD文档内声明但还没有分析过的实体,ENTITIES类似,它可以包括多个实体,用空格分隔。 |
NMTOKE, NMTOKENS |
NMTOKE是CDATA的子集,所使用的字符必须是字母、数字、句点、破折号、下划线或冒号;NMTOKENS类型,可以包含多个值,用空格分隔。 |
NOTATION |
NOTATION的值必须引用已在DTD文档其它地方声明过的某注解的名称。 |
NOTATION(enumerated) |
属性的值必须匹配NOTATION名称列表中的某个名称。 |
Enumerated |
我们定义好一些值,属性的值必须所列出的这些值。 |
Default的定义有以下四种形式:
类型 |
含义 |
#REQUIRED |
表明属性的值是非空的 |
#IMPLIED |
表明属性在元素中可有可无 |
#FIXED value |
表明属性的值必须是指定的值 |
Default value |
为属性提供一个默认值 |
如下示例说明IDREF/IDREFES的用法:
<!ATTLIST tree (node+)
<!ELEMENT node EMPTY>
<!ATTLIST node
id ID #REQUIRED
parentId IDREF #IMPLIED
value CDATA #REQUIRED
>
>
parentId的类型为IDREF,表明该属性的值必须在XML文档中出现过。
下面的文档是不合法的:
<tree>
<node id=”1” value=”x”/>
<node id=”2” value=”y”/>
<node id=”3” value=”z”/>
<node id=”4” value=”w” parentId=”5”/>
</tree>
因为parentId的值为5,而这个值并没有在文档中出现过。
定义元素的语法如下:
<!ELEMENT name CONTENT>
ELEMENT 是XML的关键字,CONTENT表示元素的类型,它指定了元素起始和结束标记之间允许包含的东西。CONTENT有以下几种形式:
类型 |
含义 |
EMPTY |
表明该元素不能包含任何子元素或文本。 |
ANY |
表明该元素可以包含任何在DTD中定义的元素内容。 |
#PCDATA |
表明该元素可以包含任何字符数据,但不能包含任何子元素。 |
其它 |
通常是其它元素的集合。 |
一个元素如何由其它元素集合而成呢?XML定义了如下的符号:
符号 |
描述 |
示例 |
() |
用来给元素分组 |
(IBM|Microsoft), HP, Honywell |
| |
在列出的对象中选一个 |
(男|女) |
+ |
该对象至少出现一次 |
(成员+) |
* |
该对象可出现任意次(含零次) |
(成员*) |
? |
该对象可以出现,但只能出现一次 |
(姓名?) |
, |
表明对象必须按指定的顺序出现 |
(北京,天津,上海) |
4. 命名空间
当我们建立XML应用的时候,会为具体的行业应用创建特定的DTD,规定可用的元素,有时候会出现两个同名的元素在不同的地方有不同的含义,这就需要指定命名空间来避免冲突。在XML中,采用全球唯一的域名作为“Namespace”,即用URL作为Namespace。先来看一个例子:
<?xml version="1.0" encoding="GB2312" ?>
<c:customer xmlns:c="http://www.customer.com/">
<c:name>ZhangSan</c:name>
<c:phone>09098768</c:phone>
<c:host xmlns:e="http://www.employee.com/">
<e:name>LiSi</e:name>
<e:phone>89675412</e:phone>
</c:host>
</c:customer>
在这个例子里定义了两个命名空间, 即c:和e:。在定义元素时,前面都加了特定的前缀,这样就能区别哪一个是客户的姓名、电话,哪一个是职工的姓名、电话了。
命名空间的定义语法如下:
xmlns:[prefix]=”[URI of namespace]”
其中,xmlns:是必须的,它是XML的关键字;prefix是命名空间的别名。如例所示:
<?xml version="1.0" encoding="GB2312"?>
<book xmlns:lib="http://www.library.com/">
<lib:title>The C++ Standard Library</lib:title>
<lib:author>Nicolai M.Josutis</lib:author>
</book>
命名空间也可以在父元素中指明,这样可以避免在每个子元素中都去指定命名空间:
<?xml version="1.0" encoding="GB2312"?>
<book xmlns="http://www.library.com/">
<title>The C++ Standard Library</title>
<author>Nicolai M.Josutis</author>
</book>
如果父元素中指定了命名空间,而子元素希望用自己的命名空间:
<?xml version="1.0" encoding="GB2312"?>
<customer xmlns="http://www.customer.com/"
xmlns:e="http://www.employee.com/">
<name>ZhangSan</name>
<phone>09098768</phone>
<host>
<e:name>LiSi</e:name>
<e:phone>89675412</e:phone>
</host>
</customer>