|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
1. 引言
XML(eXtensible Markup Language)作为一种自描述性的标记语言,已经成为数据交换和存储的重要标准。在XML的世界中,DTD(Document Type Definition,文档类型定义)扮演着至关重要的角色,它定义了XML文档的结构、元素以及元素之间的关系。DTD不仅确保了XML文档的有效性,还提供了一种验证机制,使得数据交换更加可靠和标准化。
本文将深入探讨DTD的两个核心组成部分:实体引用和元素声明。通过从基础概念到实际应用的全面解析,帮助读者理解如何使用DTD来构建结构化、有效且可维护的XML文档。无论您是XML的初学者还是希望加深对DTD理解的专业人士,本文都将为您提供有价值的知识和实践指导。
2. XML基础回顾
在深入探讨DTD之前,让我们先回顾一下XML的基础知识。
XML是一种标记语言,类似于HTML,但与之不同的是,XML专注于数据的描述和传输,而不是数据的显示。XML文档由标签、属性和内容组成,具有自我描述的特性。
一个简单的XML文档示例如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <bookstore>
- <book category="fiction">
- <title lang="en">The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
- <book category="children">
- <title lang="en">Harry Potter</title>
- <author>J.K. Rowling</author>
- <year>1997</year>
- <price>15.99</price>
- </book>
- </bookstore>
复制代码
XML文档有两个基本的有效性级别:
1. 格式良好的(Well-formed):文档遵循XML的基本语法规则,如所有标签都必须关闭,标签必须正确嵌套等。
2. 有效的(Valid):文档不仅格式良好,还符合其DTD或XML Schema中定义的结构和规则。
DTD就是用来定义XML文档结构和规则的机制,它确保了XML文档的有效性。
3. DTD概述
DTD(Document Type Definition,文档类型定义)是一套用于定义XML文档结构的规则集合。它指定了XML文档中可以包含哪些元素、元素之间的关系、元素可以具有哪些属性以及元素的值应该遵循什么规则。
DTD可以:
• 定义XML文档的结构
• 确保数据的一致性和完整性
• 提供文档验证机制
• 支持数据重用(通过实体)
DTD可以通过两种方式与XML文档关联:
1. 内部DTD:DTD直接包含在XML文档中。
2. 外部DTD:DTD存储在单独的文件中,XML文档通过引用来使用它。
3.1 内部DTD示例
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE bookstore [
- <!ELEMENT bookstore (book+)>
- <!ELEMENT book (title, author, year, price)>
- <!ATTLIST book category CDATA #REQUIRED>
- <!ELEMENT title (#PCDATA)>
- <!ATTLIST title lang CDATA #REQUIRED>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
- ]>
- <bookstore>
- <book category="fiction">
- <title lang="en">The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
- <book category="children">
- <title lang="en">Harry Potter</title>
- <author>J.K. Rowling</author>
- <year>1997</year>
- <price>15.99</price>
- </book>
- </bookstore>
复制代码
3.2 外部DTD示例
首先,创建一个名为bookstore.dtd的外部DTD文件:
- <!ELEMENT bookstore (book+)>
- <!ELEMENT book (title, author, year, price)>
- <!ATTLIST book category CDATA #REQUIRED>
- <!ELEMENT title (#PCDATA)>
- <!ATTLIST title lang CDATA #REQUIRED>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
复制代码
然后,在XML文档中引用这个外部DTD:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE bookstore SYSTEM "bookstore.dtd">
- <bookstore>
- <book category="fiction">
- <title lang="en">The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
- <book category="children">
- <title lang="en">Harry Potter</title>
- <author>J.K. Rowling</author>
- <year>1997</year>
- <price>15.99</price>
- </book>
- </bookstore>
复制代码
4. DTD中的元素声明
元素声明是DTD的核心部分,它定义了XML文档中可以包含哪些元素以及这些元素的结构和内容模型。
4.1 元素声明的语法
元素声明的基本语法如下:
- <!ELEMENT element_name content_model>
复制代码
其中:
• element_name是元素的名称
• content_model指定了元素的内容模型,即元素可以包含的内容
4.2 元素内容模型
DTD中定义了五种基本的元素内容模型:
空元素不包含任何内容,只能有属性。声明语法为:
- <!ELEMENT element_name EMPTY>
复制代码
示例:
对应的XML:
这种元素可以包含任何内容,包括其他元素、文本、甚至混合内容。声明语法为:
- <!ELEMENT element_name ANY>
复制代码
示例:
对应的XML:
- <note>
- <to>Tove</to>
- <from>Jani</from>
- <heading>Reminder</heading>
- <body>Don't forget me this weekend!</body>
- This is some text
- <b>and this is bold text</b>
- </note>
复制代码
这种元素只能包含指定的子元素,不能直接包含文本。声明语法为:
- <!ELEMENT element_name (child_element1, child_element2, ...)>
复制代码
示例:
- <!ELEMENT book (title, author, year, price)>
复制代码
对应的XML:
- <book>
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
复制代码
这种元素只能包含文本,不能包含子元素。声明语法为:
- <!ELEMENT element_name (#PCDATA)>
复制代码
其中,#PCDATA(Parsed Character Data)表示可解析的字符数据,即文本内容。
示例:
- <!ELEMENT title (#PCDATA)>
复制代码
对应的XML:
- <title>The Great Gatsby</title>
复制代码
这种元素可以包含文本和指定的子元素。声明语法为:
- <!ELEMENT element_name (#PCDATA|child_element1|child_element2|...)*>
复制代码
示例:
- <!ELEMENT description (#PCDATA|b|i|u)*>
复制代码
对应的XML:
- <description>
- This is a <b>bold</b> statement with <i>italic</i> and <u>underlined</u> text.
- </description>
复制代码
4.3 元素内容模型中的操作符
在定义元素内容模型时,可以使用以下操作符来指定元素的出现次数和顺序:
逗号用于指定子元素的顺序,表示子元素必须按照声明的顺序出现。
示例:
- <!ELEMENT book (title, author, year, price)>
复制代码
对应的XML必须按照title、author、year、price的顺序:
- <book>
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
复制代码
竖线用于表示选择,即子元素中只能出现其中一个。
示例:
- <!ELEMENT message (header|body)>
复制代码
对应的XML可以包含header或body中的一个:
- <message>
- <header>Important Message</header>
- </message>
复制代码
或
- <message>
- <body>This is the message content.</body>
- </message>
复制代码
问号表示元素是可选的,可以出现0次或1次。
示例:
- <!ELEMENT book (title, author, year?, price)>
复制代码
对应的XML中year元素是可选的:
- <book>
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <price>10.99</price>
- </book>
复制代码
星号表示元素可以出现0次或多次。
示例:
- <!ELEMENT bookstore (book*)>
复制代码
对应的XML中可以包含0个或多个book元素:
- <bookstore>
- <book>
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
- <book>
- <title>Harry Potter</title>
- <author>J.K. Rowling</author>
- <year>1997</year>
- <price>15.99</price>
- </book>
- </bookstore>
复制代码
或者
加号表示元素必须出现至少1次,可以出现多次。
示例:
- <!ELEMENT bookstore (book+)>
复制代码
对应的XML中必须包含至少1个book元素:
- <bookstore>
- <book>
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
- </bookstore>
复制代码
4.4 复杂内容模型示例
通过组合使用上述操作符,可以创建复杂的内容模型。以下是一些示例:
- <!ELEMENT bookstore (book+)>
- <!ELEMENT book (title, author+, (year|published), price, description?)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT published (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
- <!ELEMENT description (#PCDATA)>
复制代码
对应的XML:
- <bookstore>
- <book>
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
- <book>
- <title>Harry Potter</title>
- <author>J.K. Rowling</author>
- <author>Another Author</author>
- <published>1997</published>
- <price>15.99</price>
- <description>A popular children's book.</description>
- </book>
- </bookstore>
复制代码- <!ELEMENT paragraph (#PCDATA|b|i|u|em|strong)*>
- <!ELEMENT b (#PCDATA)>
- <!ELEMENT i (#PCDATA)>
- <!ELEMENT u (#PCDATA)>
- <!ELEMENT em (#PCDATA)>
- <!ELEMENT strong (#PCDATA)>
复制代码
对应的XML:
- <paragraph>
- This is a <strong>paragraph</strong> with <em>mixed</em> content.
- It can contain <b>bold</b>, <i>italic</i>, and <u>underlined</u> text,
- as well as plain text.
- </paragraph>
复制代码
4.5 元素声明的最佳实践
在定义DTD中的元素声明时,应遵循以下最佳实践:
1. 保持一致性:使用一致的命名约定和结构风格。
2. 避免过度复杂:尽量保持内容模型简单明了,避免不必要的复杂性。
3. 合理使用操作符:根据实际需求选择合适的操作符,避免过度限制或过度宽松。
4. 考虑可扩展性:设计DTD时考虑未来的扩展需求,预留适当的灵活性。
5. 文档化:为复杂的DTD提供详细的文档,说明每个元素的用途和结构。
5. DTD中的实体引用
实体是DTD中的另一个重要概念,它允许定义可重用的内容片段。实体可以看作是XML文档中的宏或变量,可以在文档中被引用和替换。
5.1 实体的类型
DTD中定义了多种类型的实体:
1. 内部通用实体:在DTD内部定义,在XML文档中引用。
2. 外部通用实体:在外部文件中定义,在XML文档中引用。
3. 内部参数实体:在DTD内部定义,仅在DTD中引用。
4. 外部参数实体:在外部文件中定义,仅在DTD中引用。
5.2 内部通用实体
内部通用实体在DTD内部定义,可以在XML文档中引用。其声明语法为:
- <!ENTITY entity_name "entity_value">
复制代码
示例:
- <!ENTITY company "ABC Corporation">
- <!ENTITY copyright "Copyright &company; 2023. All rights reserved.">
复制代码
在XML文档中引用这些实体:
- <footer>
- ©right;
- </footer>
复制代码
解析后的XML:
- <footer>
- Copyright ABC Corporation 2023. All rights reserved.
- </footer>
复制代码
5.3 外部通用实体
外部通用实体引用外部文件中的内容。其声明语法为:
- <!ENTITY entity_name SYSTEM "URI">
复制代码
或者:
- <!ENTITY entity_name PUBLIC "public_identifier" "URI">
复制代码
示例:
假设有一个名为footer.xml的外部文件:
- <footer>
- <company>ABC Corporation</company>
- <year>2023</year>
- <rights>All rights reserved.</rights>
- </footer>
复制代码
在DTD中声明外部实体:
- <!ENTITY footer SYSTEM "footer.xml">
复制代码
在XML文档中引用这个实体:
- <document>
- <content>...</content>
- &footer;
- </document>
复制代码
解析后的XML:
- <document>
- <content>...</content>
- <footer>
- <company>ABC Corporation</company>
- <year>2023</year>
- <rights>All rights reserved.</rights>
- </footer>
- </document>
复制代码
5.4 内部参数实体
参数实体只能在DTD内部使用,不能在XML文档中直接引用。参数实体的名称以百分号(%)开头。其声明语法为:
- <!ENTITY % entity_name "entity_value">
复制代码
示例:
- <!ENTITY % commonElements "title, author, year">
- <!ELEMENT book (%commonElements;, price)>
- <!ELEMENT article (%commonElements;, content)>
复制代码
在这个例子中,%commonElements;参数实体被定义为title, author, year,然后在book和article元素的声明中被引用。这样做的好处是可以重用共同的元素定义,减少重复。
5.5 外部参数实体
外部参数实体引用外部文件中的内容,并且只能在DTD内部使用。其声明语法为:
- <!ENTITY % entity_name SYSTEM "URI">
复制代码
或者:
- <!ENTITY % entity_name PUBLIC "public_identifier" "URI">
复制代码
示例:
假设有一个名为common-elements.dtd的外部DTD文件:
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
复制代码
在主DTD文件中引用这个外部参数实体:
- <!ENTITY % commonElements SYSTEM "common-elements.dtd">
- %commonElements;
- <!ELEMENT book (title, author, year, price)>
- <!ELEMENT price (#PCDATA)>
复制代码
这种方式允许将DTD模块化,便于维护和重用。
5.6 预定义实体
XML中预定义了五个实体,用于表示特殊字符:
这些实体可以直接在XML文档中使用,无需在DTD中声明。
示例:
- <example>
- <book>
- <title>"Harry Potter"</title>
- <author>J.K. Rowling</author>
- </book>
- </example>
复制代码
解析后的XML:
- <example>
- <book>
- <title>"Harry Potter"</title>
- <author>J.K. Rowling</author>
- </book>
- </example>
复制代码
5.7 实体的高级应用
实体可以嵌套引用,即一个实体的值可以包含对另一个实体的引用。
示例:
- <!ENTITY company "ABC Corporation">
- <!ENTITY year "2023">
- <!ENTITY copyright "Copyright &company; &year;. All rights reserved.">
复制代码
在XML文档中引用:
- <footer>©right;</footer>
复制代码
解析后的XML:
- <footer>Copyright ABC Corporation 2023. All rights reserved.</footer>
复制代码
非解析实体(Unparsed Entities)用于引用非XML数据,如图像、音频或视频文件。非解析实体使用NDATA关键字声明。
示例:
- <!ENTITY logo SYSTEM "company-logo.gif" NDATA gif>
- <!NOTATION gif SYSTEM "image/gif">
复制代码
在XML文档中通过属性引用非解析实体:
- <company>
- <name>ABC Corporation</name>
- <logo source="logo"/>
- </company>
复制代码
对应的DTD声明:
- <!ELEMENT company (name, logo)>
- <!ELEMENT name (#PCDATA)>
- <!ELEMENT logo EMPTY>
- <!ATTLIST logo source ENTITY #REQUIRED>
复制代码
DTD支持条件部分,允许根据条件包含或排除某些声明。条件部分使用参数实体和INCLUDE/IGNORE关键字实现。
示例:
- <!ENTITY % extended "INCLUDE">
- <![%extended;[
- <!ELEMENT extended-content (section+)>
- <!ELEMENT section (title, para+)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT para (#PCDATA)>
- ]]>
复制代码
如果将%extended;定义为IGNORE,则条件部分的内容将被忽略:
- <!ENTITY % extended "IGNORE">
- <![%extended;[
- <!ELEMENT extended-content (section+)>
- <!ELEMENT section (title, para+)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT para (#PCDATA)>
- ]]>
复制代码
5.8 实体引用的最佳实践
在使用DTD中的实体引用时,应遵循以下最佳实践:
1. 合理命名:使用清晰、一致的命名约定,使实体名称易于理解。
2. 避免过度嵌套:虽然实体可以嵌套引用,但过度嵌套会降低可读性和维护性。
3. 模块化设计:使用外部参数实体将DTD模块化,提高可维护性。
4. 注意安全性:外部实体可能带来安全风险,如XXE(XML External Entity)攻击,应谨慎使用。
5. 文档化:为复杂的实体提供详细的文档,说明其用途和使用方法。
6. DTD中的属性声明
除了元素声明和实体引用,DTD还允许声明元素的属性。属性提供了关于元素的额外信息。
6.1 属性声明的语法
属性声明的语法如下:
- <!ATTLIST element_name
- attribute_name attribute_type attribute_default
- attribute_name attribute_type attribute_default
- ...
- >
复制代码
其中:
• element_name是元素的名称
• attribute_name是属性的名称
• attribute_type是属性的类型
• attribute_default是属性的默认值或默认行为
6.2 属性类型
DTD定义了多种属性类型:
CDATA(Character Data)类型的属性可以包含任何文本字符。
示例:
- <!ATTLIST book
- description CDATA #IMPLIED
- >
复制代码
对应的XML:
- <book description="A classic American novel">
- ...
- </book>
复制代码
枚举类型限制属性的值必须是预定义选项之一。
示例:
- <!ATTLIST book
- category (fiction|non-fiction|biography|science) "fiction"
- >
复制代码
对应的XML:
- <book category="fiction">
- ...
- </book>
复制代码
ID类型的属性必须是一个唯一的标识符,在文档中不能重复。
示例:
- <!ATTLIST book
- id ID #REQUIRED
- >
复制代码
对应的XML:
- <book id="bk101">
- ...
- </book>
复制代码
IDREF类型的属性必须引用文档中某个元素的ID属性值。IDREFS类型的属性可以引用多个ID,用空格分隔。
示例:
- <!ATTLIST book
- id ID #REQUIRED
- related IDREFS #IMPLIED
- >
复制代码
对应的XML:
- <book id="bk101">
- ...
- </book>
- <book id="bk102" related="bk101">
- ...
- </book>
复制代码
NMTOKEN(Name Token)类型的属性必须是一个有效的XML名称。NMTOKENS类型的属性可以包含多个NMTOKEN,用空格分隔。
示例:
- <!ATTLIST book
- keywords NMTOKENS #IMPLIED
- >
复制代码
对应的XML:
- <book keywords="classic american novel">
- ...
- </book>
复制代码
NOTATION类型的属性值必须是在DTD中声明的符号名称。
示例:
- <!NOTATION gif SYSTEM "image/gif">
- <!NOTATION jpeg SYSTEM "image/jpeg">
- <!ATTLIST image
- src CDATA #REQUIRED
- type NOTATION (gif|jpeg) #REQUIRED
- >
复制代码
对应的XML:
- <image src="logo.gif" type="gif"/>
复制代码
ENTITY类型的属性值必须是在DTD中声明的实体名称。ENTITIES类型的属性可以包含多个实体名称,用空格分隔。
示例:
- <!ENTITY logo1 SYSTEM "logo1.gif" NDATA gif>
- <!ENTITY logo2 SYSTEM "logo2.gif" NDATA gif>
- <!NOTATION gif SYSTEM "image/gif">
- <!ATTLIST image
- source ENTITY #REQUIRED
- >
复制代码
对应的XML:
6.3 属性默认值
DTD中定义了四种属性默认值的行为:
属性必须提供值。
示例:
- <!ATTLIST book
- id ID #REQUIRED
- >
复制代码
对应的XML:
- <book id="bk101">
- ...
- </book>
复制代码
属性是可选的。
示例:
- <!ATTLIST book
- description CDATA #IMPLIED
- >
复制代码
对应的XML:
或
- <book description="A classic American novel">
- ...
- </book>
复制代码
属性有固定值,如果在XML中提供了其他值,则验证器会报错。
示例:
- <!ATTLIST book
- version CDATA #FIXED "1.0"
- >
复制代码
对应的XML:
- <book version="1.0">
- ...
- </book>
复制代码
或者,因为值是固定的,所以可以省略:
为属性提供默认值,如果在XML中没有提供值,则使用默认值。
示例:
- <!ATTLIST book
- category (fiction|non-fiction|biography|science) "fiction"
- >
复制代码
对应的XML:
- <book category="non-fiction">
- ...
- </book>
复制代码
或者,因为提供了默认值,所以可以省略:
6.4 属性声明的示例
以下是一个综合示例,展示了DTD中属性声明的各种用法:
- <!ELEMENT bookstore (book+)>
- <!ELEMENT book (title, author+, year, price, description?)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
- <!ELEMENT description (#PCDATA)>
- <!ATTLIST book
- id ID #REQUIRED
- category (fiction|non-fiction|biography|science) "fiction"
- keywords NMTOKENS #IMPLIED
- related IDREFS #IMPLIED
- edition CDATA "1"
- lang CDATA "en"
- >
- <!NOTATION gif SYSTEM "image/gif">
- <!NOTATION jpeg SYSTEM "image/jpeg">
- <!ENTITY cover1 SYSTEM "cover1.gif" NDATA gif>
- <!ENTITY cover2 SYSTEM "cover2.jpg" NDATA jpeg>
- <!ELEMENT image EMPTY>
- <!ATTLIST image
- source ENTITY #REQUIRED
- type NOTATION (gif|jpeg) #REQUIRED
- >
复制代码
对应的XML:
- <bookstore>
- <book id="bk101" category="fiction" keywords="classic american" edition="1" lang="en">
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- <description>A classic American novel</description>
- <image source="cover1" type="gif"/>
- </book>
- <book id="bk102" category="fiction" related="bk101">
- <title>Tender Is the Night</title>
- <author>F. Scott Fitzgerald</author>
- <year>1934</year>
- <price>12.99</price>
- <image source="cover2" type="jpeg"/>
- </book>
- </bookstore>
复制代码
6.5 属性声明的最佳实践
在定义DTD中的属性声明时,应遵循以下最佳实践:
1. 合理使用属性:属性适合存储元素的元数据,而不是内容。内容应该放在子元素中。
2. 选择合适的属性类型:根据实际需求选择最合适的属性类型,如使用ID类型确保唯一性。
3. 提供适当的默认值:为常用属性提供合理的默认值,减少XML中的冗余。
4. 避免过度使用:不要过度使用属性,保持DTD的简洁性和可读性。
5. 文档化:为复杂的属性提供详细的文档,说明其用途和有效值。
7. DTD的高级应用
7.1 命名空间与DTD
XML命名空间(Namespaces)允许在同一个XML文档中使用来自不同词汇表的元素和属性,避免名称冲突。然而,DTD本身并不直接支持命名空间,因为DTD是在命名空间概念出现之前设计的。
要在DTD中处理命名空间,通常采用以下方法:
在DTD中固定使用特定的前缀来表示命名空间。
示例:
- <!ELEMENT html:html (html:head, html:body)>
- <!ELEMENT html:head (html:title)>
- <!ELEMENT html:title (#PCDATA)>
- <!ELEMENT html:body (html:p+)>
- <!ELEMENT html:p (#PCDATA)>
- <!ATTLIST html:html
- xmlns:html CDATA #FIXED "http://www.w3.org/1999/xhtml"
- >
复制代码
对应的XML:
- <html:html xmlns:html="http://www.w3.org/1999/xhtml">
- <html:head>
- <html:title>Example</html:title>
- </html:head>
- <html:body>
- <html:p>This is a paragraph.</html:p>
- </html:body>
- </html:html>
复制代码
在DTD中忽略命名空间,只关注本地名称。
示例:
- <!ELEMENT html (head, body)>
- <!ELEMENT head (title)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT body (p+)>
- <!ELEMENT p (#PCDATA)>
复制代码
对应的XML:
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title>Example</title>
- </head>
- <body>
- <p>This is a paragraph.</p>
- </body>
- </html>
复制代码
7.2 DTD的局限性
尽管DTD在XML文档验证中扮演了重要角色,但它也有一些明显的局限性:
DTD只支持有限的数据类型,主要是文本类型。它不支持更复杂的数据类型,如整数、日期、布尔值等。
如前所述,DTD本身不直接支持XML命名空间,这在使用多个词汇表时可能导致名称冲突。
DTD使用自己的语法,与XML不同,这使得学习和使用DTD变得复杂。
DTD的模块化和重用能力有限,特别是在大型项目中。
DTD对内容模型的控制相对粗糙,无法表达更复杂的约束,如”元素A必须出现,但如果元素B出现,则元素A不能出现”等。
7.3 DTD与XML Schema的比较
为了克服DTD的局限性,W3C开发了XML Schema(XSD),它提供了更强大和灵活的文档验证机制。以下是DTD与XML Schema的主要区别:
• DTD:使用非XML语法。
• XML Schema:使用XML语法,与其他XML工具和技术更好地集成。
• DTD:只支持基本的数据类型,主要是文本。
• XML Schema:支持丰富的内置数据类型,如字符串、整数、日期、布尔值等,还允许创建自定义数据类型。
• DTD:不直接支持命名空间。
• XML Schema:完全支持命名空间,允许在同一个文档中使用多个词汇表。
• DTD:内容模型相对简单,无法表达复杂的约束。
• XML Schema:提供更复杂和灵活的内容模型,支持更精细的控制。
• DTD:不支持继承,重用能力有限。
• XML Schema:支持类型继承,提供了更好的重用机制。
以下是一个简单的DTD和对应的XML Schema示例:
DTD示例:
- <!ELEMENT bookstore (book+)>
- <!ELEMENT book (title, author, year, price)>
- <!ATTLIST book category CDATA #IMPLIED>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
复制代码
XML Schema示例:
- <?xml version="1.0" encoding="UTF-8"?>
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:element name="bookstore">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="book" maxOccurs="unbounded">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="title" type="xs:string"/>
- <xs:element name="author" type="xs:string"/>
- <xs:element name="year" type="xs:gYear"/>
- <xs:element name="price" type="xs:decimal"/>
- </xs:sequence>
- <xs:attribute name="category" type="xs:string" use="optional"/>
- </xs:complexType>
- </xs:element>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- </xs:schema>
复制代码
8. 实际应用案例
8.1 电子书目录系统
假设我们要开发一个电子书目录系统,使用XML存储书籍信息,并使用DTD进行验证。
系统需要存储以下信息:
• 书籍基本信息:标题、作者、出版年份、价格、分类
• 书籍描述:摘要、目录
• 书籍评价:评分、评论
- <!-- 实体声明 -->
- <!ENTITY % textContent "(#PCDATA|b|i|u|em|strong)*">
- <!ENTITY % commonElements "title, author, year, price, category, description?">
- <!-- 元素声明 -->
- <!ELEMENT bookstore (book+)>
- <!ELEMENT book (%commonElements;, reviews?)>
- <!ELEMENT title %textContent;>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
- <!ELEMENT category (#PCDATA)>
- <!ELEMENT description (%textContent;, toc?)>
- <!ELEMENT toc (chapter+)>
- <!ELEMENT chapter (#PCDATA)>
- <!ELEMENT reviews (review+)>
- <!ELEMENT review (rating, comment, reviewer)>
- <!ELEMENT rating (#PCDATA)>
- <!ELEMENT comment (#PCDATA)>
- <!ELEMENT reviewer (#PCDATA)>
- <!-- 属性声明 -->
- <!ATTLIST book
- id ID #REQUIRED
- isbn CDATA #IMPLIED
- lang CDATA "en"
- available (yes|no) "yes"
- >
- <!ATTLIST chapter
- number CDATA #REQUIRED
- pages CDATA #IMPLIED
- >
- <!ATTLIST review
- date CDATA #REQUIRED
- >
- <!-- 格式化元素声明 -->
- <!ELEMENT b (#PCDATA)>
- <!ELEMENT i (#PCDATA)>
- <!ELEMENT u (#PCDATA)>
- <!ELEMENT em (#PCDATA)>
- <!ELEMENT strong (#PCDATA)>
复制代码- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE bookstore SYSTEM "bookstore.dtd">
- <bookstore>
- <book id="bk101" isbn="978-0-7432-7356-5" lang="en" available="yes">
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- <category>fiction</category>
- <description>
- A classic American novel set in the Jazz Age on Long Island.
- <toc>
- <chapter number="1">Chapter 1</chapter>
- <chapter number="2">Chapter 2</chapter>
- <chapter number="3">Chapter 3</chapter>
- <chapter number="4">Chapter 4</chapter>
- <chapter number="5">Chapter 5</chapter>
- <chapter number="6">Chapter 6</chapter>
- <chapter number="7">Chapter 7</chapter>
- <chapter number="8">Chapter 8</chapter>
- <chapter number="9">Chapter 9</chapter>
- </toc>
- </description>
- <reviews>
- <review date="2023-01-15">
- <rating>5</rating>
- <comment>A masterpiece of American literature.</comment>
- <reviewer>John Doe</reviewer>
- </review>
- <review date="2023-02-20">
- <rating>4</rating>
- <comment>Fitzgerald's prose is beautiful and evocative.</comment>
- <reviewer>Jane Smith</reviewer>
- </review>
- </reviews>
- </book>
- <book id="bk102" isbn="978-0-439-70818-8" lang="en" available="yes">
- <title>Harry Potter and the Sorcerer's Stone</title>
- <author>J.K. Rowling</author>
- <year>1997</year>
- <price>15.99</price>
- <category>children</category>
- <description>
- The first novel in the <em>Harry Potter</em> series.
- <toc>
- <chapter number="1">The Boy Who Lived</chapter>
- <chapter number="2">The Vanishing Glass</chapter>
- <chapter number="3">The Letters from No One</chapter>
- <chapter number="4">The Keeper of the Keys</chapter>
- <chapter number="5">Diagon Alley</chapter>
- <chapter number="6">The Journey from Platform Nine and Three-Quarters</chapter>
- <chapter number="7">The Sorting Hat</chapter>
- <chapter number="8">The Potions Master</chapter>
- <chapter number="9">The Midnight Duel</chapter>
- <chapter number="10">Halloween</chapter>
- <chapter number="11">Quidditch</chapter>
- <chapter number="12">The Mirror of Erised</chapter>
- <chapter number="13">Nicolas Flamel</chapter>
- <chapter number="14">Norbert the Norwegian Ridgeback</chapter>
- <chapter number="15">The Forbidden Forest</chapter>
- <chapter number="16">Through the Trapdoor</chapter>
- <chapter number="17">The Man with Two Faces</chapter>
- </toc>
- </description>
- </book>
- </bookstore>
复制代码
8.2 企业报告系统
假设我们要开发一个企业报告系统,使用XML存储季度报告数据,并使用DTD进行验证。
系统需要存储以下信息:
• 报告基本信息:标题、期间、部门
• 财务数据:收入、支出、利润
• 关键指标:员工数量、客户数量、项目数量
• 分析和预测:趋势分析、未来预测
- <!-- 外部参数实体 -->
- <!ENTITY % financialElements SYSTEM "financial-elements.dtd">
- %financialElements;
- <!-- 内部参数实体 -->
- <!ENTITY % commonAttributes "id ID #IMPLIED status (draft|final|archived) 'draft'">
- <!-- 元素声明 -->
- <!ELEMENT reports (report+)>
- <!ELEMENT report (header, financial, metrics, analysis)>
- <!ELEMENT header (title, period, department, author)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT period (#PCDATA)>
- <!ELEMENT department (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT financial (revenue, expenses, profit)>
- <!ELEMENT revenue (item+)>
- <!ELEMENT expenses (item+)>
- <!ELEMENT profit (#PCDATA)>
- <!ELEMENT item (#PCDATA)>
- <!ELEMENT metrics (employees, customers, projects)>
- <!ELEMENT employees (#PCDATA)>
- <!ELEMENT customers (#PCDATA)>
- <!ELEMENT projects (#PCDATA)>
- <!ELEMENT analysis (trends, forecast)>
- <!ELEMENT trends (trend+)>
- <!ELEMENT trend (#PCDATA)>
- <!ELEMENT forecast (#PCDATA)>
- <!-- 属性声明 -->
- <!ATTLIST report %commonAttributes;>
- <!ATTLIST period
- start CDATA #REQUIRED
- end CDATA #REQUIRED
- type (monthly|quarterly|yearly) "quarterly"
- >
- <!ATTLIST item
- category CDATA #REQUIRED
- amount CDATA #REQUIRED
- currency CDATA "USD"
- >
- <!ATTLIST trend
- metric CDATA #REQUIRED
- direction (up|down|stable) #REQUIRED
- change CDATA #IMPLIED
- >
复制代码- <!ELEMENT revenue (item+)>
- <!ELEMENT expenses (item+)>
- <!ELEMENT profit (#PCDATA)>
- <!ELEMENT item (#PCDATA)>
- <!ATTLIST item
- category CDATA #REQUIRED
- amount CDATA #REQUIRED
- currency CDATA "USD"
- >
复制代码- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE reports SYSTEM "reports.dtd">
- <reports>
- <report id="rpt2023q1" status="final">
- <header>
- <title>Q1 2023 Financial Report</title>
- <period start="2023-01-01" end="2023-03-31" type="quarterly">Q1 2023</period>
- <department>Finance</department>
- <author>John Smith</author>
- </header>
- <financial>
- <revenue>
- <item category="Product Sales" amount="1250000" currency="USD"/>
- <item category="Services" amount="750000" currency="USD"/>
- <item category="Licensing" amount="250000" currency="USD"/>
- </revenue>
- <expenses>
- <item category="Salaries" amount="800000" currency="USD"/>
- <item category="Marketing" amount="200000" currency="USD"/>
- <item category="Operations" amount="300000" currency="USD"/>
- <item category="R&D" amount="150000" currency="USD"/>
- </expenses>
- <profit>300000</profit>
- </financial>
- <metrics>
- <employees>120</employees>
- <customers>450</customers>
- <projects>25</projects>
- </metrics>
- <analysis>
- <trends>
- <trend metric="Revenue" direction="up" change="15%"/>
- <trend metric="Profit" direction="up" change="10%"/>
- <trend metric="Customers" direction="up" change="8%"/>
- </trends>
- <forecast>
- Based on current trends, we expect Q2 revenue to increase by approximately 12%,
- with continued growth in customer acquisition and project delivery.
- </forecast>
- </analysis>
- </report>
- <report id="rpt2023q2" status="draft">
- <header>
- <title>Q2 2023 Financial Report</title>
- <period start="2023-04-01" end="2023-06-30" type="quarterly">Q2 2023</period>
- <department>Finance</department>
- <author>John Smith</author>
- </header>
- <financial>
- <revenue>
- <item category="Product Sales" amount="1400000" currency="USD"/>
- <item category="Services" amount="850000" currency="USD"/>
- <item category="Licensing" amount="300000" currency="USD"/>
- </revenue>
- <expenses>
- <item category="Salaries" amount="850000" currency="USD"/>
- <item category="Marketing" amount="250000" currency="USD"/>
- <item category="Operations" amount="320000" currency="USD"/>
- <item category="R&D" amount="180000" currency="USD"/>
- </expenses>
- <profit>350000</profit>
- </financial>
- <metrics>
- <employees>125</employees>
- <customers>485</customers>
- <projects>28</projects>
- </metrics>
- <analysis>
- <trends>
- <trend metric="Revenue" direction="up" change="12%"/>
- <trend metric="Profit" direction="up" change="16.7%"/>
- <trend metric="Customers" direction="up" change="7.8%"/>
- </trends>
- <forecast>
- Q2 results exceeded expectations, with strong performance across all product lines.
- We are optimistic about continued growth in the second half of the year.
- </forecast>
- </analysis>
- </report>
- </reports>
复制代码
9. 最佳实践和常见问题
9.1 DTD设计最佳实践
将大型DTD分解为多个小的、可重用的模块,使用外部参数实体进行组合。
示例:
- <!-- 主DTD文件 -->
- <!ENTITY % commonElements SYSTEM "common-elements.dtd">
- <!ENTITY % financialElements SYSTEM "financial-elements.dtd">
- <!ENTITY % reportStructure SYSTEM "report-structure.dtd">
- %commonElements;
- %financialElements;
- %reportStructure;
- <!ELEMENT reports (report+)>
复制代码
采用清晰、一致的命名约定,使DTD易于理解和维护。
示例:
- <!-- 使用驼峰命名法 -->
- <!ELEMENT firstName (#PCDATA)>
- <!ELEMENT lastName (#PCDATA)>
- <!ELEMENT emailAddress (#PCDATA)>
- <!-- 或者使用下划线分隔 -->
- <!ELEMENT first_name (#PCDATA)>
- <!ELEMENT last_name (#PCDATA)>
- <!ELEMENT email_address (#PCDATA)>
复制代码
为DTD提供详细的文档,说明每个元素和属性的用途、约束和示例。
示例:
- <!--
- Report DTD
- Version: 1.0
- Date: 2023-06-15
-
- Description:
- This DTD defines the structure for quarterly financial reports.
-
- Elements:
- - reports: Root element containing one or more report elements
- - report: Represents a single financial report
- - header: Contains report metadata
- - financial: Contains financial data
- - metrics: Contains key performance indicators
- - analysis: Contains trend analysis and forecasts
-
- Attributes:
- - id: Unique identifier for the report
- - status: Current status of the report (draft, final, archived)
- - period: Time period covered by the report
- -->
复制代码
保持DTD简单明了,避免不必要的复杂性。
示例:
- <!-- 不好的做法:过度复杂的内容模型 -->
- <!ELEMENT complexElement (a, (b | (c, d)?, e+, (f | g)*), h?)>
- <!-- 好的做法:简化内容模型 -->
- <!ELEMENT complexElement (a, content, h?)>
- <!ELEMENT content (b | (c, d)? | e+ | (f | g)*)>
复制代码
使用实体来重用常见的内容和结构,但避免过度嵌套。
示例:
- <!-- 好的做法:使用参数实体重用公共元素定义 -->
- <!ENTITY % contactInfo "name, email, phone?">
- <!ELEMENT customer (%contactInfo;, address)>
- <!ELEMENT supplier (%contactInfo;, company)>
复制代码
9.2 常见问题及解决方案
症状:XML文档无法通过DTD验证,出现各种错误。
可能原因:
• XML文档结构与DTD定义不匹配
• 元素顺序不正确
• 必需的属性缺失
• 实体引用错误
解决方案:
1. 仔细检查XML文档,确保其结构与DTD定义一致。
2. 使用XML验证工具(如XMLSpy、 Oxygen XML Editor等)进行验证,获取详细的错误信息。
3. 逐步构建XML文档,每添加一部分就进行验证,以便快速定位问题。
示例:
- <!-- 错误的XML -->
- <book>
- <author>F. Scott Fitzgerald</author>
- <title>The Great Gatsby</title>
- <year>1925</year>
- <price>10.99</price>
- </book>
- <!-- 正确的XML(根据DTD定义的顺序) -->
- <book>
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <year>1925</year>
- <price>10.99</price>
- </book>
复制代码
症状:XML文档中的实体引用无法正确解析或显示。
可能原因:
• 实体未在DTD中声明
• 实体引用语法错误
• 外部实体文件无法访问
解决方案:
1. 确保所有实体都在DTD中正确声明。
2. 检查实体引用语法,确保使用正确的格式(如&entity;)。
3. 对于外部实体,确保文件路径正确且文件可访问。
示例:
- <!-- 正确的实体声明 -->
- <!ENTITY company "ABC Corporation">
- <!ENTITY copyright "Copyright &company; 2023. All rights reserved.">
复制代码- <!-- 正确的实体引用 -->
- <footer>©right;</footer>
复制代码
症状:DTD变得非常复杂,难以理解和维护。
可能原因:
• 缺乏模块化设计
• 内容模型过于复杂
• 缺乏文档和注释
解决方案:
1. 将大型DTD分解为多个小的、可重用的模块。
2. 简化内容模型,避免不必要的复杂性。
3. 添加详细的注释和文档。
4. 考虑使用XML Schema替代DTD,特别是对于复杂的数据模型。
示例:
- <!-- 模块化DTD -->
- <!-- common-elements.dtd -->
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
- <!-- book.dtd -->
- <!ENTITY % commonElements SYSTEM "common-elements.dtd">
- %commonElements;
- <!ELEMENT book (title, author, year, price)>
复制代码
10. 总结
DTD(Document Type Definition)作为XML文档结构化的重要工具,在定义文档结构、确保数据一致性和完整性方面发挥着关键作用。本文从基础概念到实际应用,全面解析了DTD的核心组成部分:元素声明和实体引用。
通过本文的学习,我们了解到:
1. DTD基础:DTD定义了XML文档的结构、元素和属性,确保文档的有效性。DTD可以是内部的(直接包含在XML文档中)或外部的(存储在单独的文件中)。
2. 元素声明:元素声明定义了XML文档中可以包含哪些元素以及这些元素的内容模型。DTD支持多种内容模型,包括空元素、包含任何内容的元素、包含子元素的元素、包含文本的元素和混合内容元素。通过使用操作符(逗号、竖线、问号、星号和加号),可以创建复杂的内容模型。
3. 实体引用:实体是可重用的内容片段,可以分为内部通用实体、外部通用实体、内部参数实体和外部参数实体。实体引用允许在XML文档中重用预定义的内容,提高文档的可维护性和一致性。
4. 属性声明:属性声明定义了元素的属性,包括属性的类型和默认值。DTD支持多种属性类型,如CDATA、枚举类型、ID、IDREF、IDREFS、NMTOKEN、NMTOKENS、NOTATION、ENTITY和ENTITIES。
5. DTD的高级应用:尽管DTD有一些局限性(如不支持命名空间和数据类型有限),但在某些场景下仍然有其价值。DTD与XML Schema的比较显示,XML Schema提供了更强大和灵活的文档验证机制,但DTD在简单文档验证、传统系统维护和性能考虑方面仍有优势。
6. 实际应用案例:通过电子书目录系统和企业报告系统的案例,我们了解了如何在实际项目中应用DTD来定义和验证XML文档结构。
7. 最佳实践和常见问题:遵循DTD设计的最佳实践(如模块化设计、一致的命名约定、详细的文档、避免过度复杂的模型和合理使用实体)可以帮助我们创建高质量、可维护的DTD。同时,了解常见问题及其解决方案可以帮助我们快速定位和解决问题。
DTD基础:DTD定义了XML文档的结构、元素和属性,确保文档的有效性。DTD可以是内部的(直接包含在XML文档中)或外部的(存储在单独的文件中)。
元素声明:元素声明定义了XML文档中可以包含哪些元素以及这些元素的内容模型。DTD支持多种内容模型,包括空元素、包含任何内容的元素、包含子元素的元素、包含文本的元素和混合内容元素。通过使用操作符(逗号、竖线、问号、星号和加号),可以创建复杂的内容模型。
实体引用:实体是可重用的内容片段,可以分为内部通用实体、外部通用实体、内部参数实体和外部参数实体。实体引用允许在XML文档中重用预定义的内容,提高文档的可维护性和一致性。
属性声明:属性声明定义了元素的属性,包括属性的类型和默认值。DTD支持多种属性类型,如CDATA、枚举类型、ID、IDREF、IDREFS、NMTOKEN、NMTOKENS、NOTATION、ENTITY和ENTITIES。
DTD的高级应用:尽管DTD有一些局限性(如不支持命名空间和数据类型有限),但在某些场景下仍然有其价值。DTD与XML Schema的比较显示,XML Schema提供了更强大和灵活的文档验证机制,但DTD在简单文档验证、传统系统维护和性能考虑方面仍有优势。
实际应用案例:通过电子书目录系统和企业报告系统的案例,我们了解了如何在实际项目中应用DTD来定义和验证XML文档结构。
最佳实践和常见问题:遵循DTD设计的最佳实践(如模块化设计、一致的命名约定、详细的文档、避免过度复杂的模型和合理使用实体)可以帮助我们创建高质量、可维护的DTD。同时,了解常见问题及其解决方案可以帮助我们快速定位和解决问题。
尽管XML Schema提供了更强大的功能,但DTD作为XML验证的传统工具,仍然在许多场景下发挥着重要作用。通过深入理解DTD的核心概念和应用技巧,我们可以更好地利用这一工具来创建结构化、有效且可维护的XML文档。
随着XML技术的不断发展,我们可能会看到更多现代化的验证机制出现,但DTD作为XML文档结构化的基础,其核心概念和原理将继续影响未来的XML技术发展。因此,深入理解DTD对于任何从事XML相关工作的人员来说都是非常有价值的。
版权声明
1、转载或引用本网站内容(深入理解XML文档结构化核心DTD实体引用与元素声明从基础到应用全面解析)须注明原网址及作者(威震华夏关云长),并标明本网站网址(https://www.pixtech.cc/)。
2、对于不当转载或引用本网站内容而引起的民事纷争、行政处理或其他损失,本网站不承担责任。
3、对不遵守本声明或其他违法、恶意使用本网站内容者,本网站保留追究其法律责任的权利。
本文地址: https://www.pixtech.cc/thread-35062-1-1.html
|
|