640 likes | 1k Views
DTD 和 XML Schema. 第 3 章. DTD 和 XML Schema. 3.1 DTD 3.2 XML Schema 3.3 XML Schema 和 DTD 的区别. 3.1 DTD. 3.1.1 DTD 简介 3.1.2 DTD 的存在方式 3.1.3 XML 元素的声明 3.1.4 DTD 的属性声明 3.1.5 DTD 的实体声明与引用. 3.1.1 DTD 简介. Document Type Definition 文档类型定义 DTD 是一套关于关于标记的语法规则,详细地描述一组 XML 文档的结构。
E N D
DTD和XML Schema 第3章
DTD 和XML Schema • 3.1 DTD • 3.2 XML Schema • 3.3 XML Schema 和DTD的区别
3.1 DTD • 3.1.1 DTD简介 • 3.1.2 DTD的存在方式 • 3.1.3 XML元素的声明 • 3.1.4 DTD的属性声明 • 3.1.5 DTD的实体声明与引用
3.1.1 DTD简介 • Document Type Definition 文档类型定义 • DTD是一套关于关于标记的语法规则,详细地描述一组XML文档的结构。 • DTD文件严格地规定了将以它为标准的所有实例XML文档的树状层次结构的全部细节。 • 对XML文档的有效性验证是可选的 • 对文档有效性验证会降低系统的性能 • 使用DTD对XML文档进行有效性验证将限制其扩展性
3.1.2 DTD的存在方式 • DTD语句也称DTD声明,它使用一套与XML完全不同的语法规则进行编写。 • 内部DTD:存在于XML文档本体中元素、属性或实体的DTD声明 • 以”<! DOCTYPE”开始,以”]>”结束 • DOCTYPE是DTD的关键字,必须大写 • 外部DTD:对XML元素和属性等的声明包含在一个单独的DTD文件中。 • 方便共享 • SYSTEM引用:主要用于一个作者或组织所编写的众多XML文档中通用的DTD • PUBLIC引用:引用公开给公众使用的DTD • 内部DTD和外部DTD结合使用
3.1.3 XML元素的声明 • 示例 内部DTD <?xml version="1.0" standalone="yes"?> <!DOCTYPE REGARD [ <!ELEMENT REGARD (#PCDATA)> ]> <REGARD> HelloXML! </REGARD>
3.1.3 XML元素的声明 • 列出元素 • 要为一个文档创建适当的DTD,第一步是了解用DTD中定义的元素编码的信息结构。 • 所编写的DTD要为每个元素作元素声明。每一元素声明列出元素名和它的子元素。 • 清单:需要编写DTD结构完整的XML文档 3-1.doc • 表:学生成绩统计中的元素 表3-1.doc
3.1.3 XML元素的声明 • 在合法的XML文档中使用的每项标记都要在DTD中的元素声明中加以声明。一项元素声明指明了元素名称和元素可能的内容。 • 元素声明的基本语法: <!ELEMENT 元素名称 元素内容描述> • ELEMENT是DTD的关键字,必须大写 • 元素名:命名规则与标记的命名规则同 • 元素内容描述:规定该元素将包含哪些子元素及子元素之间的顺序,或者对于不包含子元素的元素定义其数据类型。
3.1.3 XML元素的声明 • 空元素类型 • ANY元素类型 • 父元素类型 • 只包含文本的元素类型
1、 空元素的声明 • 即没有内容的元素 • <!ELEMENT 元素名 EMPTY> • 例如:<!ELEMENT HR EMPTY> 这样,在XML文件中,就可以使用一个空元素<HR/>。
2、ANY元素类型 • 是XML为某些结构性比较差的元素提供的说明方法,它对该元素不作限制。 • 可以包含任何在该DTD中声明过的子元素 • 这些子元素的出现次数与次序不作限制 • 可以包含文本数据,即(#PCDATA)型数据 • 数据内容与子元素可以交错出现 • 语法: <!ELEMENT 元素名 ANY> • 例如:<!ELEMENT SEASON ANY> 关键词ANY(也要区分大小写)表明所有可能的元素以及可解析的字符数据都可以是SEASON元素的子元素。 • 对于根元素特别是未结构化的文档,使用ANY常见,但在其他大多数情况下,尽量避免使用。
4.只包含文本的元素类型 • 元素的内容完全是文本形式的元素类型 • 例如:<!ELEMENT YEAR (#PCDATA)> 该声明说明YEAR只能包含可析的字符数据,即非标记文本,但它不能包含自己的子元素。所以,下面这个YEAR元素是合法的: <YEAR>1998</YEAR>; 不合法: <YEAR> <MONTH>January</MONTH> <MONTH>February</MONTH> </YEAR>
3.父元素类型 • XML文档本身通过元素之间的嵌套关系描述了数据(元素)之间的树状结构关系。 • 子元素声明中包括: • 子元素名称 • 子元素出现的次数及次序 • 见下图:结构符合的具体描述 • 一个元素的各个子元素之间可以以任意顺序出现,也可以强制遵循一定的顺序。 • 不要求顺序的子元素
3.父元素类型 考虑下面的DTD定义: <!ELEMENT 联系人(姓名 EMAIL)> <!ELEMENT 姓名(#PCDATA)> <!ELEMENT EMAIL(#PCDATA)> 遵从这个DTD的XML文件可以为: 同样,下面这个XML文件也是有效的: <联系人> <EMAIL>zhang@aaa.com</EMAIL> <姓名>张三</姓名></联系人> 在DTD定义中仅仅用空白符分隔了元素“联系人”的两个子元素,这说明并没有严格要求两个元素出现的顺序,因此上面两种写法都是允许的。 <联系人> <姓名>张三</姓名> <EMAIL>zhang@aaa.com</EMAIL> </联系人>
3.父元素类型 • 要求顺序的子元素 • 在上面例子中,如果我们使用逗号“,”来分隔两个子元素,那么XML文件中,元素“姓名”就必须出现在元素“EMAIL”前面。也就是说,如果我们把DTD定义为下面的形式: • <!ELEMENT 联系人(姓名, EMAIL)> <!ELEMENT 姓名(#PCDATA)> <!ELEMENT EMAIL(#PCDATA)>
3.父元素类型 那么下面的文件是有效的: <联系人><姓名>张三</姓名><EMAIL>zhang@aaa.com</EMAIL> </联系人> 而下面这个文件不是有效的,因为它把元素“EMAIL”放在了元素“姓名”之前,这是不合规定的: <联系人> <EMAIL>zhang@aaa.com</EMAIL> <姓名>张三</姓名></联系人>
3.父元素类型 • 重复元素 <!ELEMENT 联系人(姓名,EMAIL+)> <!ELEMENT 姓名(#PCDATA)> <!ELEMENT EMAIL(#PCDATA)> 它说明一个“联系人”元素中必须含有一个“姓 名”元素,后面接一个或多个“EMAIL”元素。 <联系人> <姓名>张三</姓名></联系人> 这个片段不是有效的,因为它没有“EMAIL”元素,而“+”代表了“一个或多个”。如果你需要表示“零个或多个”,那么应该使用字符“*”。 这样,下面的这段XML文件是“有效的”。 <联系人> <姓名>张三</姓名> <EMAIL>zhang@aaa.com</EMAIL> <EMAIL>zhang@hotmail.com</EMAIL> <EMAIL>zhang@yahoo.com</EMAIL></联系人>
3.父元素类型 • 成组元素:子元素可以使用括号并为一组。 • 下面的DTD片段说明,一个“联系人”元素中可以有一个或多个“姓名/EMAIL”子元素对,并且在每个子元素对中,“姓名”都放在“EMAIL”之前。 <!ELEMENT 联系人(姓名,EMAIL)+> <!ELEMENT 姓名(#PCDATA)> <!ELEMENT EMAIL(#PCDATA)>
3.父元素类型 • 符合这个DTD的XML文件可以是: <联系人> <姓名>张三</姓名> <EMAIL>zhang@aaa.com</EMAIL> <姓名>李四</姓名> <EMAIL>li@bbb.org</EMAIL> <姓名>王五</姓名> <EMAIL>wang@ccc.org</EMAIL></联系人> • 注意,仅仅是因为“+”由括号里面移到括号外面,元素“联系人”的内容就大大不同了。
OR或 • 符号“|”描述了一个OR操作。 • 因此,下面的DTD片段所规定的XML元素是:所有的“联系人”元素应该有一个“姓名”子元素,同时,在此之后还应该有一个“电话”或一个“EMAIL”元素,但不能同时有“电话”和“EMAIL”两个元素。 <!ELEMENT 联系人(姓名,(电话|EMAIL))> <!ELEMENT 姓名(#PCDATA)> <!ELEMENT 电话(#PCDATA)> <!ELEMENT EMAIL(#PCDATA)>
OR或 <联系人> <姓名>张三</姓名> </联系人> 这个例子是一个“无效的”XML片段,因为DTD中规定或者有一个“电 话”元素,或者有一个“EMAIL”元素,但上面这个例子中两种元素都 没有。 <联系人> <姓名>张三</姓名> <电话>12345678</EMAIL> <EMAIL>zhang@yahoo.com</EMAIL></联系人> 同样,这个例子仍是一个“无效的”XML片段,因为它既有“电话”元素,又有“EMAIL”元素。
OR或 一个符合上述DTD定义的“有效的”XML文件的定义应该是: <联系人> <姓名>张三</姓名> <电话>12345678</EMAIL></联系人> 或者是: <联系人> <姓名>张三</姓名> <EMAIL>zhang@yahoo.com</EMAIL> </联系人> 注意:在一个组中,只允许使用一种连接符(例如“,”或“|”)。因 此,象下面这样定义的DTD是不合法的: <!ELEMENT 联系人(姓名,电话|EMAIL)> 要想使用多种连接符,只有通过创建子组的方式,使用 <!ELEMENT 联系人(姓名,(电话|EMAIL))>
可选子元素 字符“?”说明一个子元素是可选的,它可以出现,也可以不出现。 因此,在下面的DTD中,我们规定,每一个“联系人”都必须有一个 “姓名”子元素,同时或者有一个“电话”子元素,或者有一个“EMAIL” 子元素,此外,它还可以包含一个“地址”子元素,也可以不包含这 种元素。 <!ELEMENT 联系人(姓名,(电话|EMAIL),地址?)> <!ELEMENT 姓名(#PCDATA)> <!ELEMENT 电话(#PCDATA)> <!ELEMENT EMAIL(#PCDATA)> <!ELEMENT 地址(街道,城市,省份)> <!ELEMENT 街道 (#PCDATA)> <!ELEMENT 城市 (#PCDATA)> <!ELEMENT 省份 (#PCDATA)>
可选子元素 下面的XML片段是“有效的”: <联系人><姓名>张三</姓名> <EMAIL>zhang@aaa.com</EMAIL> <地址> <街道>五街1234号</街道> <城市>北京市</城市> <省份>北京</省份> </地址> </联系人> 同样,下面这段不包含“地址”元素的XML片段也是“有效的”: <联系人> <姓名>张三</姓名> <EMAIL>zhang@aaa.com</EMAIL></联系人>
混合内容 • 一个元素中既希望包含子元素,也希望包含纯文本。XML中允许这种使用方法,并把这种元素称为混合内容的元素。 • 在下面的例子中,“联系人”就是一个混合元素。
混合内容 <?xml version = “1.0” encoding=“GB2312” standalone = “yes”?><!DOCTYPE 联系人列表 [ <!ELEMENT 联系人列表 (联系人)*> <!ELEMENT 联系人(姓名|电话|EMAIL|#PCDATA)*> <!ELEMENT 姓名(#PCDATA)> <!ELEMENT 电话(#PCDATA)> <!ELEMENT EMAIL(#PCDATA)> ]> <联系人列表> <联系人> <姓名>张三</姓名> <电话>(010)62345678</电话> <EMAIL>zhang@aaa.com</EMAIL>这是关于张三的信息</联系人> </联系人列表> 注意,由于在“(姓名|电话|EMAIL|#PCDATA)”之外有“*”,所以在元素 “联系人”中可以包含零个或多个“姓名”、电话、EMAIL和纯文本字段。
小结 • 除了根元素外,在定义其它元素时使用关键字ANY都是不好的习惯。一般来说,在写一个XML文件时需要严格遵循DTD的规则,这时,一个定义明确的DTD,虽然表面上似乎充满了条条框框,但实际上会使你在书写XML文件时有规可循,反而方便了你的工作和语法分析器的工作。相反,一个在元素定义中充满了ANY的DTD,反而可能会搞得你不知所措,一头雾水。 • 不能对不同的元素使用相同的元素名,即便这些元素的内容、包含的子元素不同也不行,因为它只会引起文件各个元素的混淆,使文件的可读性大打折扣。
小结 • 定义元素时,顺序是无关紧要的。因此<!ELEMENT 姓名(#PCDATA)> <!ELEMENT 联系人列表 ANY> <!ELEMENT 联系人(姓名)>和<!ELEMENT 联系人列表 ANY> <!ELEMENT 联系人(姓名)> <!ELEMENT 姓名(#PCDATA)>所定义的文件结构是完全相同的。
小结 • 元素名的第一个字母必须是字母、或下划线(_)、或冒号(:),后跟字母、数字、句号(.)、冒号、下划线、连结号(-)的组合,并且不能包含空白符,不能以“xml”开头。 • 另外,尽管元素的第一个字母使用冒号是合法的,但最好避免这样做,因为它会引起混淆。 • 需要注意的是,尽管XML1.0标准允许使用任何长度的文件名,但是实际的XML处理器常常会限制标记名的长度。
习 题 1.何谓DTD?在XML文件中使用DTD有何好处? 2.在合法的XML文档中使用的每项标记都要在DTD中的元素声明中加以声明,请简述以下几种声明方式: 序列;零或多个子元素零;选择。
习 题(续) 3.请撰写一个实际XML文件来说明引用底下的DTD? <?xml version=”1.0”?> <!ELEMENT book (title,author,breakline,publish,price,language)> <!ELEMENT title (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT publish (#PCDATA)> <!ELEMENT price (#PCDATA)> <!ELEMENT language (#PCDATA)> <!ELEMENT breakline EMPTY>
习 题(续) 4.请撰写一个实际XML文件来说明下面的DTD? <? Xml version = “1.0” encording = “GB2312”?> <!DOCTYPE 汽车[ <!ELEMENT 汽车(品牌,车主,保险公司*,银行贷款?,维修地点)〉 <!ELEMENT 品牌(#PCDATA)〉 <!ELEMENT 车主(#PCDATA)〉 <!ELEMENT 保险公司(#PCDATA)〉 <!ELEMENT 银行贷款(#PCDATA)〉 <!ELEMENT 维修地点(#PCDATA)〉 ]>
3.1.4 DTD的属性声明 • 开始标记和空标记可包含由等号“=”分割开的成对的属性名和属性值 • 属性包含有关元素内容信息,而不是元素内容本身。 • 元素可具有多个属性 • 结束标记不能带属性
3.1.4 DTD的属性声明 • 属性是XML提供的描述元素某些性质的信息。 • 在一个有效的XML文档中,属性要经过DTD的属性说明。 • 在DTD声明中,属性的声明语法为: <!ATTLIST 元素名 属性名 属性类型 属性默认值类型> • 元素名为属性所属的元素的名称 • 属性类型是对属性值的约束
3.1.4 DTD的属性声明 • 例如: <商品 类型 =“服装” 颜色 = "黄色"> 元素名是“商品”;属性名是属性的命名, “类型”和“颜色”是属性名;默认值说明在XML文件中,如果没有特别说明属性的取值,语法分析器默认它具有的取值;属性类型则用来指定该属性是属于有效属性类型中的哪种类型。 • 注意:由于ATTLIST是一个属性的列表,它可以包含很多属性,在实际应用中,一个元素也经常有多个属性。
属性默认值类型 • #IMPLIED:属性值可有可无的属性,而且也无须在DTD中为该属性提供缺省值。 • 语法:<!ATTLIST 元素名称 属性名称 #IMPLIED> • 有时用户在不强制指定特定默认值的情况下省略特定属性值。 • 例如,可以拥有一个SHIRT(衬衣)元素,其具有一个声明为NMTOKEN的SIZE属性。但有些衬衫属于均码,没有尺寸。可以省去SIZE这个值,并且处理器隐含这个衬衫属于均码, <!ATTLIST SHIRT SIZE NOTOKEN #IMPLIED > <SHIRT>---符合上述定义 <SHIRT SIZE=“”>---不符合上述定义
属性默认值类型 • #REQUIRED:必须赋值的属性 • 关键字REQUIRED说明XML文件中必须为这个属性给出一个属性值。 • 与提供默认值相反的情况,文档类型设计者需要强制作者选择一个值。如果属性值既重要又无法可靠地默认确定,那么设计者可以要求作者用该属性默认值来指定。 • 例如:<!ATTLIST IMAG URL CDATA #REQUIRED> 这种情况下,DTD设计者使URL属性在所用IMAG元素上都成为必需。之所以这样做是因为如果没有一个URL定位图像文件,则此IMAGE元素没有任何意义。
属性默认值类型 • #FIXED:表明该属性一定要出现,且固定为特定值,不许用其他值。 • 当需要为一个特定的属性提供一个缺省值,并且不希望XML文件的编写者把你的缺省值替代掉。这时候,就可使用FIXED关键字,同时为该属性提供一个缺省值。 • 特定属性值表明该属性的默认值,当XML文档中没有显式给出该属性的取值时,取此值。当该属性的取值已经显式地给出,则为给出值。 • 如果不使用上面任何一种关键字的话,该种属性就是属于这种类型。对于这种属性,你需要在DTD中为它提供一个缺省值。而在XML文件中可以为该属性给出新的属性值来覆盖事先定义的缺省值,也可以不另外给出属性值,后一种情况下它就默认为采用DTD中给出的缺省值。
属性类型 (1)CDATA类型:是最简单的属性类型,也是约束最少的属性类型。即CharacterData 缩写,代表该属性值为一般的文字,除此没有其它限制. • 语法: <!ATTLIST 元素名称 属性名称 CDATA 属性默认值类型> • 例如: <?xml version = "1.0“ encoding="GB2312" standalone = "yes"?><!DOCTYPE 剧本 [ <!ELEMENT 剧本 ANY> <!ELEMENT 对话 (#PCDATA)> <!ATTLIST 对话 演员 CDATA> ]> <剧本> <对话 演员=“某甲”>我可不这么认为!</对话> <对话 演员=“某乙”>为什么呢?</对话> </剧本>
属性类型 (2)枚举型:列举了该属性所能取得的全部值. • 语法: <!ATTLIST 元素名称 属性名称 (可选属性值1|可选属性值2|……|可选属性值N) 属性默认值类型> • 例如: <?xml version = “1.0”encoding=“GB2312”standalone = “yes”?><!DOCTYPE 购物篮 [ <!ELEMENT 购物篮 ANY> <!ELEMENT 肉 EMPTY> <!ATTLIST 肉 类型( 鸡肉 | 牛肉 | 猪肉 | 鱼肉 ) “鸡肉”> ]> <购物篮> <肉 类型 = “鱼肉”/> <肉 类型 = “牛肉”/> <肉/> </购物篮> 注意,在上面这个例子中,给属性“类型”定义的缺省值是“鸡肉”,所以“购 物篮”中的第三个元素的“类型”属性取值为“鸡肉”。
属性类型 (3)NMTOKEN和NMTOKENS类型:一个有效的XML名称,必须以字母或者下划线开始,之后是字母、数字下划线、短横线或圆点,而且不能包含空格。 后者表明属性值可能由若干个满足NMTOKEN属性要求结合在一起形成的,即多个NMTOKEN之间可能存在空格。 • 语法: <!ATTLIST 元素名称 属性名称 NMTOKEN|NMTOKENS 属性默认值类型>
属性类型 • 例如1: <!ATTLIST Employee security_level NMTOKEN #REQUIRED> <Employee security_level=“trusted”> • 上述代码表示元素E m p l o y e e有一个名为s e c u r i t y _ l e v e l的属性,其值符合X M L名称记号的规则。我们可以用它来控制对机密文档的访问。由于定义属性列表时使用了N M TO K E N,而不是枚举类型,文档创作者只需创建新的值,就能够适应新的安全级别要求,而不必每次都编辑D T D。只要符合我们前面介绍的有效的N M TO K E N值应该遵守的规则任何值都可以作为这种属性的值。
属性类型 • 例如2: <!ATTLIST Employee security_compartments NMTOKENS #IMPLIED> <Employee security_compartments=“red green mega ultra ”> 这个职员能够访问名为r e d、g r e e n、m e g a和u l t r a的安 全区域。就类型而言,这些都是有效的N M TO K E N值。与枚举类型 不同,解析器不检查这些值的有效性。文档的作者必须确保自己使 用了适当的名称。
属性类型 • 例如3: <!ELEMENT 数据(#PCDATA)> <!ATTLIST 数据 安全性( ON | OFF ) "OFF“ 授权用户 NMTOKENS #IMPLIED > Xml文件: <数据 安全性="ON" 授权用户 = "IggieeB SelenaS GuntherB">blah blah blah </数据>
属性类型 • NMTOKEN属性类型 • NMTOKEN属性类型限定属性值为有效的XML名称。 • 当需要从大量名字中选取不是XML的规定部分但与XML命名要求相符的名字时,就能体现NMTOKEN的用途。
属性类型 • NMTOKENS属性类型 • NMTOKENS属性类型几乎就是NMTOKEN的复数形式。这种类型的属性可以使如下情况合法——属性由若干XML名称字组成,彼此间由空格分隔。通常可为使用NMTOKEN属性相同的理由而使用NMTOKENS属性,但仅仅在需要多个名字的时候。
属性类型 (4)ENTITY和ENTITIES类型:当属性值是一个外部实体的引用时,用ENTITY来说明属性类型。 一般来说,当属性值是一个内部实体引用时,将属性类型声明为CDATA即可。 • 实体属性类型 • 实体类型的属性值属于一般实体,如前所述,它的定义方式是: <!ENTITY 实体名 “实体内容”> 或利用SYSTEM定义外部实体,方式为: <!ENTITY 实体名 SYSTEM “外部文件名”> • 引用方式为: &实体名; 使用关键字ENTITY,则声明一个属性是实体类型,它的取值为已定 义的实体。请看下面例子:
属性类型 <?xml version = "1.0" encoding="GB2312“ standalone = "yes"?><!DOCTYPE 文件[ <!ELEMENT 文件 ANY> <!ELEMENT 电影 EMPTY> <!ATTLIST 电影 来源 ENTITY #REQUIRED> <!ENTITY pic SYSTEM “1-5.jpg"> ]><文件> <电影 来源 = "pic"></文件>