DTD教程基础入门指南轻松掌握文档类型定义的核心概念从零开始学习DTD的基础知识和应用技巧帮助新手快速理解DTD的结构定义方法
1. 什么是DTD?
DTD(Document Type Definition,文档类型定义)是一种文档类型定义语言,用于定义XML文档的结构、元素和属性。DTD为XML文档提供了一套规则,规定了文档中可以包含哪些元素、元素之间的关系、元素可以有哪些属性以及它们的默认值等。
DTD最早是为SGML(Standard Generalized Markup Language)设计的,后来被XML(eXtensible Markup Language)所采用。通过DTD,可以确保XML文档的结构符合预定义的规范,从而实现数据的标准化和互操作性。
1.1 DTD的作用
DTD在XML文档中扮演着重要的角色,主要作用包括:
- 结构验证:确保XML文档遵循预定义的结构规则
- 数据完整性:通过定义元素和属性约束,保证数据的完整性和一致性
- 文档标准化:为XML文档提供统一的标准,便于不同系统之间的数据交换
- 提高可读性:明确的文档结构定义使XML文档更易于理解和维护
2. DTD的基本语法
DTD可以使用两种方式包含在XML文档中:内部DTD和外部DTD。
2.1 内部DTD
内部DTD直接包含在XML文档的DOCTYPE声明中。基本语法如下:
<!DOCTYPE 根元素 [ DTD声明内容 ]>
例如,一个简单的内部DTD示例:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE note [ <!ELEMENT note (to, from, heading, body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> ]> <note> <to>John</to> <from>Jane</from> <heading>Reminder</heading> <body>Don't forget the meeting tomorrow!</body> </note>
2.2 外部DTD
外部DTD存储在单独的文件中,通常以.dtd为扩展名。XML文档通过DOCTYPE声明引用外部DTD文件。
引用外部DTD的语法:
<!DOCTYPE 根元素 SYSTEM "DTD文件路径">
例如,假设有一个名为note.dtd的外部DTD文件:
<!ELEMENT note (to, from, heading, body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)>
XML文档可以这样引用它:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE note SYSTEM "note.dtd"> <note> <to>John</to> <from>Jane</from> <heading>Reminder</heading> <body>Don't forget the meeting tomorrow!</body> </note>
还可以使用公共标识符引用DTD:
<!DOCTYPE 根元素 PUBLIC "公共标识符" "DTD文件路径">
例如:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3. 元素声明
在DTD中,元素声明是最基本的组成部分,用于定义XML文档中可以包含的元素及其内容模型。
3.1 基本元素声明语法
元素声明的基本语法如下:
<!ELEMENT 元素名称 内容模型>
3.2 内容模型类型
DTD中定义了多种内容模型类型,用于指定元素可以包含的内容:
3.2.1 空元素
空元素不包含任何内容,使用关键字EMPTY声明:
<!ELEMENT img EMPTY>
在XML文档中,空元素可以表示为:
<img src="image.jpg" />
3.2.2 只包含文本的元素
只包含文本的元素使用关键字#PCDATA(Parsed Character Data)声明:
<!ELEMENT title (#PCDATA)>
在XML文档中:
<title>DTD Tutorial</title>
3.2.3 包含子元素的元素
包含子元素的元素通过列出子元素的名称来声明:
<!ELEMENT book (title, author, publisher, price)>
这表示book元素必须按顺序包含title、author、publisher和price四个子元素。
3.2.4 混合内容元素
混合内容元素可以包含文本和子元素,使用混合内容声明:
<!ELEMENT description (#PCDATA | emph | strong)*>
这表示description元素可以包含文本、emph元素和strong元素,它们可以按任意顺序出现零次或多次。
3.2.5 任意内容元素
使用关键字ANY声明的元素可以包含任何内容:
<!ELEMENT misc ANY>
在XML文档中:
<misc> This is some text <b>with bold</b> and <i>italic</i> text. </misc>
3.3 元素出现次数指示符
在元素声明中,可以使用特殊字符来指示子元素的出现次数:
?
- 出现零次或一次*
- 出现零次或多次+
- 出现一次或多次
例如:
<!ELEMENT book (title, author+, publisher?, chapter*)>
这表示:
- book元素必须包含一个title元素
- 必须包含一个或多个author元素
- 可以包含零个或一个publisher元素
- 可以包含零个或多个chapter元素
3.4 选择列表
使用竖线 |
可以创建选择列表,表示只能从列表中选择一个元素:
<!ELEMENT choice (option1 | option2 | option3)>
这表示choice元素必须包含option1、option2或option3中的一个。
3.5 组合使用
可以将上述各种方式组合使用,创建复杂的内容模型:
<!ELEMENT book (title, author+, (publisher | publication), chapter*, appendix?)>
这表示:
- book元素必须包含一个title元素
- 必须包含一个或多个author元素
- 必须包含一个publisher或publication元素(二选一)
- 可以包含零个或多个chapter元素
- 可以包含零个或一个appendix元素
4. 属性声明
DTD允许为元素定义属性,属性声明使用ATTLIST关键字。
4.1 属性声明语法
属性声明的基本语法如下:
<!ATTLIST 元素名称 属性名称 属性类型 属性默认值 ... >
例如:
<!ATTLIST img src CDATA #REQUIRED alt CDATA #IMPLIED width CDATA "100" height CDATA "100" >
4.2 属性类型
DTD定义了多种属性类型:
4.2.1 CDATA
CDATA(Character Data)类型的属性可以包含任何文本字符:
<!ATTLIST book title CDATA #REQUIRED >
4.2.2 枚举类型
枚举类型限制属性值必须为预定义的选项之一:
<!ATTLIST payment method (credit|debit|cash) "credit" >
这表示method属性的值只能是credit、debit或cash,默认值为credit。
4.2.3 ID和IDREF
ID类型的属性值必须是唯一的标识符,IDREF类型的属性值必须引用文档中某个元素的ID属性:
<!ATTLIST employee empID ID #REQUIRED manager IDREF #IMPLIED >
4.2.4 IDREFS
IDREFS类型的属性值可以包含多个ID引用,用空格分隔:
<!ATTLIST project projectID ID #REQUIRED members IDREFS #IMPLIED >
4.2.5 NMTOKEN和NMTOKENS
NMTOKEN(Name Token)类型的属性值必须是一个有效的XML名称,NMTOKENS可以包含多个NMTOKEN,用空格分隔:
<!ATTLIST product productCode NMTOKEN #REQUIRED categories NMTOKENS #IMPLIED >
4.2.6 NOTATION
NOTATION类型的属性值引用一个在DTD中声明的符号:
<!NOTATION GIF SYSTEM "image/gif"> <!NOTATION JPEG SYSTEM "image/jpeg"> <!ATTLIST image src CDATA #REQUIRED type NOTATION (GIF | JPEG) #REQUIRED >
4.2.7 实体
实体类型的属性值引用一个在DTD中声明的实体:
<!ENTITY logo SYSTEM "logo.gif" NDATA GIF> <!ATTLIST figure image ENTITY #REQUIRED >
4.3 属性默认值
DTD中定义了四种属性默认值:
4.3.1 #REQUIRED
属性必须提供值:
<!ATTLIST book isbn CDATA #REQUIRED >
4.3.2 #IMPLIED
属性是可选的:
<!ATTLIST book edition CDATA #IMPLIED >
4.3.3 #FIXED
属性有固定值,不能更改:
<!ATTLIST book version CDATA #FIXED "1.0" >
4.3.4 默认值
为属性提供默认值,如果未提供则使用默认值:
<!ATTLIST book language CDATA "en" >
5. 实体声明
实体是用于定义文本或数据的快捷方式,可以在XML文档中引用。DTD中可以声明多种类型的实体。
5.1 内部通用实体
内部通用实体在DTD内部定义,并在XML文档中使用:
<!ENTITY company "ABC Corporation">
在XML文档中引用:
<supplier>&company;</supplier>
5.2 外部通用实体
外部通用实体引用外部文件:
<!ENTITY footer SYSTEM "footer.xml">
在XML文档中引用:
<document> <content>...</content> &footer; </document>
5.3 参数实体
参数实体只能在DTD内部使用,以%开头:
<!ENTITY % commonElements "title | author | date"> <!ELEMENT book (%commonElements;, publisher, price)>
5.4 外部参数实体
外部参数实体引用外部DTD文件:
<!ENTITY % commonDTD SYSTEM "common.dtd"> %commonDTD;
5.5 未解析实体
未解析实体用于引用非XML数据,如图片或二进制文件:
<!NOTATION GIF SYSTEM "image/gif"> <!ENTITY logo SYSTEM "logo.gif" NDATA GIF>
在XML文档中引用:
<image src="logo"/>
6. DTD的高级特性
6.1 条件段
DTD支持条件段,可以根据条件包含或排除部分DTD声明:
<![ INCLUDE [ <!ELEMENT note (to, from, heading, body)> ]]> <![ IGNORE [ <!ELEMENT note (message)> ]]>
6.2 注释
在DTD中可以使用注释:
<!-- 这是一个DTD注释 --> <!ELEMENT note (to, from, heading, body)>
7. 实例:创建完整的DTD
让我们创建一个完整的DTD示例,用于描述图书信息。
7.1 DTD文件(book.dtd)
<!-- 图书DTD定义 --> <!-- 实体声明 --> <!ENTITY % commonElements "title | author | publisher | isbn | price"> <!-- 元素声明 --> <!ELEMENT bookstore (book+)> <!ELEMENT book (%commonElements;, description?, chapter*)> <!ELEMENT title (#PCDATA)> <!ELEMENT author (name, email?)> <!ELEMENT name (#PCDATA)> <!ELEMENT email (#PCDATA)> <!ELEMENT publisher (#PCDATA)> <!ELEMENT isbn (#PCDATA)> <!ELEMENT price (#PCDATA)> <!ELEMENT description (#PCDATA | emph | strong)*> <!ELEMENT chapter (title, content+)> <!ELEMENT content (#PCDATA | emph | strong)*> <!ELEMENT emph (#PCDATA)> <!ELEMENT strong (#PCDATA)> <!-- 属性声明 --> <!ATTLIST book id ID #REQUIRED category (fiction|non-fiction|technical) "fiction" language CDATA "en" edition CDATA "1" year CDATA #IMPLIED > <!ATTLIST chapter number CDATA #REQUIRED pages CDATA #IMPLIED > <!ATTLIST price currency (USD|EUR|GBP|JPY) "USD" >
7.2 XML文档(bookstore.xml)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE bookstore SYSTEM "book.dtd"> <bookstore> <book id="b1" category="fiction" language="en" edition="2" year="2020"> <title>The Great Novel</title> <author> <name>John Smith</name> <email>john@example.com</email> </author> <publisher>ABC Books</publisher> <isbn>123-4567890123</isbn> <price currency="USD">24.99</price> <description>A <emph>captivating</emph> story about <strong>adventure</strong> and discovery.</description> <chapter number="1" pages="25"> <title>The Beginning</title> <content>Once upon a time...</content> <content>In a land far away...</content> </chapter> <chapter number="2" pages="30"> <title>The Journey</title> <content>The hero sets out on a quest...</content> </chapter> </book> <book id="b2" category="technical" language="en"> <title>XML Programming</title> <author> <name>Jane Doe</name> </author> <publisher>Tech Press</publisher> <isbn>987-6543210987</isbn> <price currency="USD">49.99</price> <description>A comprehensive guide to <strong>XML</strong> and related technologies.</description> </book> </bookstore>
8. 验证XML文档
验证XML文档是否符合DTD定义是确保文档结构正确的重要步骤。有多种工具可以验证XML文档:
8.1 使用浏览器验证
现代浏览器(如Chrome、Firefox)可以加载XML文档并在有错误时显示错误信息。只需在浏览器中打开XML文件即可。
8.2 使用在线验证工具
有许多在线工具可以验证XML文档,如:
- https://www.xmlvalidation.com/
- https://www.freeformatter.com/xml-validator-xsd.html
8.3 使用编程语言验证
8.3.1 Java示例
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import java.io.File; public class DTDValidator { public static void main(String[] args) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); // 启用DTD验证 DocumentBuilder builder = factory.newDocumentBuilder(); // 设置错误处理器 builder.setErrorHandler(new org.xml.sax.ErrorHandler() { public void warning(SAXParseException e) throws SAXException { System.out.println("Warning: " + e.getMessage()); } public void error(SAXParseException e) throws SAXException { System.out.println("Error: " + e.getMessage()); } public void fatalError(SAXParseException e) throws SAXException { System.out.println("Fatal Error: " + e.getMessage()); throw e; } }); // 解析XML文档 builder.parse(new File("bookstore.xml")); System.out.println("XML文档验证通过!"); } catch (Exception e) { System.out.println("XML文档验证失败:" + e.getMessage()); } } }
8.3.2 Python示例
from xml.dom import minidom from xml.parsers.expat import ExpatError try: # 解析XML文档并验证DTD doc = minidom.parse("bookstore.xml") print("XML文档验证通过!") except ExpatError as e: print(f"XML文档验证失败:{e}") except Exception as e: print(f"发生错误:{e}")
9. DTD的优缺点
9.1 优点
- 简单易学:DTD语法相对简单,容易上手
- 广泛支持:几乎所有XML处理器都支持DTD验证
- 历史悠久:DTD是XML最早的验证机制,有丰富的使用经验
- 定义实体:DTD可以定义实体,提供文本替换功能
- 标准化:许多行业标准(如XHTML、SVG)都使用DTD
9.2 缺点
- 数据类型有限:DTD只支持有限的数据类型,无法定义更复杂的数据约束
- 语法不同:DTD使用不同于XML的语法,增加了学习成本
- 命名空间支持有限:DTD对XML命名空间的支持不够完善
- 不可扩展:DTD无法进行扩展或继承
- 文档结构限制:难以表达复杂的文档结构约束
10. DTD与XML Schema的比较
XML Schema是DTD的现代替代方案,提供了更强大的功能和更丰富的数据类型。以下是DTD与XML Schema的主要区别:
特性 | DTD | XML Schema |
---|---|---|
语法 | 非XML语法 | XML语法 |
数据类型 | 有限 | 丰富,支持自定义 |
命名空间 | 有限支持 | 完全支持 |
继承 | 不支持 | 支持 |
可扩展性 | 有限 | 高度可扩展 |
文档结构 | 简单 | 复杂但精确 |
实体定义 | 支持 | 不支持 |
10.1 XML Schema示例
与之前的book.dtd等效的XML Schema(book.xsd)示例:
<?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"> <xs:complexType> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="email" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="publisher" type="xs:string"/> <xs:element name="isbn" type="xs:string"/> <xs:element name="price" type="xs:decimal"/> <xs:element name="description" minOccurs="0"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="emph" type="xs:string"/> <xs:element name="strong" type="xs:string"/> </xs:choice> </xs:complexType> </xs:element> <xs:element name="chapter" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="title" type="xs:string"/> <xs:element name="content" maxOccurs="unbounded"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="emph" type="xs:string"/> <xs:element name="strong" type="xs:string"/> </xs:choice> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="number" type="xs:string" use="required"/> <xs:attribute name="pages" type="xs:string"/> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> <xs:attribute name="category" default="fiction"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="fiction"/> <xs:enumeration value="non-fiction"/> <xs:enumeration value="technical"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="language" type="xs:string" default="en"/> <xs:attribute name="edition" type="xs:string" default="1"/> <xs:attribute name="year" type="xs:string"/> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
11. DTD的实际应用
尽管XML Schema提供了更强大的功能,但DTD仍然在许多领域有广泛应用:
11.1 Web标准
许多Web标准使用DTD定义文档结构,如:
- XHTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- SVG:
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
11.2 企业数据交换
许多企业使用DTD定义XML文档结构,用于系统间的数据交换。例如,电子数据交换(EDI)系统常使用DTD验证交易文档。
11.3 出版行业
出版行业广泛使用DTD定义文档结构,如DocBook是一种使用DTD的技术文档标准。
11.4 配置文件
许多应用程序使用XML作为配置文件格式,并使用DTD验证配置文件的结构。
12. 学习DTD的最佳实践
12.1 从简单开始
学习DTD时,从简单的文档结构开始,逐步增加复杂性。先掌握基本的元素和属性声明,再学习更高级的特性。
12.2 实践验证
创建DTD后,使用验证工具检查XML文档是否符合DTD定义。这有助于理解DTD如何约束文档结构。
12.3 参考标准
研究现有的DTD标准,如XHTML或DocBook,学习它们如何定义文档结构。
12.4 工具辅助
使用专门的XML编辑器(如XMLSpy、 Oxygen XML Editor)可以简化DTD的创建和验证过程。
12.5 持续学习
DTD只是XML验证的一种方式,继续学习XML Schema和其他相关技术,如XPath、XSLT等,可以更全面地掌握XML技术栈。
13. 总结
DTD是XML文档验证的重要工具,通过定义文档的结构、元素和属性,确保XML文档符合预定义的规范。尽管XML Schema提供了更强大的功能,但DTD因其简单性和广泛支持,仍在许多领域有重要应用。
本文详细介绍了DTD的基本概念、语法结构、元素和属性声明、实体定义以及高级特性,并通过实际示例展示了如何创建和使用DTD。通过学习本文,您应该能够理解DTD的核心概念,并能够创建自己的DTD来验证XML文档。
无论您是XML新手还是有经验的开发者,掌握DTD都将帮助您更好地理解和处理XML文档,为您的项目带来更高的数据质量和互操作性。