|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
XML(可扩展标记语言)是一种用于存储和传输数据的标记语言,它以其自描述性、灵活性和可扩展性而被广泛应用于各种领域。为了确保XML文档的结构符合预期,文档类型定义(DTD)作为一种验证机制被引入。DTD定义了XML文档的结构、元素关系以及元素属性,为XML文档提供了结构化的验证框架。本文将深入解析DTD中的属性定义机制,探讨其在XML文档结构验证中的实际应用,并提供常见问题的解决方案。
DTD文档类型定义概述
DTD(Document Type Definition,文档类型定义)是XML文档的结构定义规范,它定义了XML文档中允许出现的元素、元素之间的关系、元素可以包含的属性以及属性的类型和默认值等。DTD最早是从SGML(Standard Generalized Markup Language)继承而来的,是XML1.0标准的一部分。
DTD的基本结构包括元素声明和属性声明。元素声明定义了XML文档中可以出现的元素及其内容模型,而属性声明则定义了元素可以具有的属性及其特性。DTD可以通过内部子集直接嵌入XML文档中,也可以作为外部文件独立存在,通过URI引用。
内部DTD示例:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE library [
- <!ELEMENT library (book+)>
- <!ELEMENT book (title, author+, publisher, year, price?)>
- <!-- 其他元素和属性声明 -->
- ]>
- <library>
- <!-- XML内容 -->
- </library>
复制代码
外部DTD示例:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE library SYSTEM "library.dtd">
- <library>
- <!-- XML内容 -->
- </library>
复制代码
DTD中的属性定义机制
在DTD中,属性定义使用ATTLIST声明来完成。其基本语法如下:
- <!ATTLIST element-name attribute-name attribute-type default-value>
复制代码
其中:
• element-name是要定义属性的元素名称
• attribute-name是属性的名称
• attribute-type是属性的类型,决定了属性可以接受的值
• default-value是属性的默认值,可以是具体的默认值、#REQUIRED、#IMPLIED或#FIXED
属性类型详解
属性类型在DTD中有多种选择,主要包括:
1. CDATA:字符数据,属性值可以是任意字符串<!ATTLIST book
title CDATA #REQUIRED>
2. ID:唯一标识符,属性值在文档中必须是唯一的<!ATTLIST book
id ID #REQUIRED>
3. IDREF:引用文档中其他元素的ID<!ATTLIST chapter
bookId IDREF #REQUIRED>
4. IDREFS:多个ID引用,用空格分隔<!ATTLIST collection
bookIds IDREFS #REQUIRED>
5. NMTOKEN:名称标记,属性值必须是有效的XML名称<!ATTLIST book
edition NMTOKEN "1">
6. NMTOKENS:多个名称标记,用空格分隔<!ATTLIST book
keywords NMTOKENS "fiction classic">
7. ENTITY:实体引用<!ATTLIST book
cover ENTITY #IMPLIED>
8. ENTITIES:多个实体引用,用空格分隔<!ATTLIST book
images ENTITIES #IMPLIED>
9. - NOTATION:符号引用<!ATTLIST book
- format NOTATION (pdf|epub|mobi) #IMPLIED>
复制代码 10. - 枚举类型:使用括号括起来的可选值列表<!ATTLIST book
- category (fiction|non-fiction|biography) "fiction">
复制代码
CDATA:字符数据,属性值可以是任意字符串
- <!ATTLIST book
- title CDATA #REQUIRED>
复制代码
ID:唯一标识符,属性值在文档中必须是唯一的
- <!ATTLIST book
- id ID #REQUIRED>
复制代码
IDREF:引用文档中其他元素的ID
- <!ATTLIST chapter
- bookId IDREF #REQUIRED>
复制代码
IDREFS:多个ID引用,用空格分隔
- <!ATTLIST collection
- bookIds IDREFS #REQUIRED>
复制代码
NMTOKEN:名称标记,属性值必须是有效的XML名称
- <!ATTLIST book
- edition NMTOKEN "1">
复制代码
NMTOKENS:多个名称标记,用空格分隔
- <!ATTLIST book
- keywords NMTOKENS "fiction classic">
复制代码
ENTITY:实体引用
- <!ATTLIST book
- cover ENTITY #IMPLIED>
复制代码
ENTITIES:多个实体引用,用空格分隔
- <!ATTLIST book
- images ENTITIES #IMPLIED>
复制代码
NOTATION:符号引用
- <!ATTLIST book
- format NOTATION (pdf|epub|mobi) #IMPLIED>
复制代码
枚举类型:使用括号括起来的可选值列表
- <!ATTLIST book
- category (fiction|non-fiction|biography) "fiction">
复制代码
属性默认值设置
默认值设置有四种方式:
1. #REQUIRED:属性必须提供<!ATTLIST book
id ID #REQUIRED>
2. #IMPLIED:属性是可选的<!ATTLIST book
author CDATA #IMPLIED>
3. #FIXED value:属性有固定值,不能更改<!ATTLIST book
language CDATA #FIXED "en">
4. - default-value:属性的默认值,如果未提供则使用此值<!ATTLIST book
- available (true|false) "true">
复制代码
#REQUIRED:属性必须提供
- <!ATTLIST book
- id ID #REQUIRED>
复制代码
#IMPLIED:属性是可选的
- <!ATTLIST book
- author CDATA #IMPLIED>
复制代码
#FIXED value:属性有固定值,不能更改
- <!ATTLIST book
- language CDATA #FIXED "en">
复制代码
default-value:属性的默认值,如果未提供则使用此值
- <!ATTLIST book
- available (true|false) "true">
复制代码
完整属性定义示例
以下是一个完整的属性定义示例:
- <!ATTLIST book
- id ID #REQUIRED
- title CDATA #REQUIRED
- author CDATA #IMPLIED
- category (fiction|non-fiction|biography) "fiction"
- edition NMTOKEN "1"
- available (true|false) "true"
- language CDATA #FIXED "en">
复制代码
在这个例子中,我们为”book”元素定义了多个属性:
• “id”属性是ID类型,必须提供
• “title”属性是CDATA类型,必须提供
• “author”属性是CDATA类型,可选
• “category”属性是枚举类型,只能是”fiction”、”non-fiction”或”biography”之一,默认为”fiction”
• “edition”属性是NMTOKEN类型,默认为”1”
• “available”属性是枚举类型,只能是”true”或”false”,默认为”true”
• “language”属性是CDATA类型,固定值为”en”
DTD在XML文档结构验证中的实际应用
让我们通过一个完整的例子来展示DTD在XML文档结构验证中的实际应用。假设我们要创建一个图书目录的XML文档,并使用DTD来验证其结构。
创建带有DTD的XML文档
首先,我们定义DTD(内部DTD):
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE library [
- <!ELEMENT library (book+)>
- <!ELEMENT book (title, author+, publisher, year, price?)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT publisher (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
-
- <!ATTLIST book
- id ID #REQUIRED
- category (fiction|non-fiction|biography) "fiction"
- available (true|false) "true">
- ]>
复制代码
然后,我们创建符合此DTD的XML文档:
- <library>
- <book id="b1" category="fiction" available="true">
- <title>The Great Gatsby</title>
- <author>F. Scott Fitzgerald</author>
- <publisher>Scribner</publisher>
- <year>1925</year>
- <price>12.99</price>
- </book>
- <book id="b2" category="non-fiction">
- <title>A Brief History of Time</title>
- <author>Stephen Hawking</author>
- <publisher>Bantam Books</publisher>
- <year>1988</year>
- </book>
- </library>
复制代码
在这个例子中,DTD定义了”library”元素必须包含一个或多个”book”元素,每个”book”元素必须包含”title”、”author”(一个或多个)、”publisher”和”year”元素,以及可选的”price”元素。此外,”book”元素有三个属性:”id”(必须且唯一)、”category”(枚举类型,默认为”fiction”)和”available”(枚举类型,默认为”true”)。
验证过程和工具
要验证XML文档是否符合DTD,可以使用各种工具:
1. - XML解析器:大多数XML解析器都支持DTD验证Java示例代码:
- “`java
- import javax.xml.parsers.DocumentBuilder;
- import javax.xml.parsers.DocumentBuilderFactory;
- import org.xml.sax.SAXException;
- import org.w3c.dom.Document;
- import java.io.File;
- import java.io.IOException;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(org.xml.sax.SAXParseException e) throws SAXException {
- System.out.println("Warning: " + e.getMessage());
- }
- public void error(org.xml.sax.SAXParseException e) throws SAXException {
- System.out.println("Error: " + e.getMessage());
- }
- public void fatalError(org.xml.sax.SAXParseException e) throws SAXException {
- System.out.println("Fatal Error: " + e.getMessage());
- throw e;
- }
- });
- // 解析并验证XML文档
- Document document = builder.parse(new File("library.xml"));
- System.out.println("XML文档验证成功!");
- } catch (Exception e) {
- System.out.println("XML文档验证失败: " + e.getMessage());
- e.printStackTrace();
- }
- }}
- “`
复制代码 2. - Java示例代码:
- “`java
- import javax.xml.parsers.DocumentBuilder;
- import javax.xml.parsers.DocumentBuilderFactory;
- import org.xml.sax.SAXException;
- import org.w3c.dom.Document;
- import java.io.File;
- import java.io.IOException;
复制代码 3. 在线验证工具:如xmlvalidation.com、freeformatter.com等只需将XML内容粘贴到网页上,选择DTD验证,即可获得验证结果
4. 只需将XML内容粘贴到网页上,选择DTD验证,即可获得验证结果
5. IDE支持:如Eclipse、IntelliJ IDEA等IDE内置XML验证功能在IDE中打开XML文件,如果文档不符合DTD,IDE会实时显示错误
6. 在IDE中打开XML文件,如果文档不符合DTD,IDE会实时显示错误
7. 命令行工具:如xmllint(Linux系统自带)xmllint --valid --noout library.xml
XML解析器:大多数XML解析器都支持DTD验证
• - Java示例代码:
- “`java
- import javax.xml.parsers.DocumentBuilder;
- import javax.xml.parsers.DocumentBuilderFactory;
- import org.xml.sax.SAXException;
- import org.w3c.dom.Document;
- import java.io.File;
- import java.io.IOException;
复制代码
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(org.xml.sax.SAXParseException e) throws SAXException {
- System.out.println("Warning: " + e.getMessage());
- }
- public void error(org.xml.sax.SAXParseException e) throws SAXException {
- System.out.println("Error: " + e.getMessage());
- }
- public void fatalError(org.xml.sax.SAXParseException e) throws SAXException {
- System.out.println("Fatal Error: " + e.getMessage());
- throw e;
- }
- });
- // 解析并验证XML文档
- Document document = builder.parse(new File("library.xml"));
- System.out.println("XML文档验证成功!");
- } catch (Exception e) {
- System.out.println("XML文档验证失败: " + e.getMessage());
- e.printStackTrace();
- }
- }
复制代码
}
“`
在线验证工具:如xmlvalidation.com、freeformatter.com等
• 只需将XML内容粘贴到网页上,选择DTD验证,即可获得验证结果
IDE支持:如Eclipse、IntelliJ IDEA等IDE内置XML验证功能
• 在IDE中打开XML文件,如果文档不符合DTD,IDE会实时显示错误
命令行工具:如xmllint(Linux系统自带)
- xmllint --valid --noout library.xml
复制代码
行业应用案例
DTD在实际行业中有广泛的应用:
1. - 出版业:定义书籍、期刊等出版物的结构<!ELEMENT book (front, body, back?)>
- <!ELEMENT front (title, author?, abstract?)>
- <!ELEMENT body (chapter+)>
- <!ELEMENT chapter (title, section+)>
- <!ELEMENT section (title, p+)>
- <!ELEMENT p (#PCDATA | emphasis | footnote)*>
复制代码 2. - 金融业:定义财务报表、交易记录等文档的格式<!ELEMENT transaction (id, date, amount, description, parties)>
- <!ELEMENT parties (sender, receiver)>
- <!ELEMENT sender (name, account)>
- <!ELEMENT receiver (name, account)>
- <!ATTLIST transaction
- type (debit|credit) #REQUIRED
- status (pending|completed|failed) "pending">
复制代码 3. - 政府:定义法规、公文等文档的标准格式<!ELEMENT regulation (header, body, amendments?)>
- <!ELEMENT header (title, number, date, authority)>
- <!ELEMENT body (section+)>
- <!ELEMENT section (title, subsection*)>
- <!ATTLIST regulation
- id ID #REQUIRED
- effectiveDate CDATA #REQUIRED>
复制代码 4. - Web技术:XHTML使用DTD来定义文档结构<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
复制代码
出版业:定义书籍、期刊等出版物的结构
- <!ELEMENT book (front, body, back?)>
- <!ELEMENT front (title, author?, abstract?)>
- <!ELEMENT body (chapter+)>
- <!ELEMENT chapter (title, section+)>
- <!ELEMENT section (title, p+)>
- <!ELEMENT p (#PCDATA | emphasis | footnote)*>
复制代码
金融业:定义财务报表、交易记录等文档的格式
- <!ELEMENT transaction (id, date, amount, description, parties)>
- <!ELEMENT parties (sender, receiver)>
- <!ELEMENT sender (name, account)>
- <!ELEMENT receiver (name, account)>
- <!ATTLIST transaction
- type (debit|credit) #REQUIRED
- status (pending|completed|failed) "pending">
复制代码
政府:定义法规、公文等文档的标准格式
- <!ELEMENT regulation (header, body, amendments?)>
- <!ELEMENT header (title, number, date, authority)>
- <!ELEMENT body (section+)>
- <!ELEMENT section (title, subsection*)>
- <!ATTLIST regulation
- id ID #REQUIRED
- effectiveDate CDATA #REQUIRED>
复制代码
Web技术:XHTML使用DTD来定义文档结构
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
复制代码
常见问题及解决方案
在使用DTD进行XML文档验证时,可能会遇到各种问题。以下是一些常见问题及其解决方案:
1. 语法错误及修正
问题:DTD声明中的语法错误是最常见的问题之一,如缺少分号、括号不匹配等。
示例错误:
- <!ATTLIST book
- id ID #REQUIRED
- title CDATA #REQUIRED
- author CDATA #IMPLIED
- category (fiction|non-fiction|biography "fiction">
复制代码
问题分析:在”category”属性定义中,缺少右括号。
解决方案:
- <!ATTLIST book
- id ID #REQUIRED
- title CDATA #REQUIRED
- author CDATA #IMPLIED
- category (fiction|non-fiction|biography) "fiction">
复制代码
验证代码示例:
- import javax.xml.parsers.DocumentBuilder;
- import javax.xml.parsers.DocumentBuilderFactory;
- import org.xml.sax.ErrorHandler;
- import org.xml.sax.SAXException;
- import org.xml.sax.SAXParseException;
- import org.w3c.dom.Document;
- import java.io.StringReader;
- import org.xml.sax.InputSource;
- public class DTDSyntaxErrorDemo {
- public static void main(String[] args) {
- String xmlWithDTD = "<?xml version="1.0" encoding="UTF-8"?>\n" +
- "<!DOCTYPE library [\n" +
- " <!ELEMENT library (book+)>\n" +
- " <!ELEMENT book (title, author)>\n" +
- " <!ELEMENT title (#PCDATA)>\n" +
- " <!ELEMENT author (#PCDATA)>\n" +
- " <!ATTLIST book\n" +
- " id ID #REQUIRED\n" +
- " category (fiction|non-fiction|biography "fiction">\n" + // 故意缺少右括号
- "]>\n" +
- "<library>\n" +
- " <book id="b1">\n" +
- " <title>The Great Gatsby</title>\n" +
- " <author>F. Scott Fitzgerald</author>\n" +
- " </book>\n" +
- "</library>";
-
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setValidating(true);
- DocumentBuilder builder = factory.newDocumentBuilder();
-
- builder.setErrorHandler(new ErrorHandler() {
- public void warning(SAXParseException e) throws SAXException {
- System.out.println("警告: " + e.getMessage());
- }
-
- public void error(SAXParseException e) throws SAXException {
- System.out.println("错误: " + e.getMessage());
- System.out.println("行: " + e.getLineNumber() + ", 列: " + e.getColumnNumber());
- }
-
- public void fatalError(SAXParseException e) throws SAXException {
- System.out.println("致命错误: " + e.getMessage());
- System.out.println("行: " + e.getLineNumber() + ", 列: " + e.getColumnNumber());
- throw e;
- }
- });
-
- Document document = builder.parse(new InputSource(new StringReader(xmlWithDTD)));
- System.out.println("XML文档验证成功!");
- } catch (Exception e) {
- System.out.println("XML文档验证失败: " + e.getMessage());
- }
- }
- }
复制代码
2. 命名冲突问题
问题:在大型XML文档或多个DTD组合使用时,可能会出现元素或属性名称冲突。
示例场景:
- <!-- DTD 1 -->
- <!ELEMENT book (title, author)>
- <!ELEMENT title (#PCDATA)>
- <!-- DTD 2 -->
- <!ELEMENT book (title, publisher)>
- <!ELEMENT title (#PCDATA)>
复制代码
问题分析:两个DTD都定义了”book”和”title”元素,但内容模型不同,导致冲突。
解决方案:
• 使用命名空间(虽然DTD本身对命名空间的支持有限)
• 重命名元素或属性以避免冲突
• 合并DTD,统一元素定义
重命名解决方案示例:
- <!-- 合并后的DTD -->
- <!ELEMENT library (book+)>
- <!ELEMENT book (title, author, publisher)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT publisher (#PCDATA)>
复制代码
3. 复杂结构定义挑战
问题:DTD的表达能力有限,难以定义复杂的结构,如元素顺序的灵活组合、数据类型的精确限制等。
示例场景:想要定义一个”person”元素,可以包含”name”和”age”元素,但顺序可以任意。
问题分析:DTD不支持无序的内容模型,只能使用固定的顺序或选择。
解决方案:
• 使用多个选择组合,如:<!ELEMENT person ((name, age) | (age, name))>
• 考虑使用XML Schema(XSD)替代DTD,它提供了更强大的表达能力
使用多个选择组合,如:
- <!ELEMENT person ((name, age) | (age, name))>
复制代码
考虑使用XML Schema(XSD)替代DTD,它提供了更强大的表达能力
XML Schema替代方案示例:
- <?xml version="1.0" encoding="UTF-8"?>
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:element name="person">
- <xs:complexType>
- <xs:all>
- <xs:element name="name" type="xs:string"/>
- <xs:element name="age" type="xs:positiveInteger"/>
- </xs:all>
- </xs:complexType>
- </xs:element>
- </xs:schema>
复制代码
4. DTD的局限性及替代方案
问题:DTD有一些固有的局限性,如不支持数据类型、不支持命名空间、表达能力有限等。
解决方案:
1. - XML Schema(XSD):提供了更强大的数据类型支持、命名空间支持和更复杂的结构定义能力<?xml version="1.0" encoding="UTF-8"?>
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:element name="book">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="title" type="xs:string"/>
- <xs:element name="author" type="xs:string"/>
- <xs:element name="price" type="xs:decimal"/>
- </xs:sequence>
- <xs:attribute name="id" type="xs:ID" use="required"/>
- <xs:attribute name="category" use="optional" default="fiction">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value="fiction"/>
- <xs:enumeration value="non-fiction"/>
- <xs:enumeration value="biography"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- </xs:schema>
复制代码 2. - RELAX NG:另一种XML验证语言,语法更简洁,表达能力更强<?xml version="1.0" encoding="UTF-8"?>
- <grammar xmlns="http://relaxng.org/ns/structure/1.0">
- <start>
- <element name="book">
- <attribute name="id">
- <text/>
- </attribute>
- <optional>
- <attribute name="category">
- <choice>
- <value>fiction</value>
- <value>non-fiction</value>
- <value>biography</value>
- </choice>
- </attribute>
- </optional>
- <element name="title">
- <text/>
- </element>
- <element name="author">
- <text/>
- </element>
- <optional>
- <element name="price">
- <text/>
- </element>
- </optional>
- </element>
- </start>
- </grammar>
复制代码 3. - Schematron:基于规则的验证语言,可以表达更复杂的业务规则<?xml version="1.0" encoding="UTF-8"?>
- <schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
- <title>Book Validation Rules</title>
- <pattern>
- <rule context="book">
- <assert test="@category = 'fiction' or @category = 'non-fiction' or @category = 'biography'">
- Category must be one of: fiction, non-fiction, biography
- </assert>
- <assert test="number(price) > 0">
- Price must be a positive number
- </assert>
- <assert test="string-length(title) > 0">
- Title must not be empty
- </assert>
- </rule>
- </pattern>
- </schema>
复制代码
XML Schema(XSD):提供了更强大的数据类型支持、命名空间支持和更复杂的结构定义能力
- <?xml version="1.0" encoding="UTF-8"?>
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:element name="book">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="title" type="xs:string"/>
- <xs:element name="author" type="xs:string"/>
- <xs:element name="price" type="xs:decimal"/>
- </xs:sequence>
- <xs:attribute name="id" type="xs:ID" use="required"/>
- <xs:attribute name="category" use="optional" default="fiction">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value="fiction"/>
- <xs:enumeration value="non-fiction"/>
- <xs:enumeration value="biography"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- </xs:schema>
复制代码
RELAX NG:另一种XML验证语言,语法更简洁,表达能力更强
- <?xml version="1.0" encoding="UTF-8"?>
- <grammar xmlns="http://relaxng.org/ns/structure/1.0">
- <start>
- <element name="book">
- <attribute name="id">
- <text/>
- </attribute>
- <optional>
- <attribute name="category">
- <choice>
- <value>fiction</value>
- <value>non-fiction</value>
- <value>biography</value>
- </choice>
- </attribute>
- </optional>
- <element name="title">
- <text/>
- </element>
- <element name="author">
- <text/>
- </element>
- <optional>
- <element name="price">
- <text/>
- </element>
- </optional>
- </element>
- </start>
- </grammar>
复制代码
Schematron:基于规则的验证语言,可以表达更复杂的业务规则
- <?xml version="1.0" encoding="UTF-8"?>
- <schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
- <title>Book Validation Rules</title>
- <pattern>
- <rule context="book">
- <assert test="@category = 'fiction' or @category = 'non-fiction' or @category = 'biography'">
- Category must be one of: fiction, non-fiction, biography
- </assert>
- <assert test="number(price) > 0">
- Price must be a positive number
- </assert>
- <assert test="string-length(title) > 0">
- Title must not be empty
- </assert>
- </rule>
- </pattern>
- </schema>
复制代码
最佳实践和高级技巧
在使用DTD进行XML文档验证时,以下是一些最佳实践和高级技巧:
1. 模块化设计
将大型DTD拆分为多个模块,通过参数实体引用来组合,提高可维护性。
- <!-- 主DTD文件 -->
- <!ENTITY % common-elements SYSTEM "common-elements.dtd">
- %common-elements;
- <!ENTITY % book-elements SYSTEM "book-elements.dtd">
- %book-elements;
- <!ELEMENT library (book+)>
复制代码- <!-- common-elements.dtd -->
- <!ENTITY % boolean "(true|false)">
- <!ENTITY % id-type "ID">
- <!ENTITY % text-type "CDATA">
复制代码- <!-- book-elements.dtd -->
- <!ELEMENT book (title, author+, publisher, year, price?)>
- <!ELEMENT title (#PCDATA)>
- <!ELEMENT author (#PCDATA)>
- <!ELEMENT publisher (#PCDATA)>
- <!ELEMENT year (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
- <!ATTLIST book
- id %id-type; #REQUIRED
- category (fiction|non-fiction|biography) "fiction"
- available %boolean; "true">
复制代码
2. 使用参数实体
参数实体可以提高DTD的重用性和灵活性。
- <!ENTITY % boolean "(true|false)">
- <!ATTLIST book
- available %boolean; "true">
-
- <!ATTLIST magazine
- inStock %boolean; "true">
复制代码
3. 条件包含
使用参数实体和条件包含来创建可配置的DTD。
- <!ENTITY % include.optional "INCLUDE">
- <![%include.optional;[
- <!ELEMENT price (#PCDATA)>
- <!ATTLIST book
- hasPrice %boolean; "true">
- ]>
复制代码
使用时,可以通过改变参数实体的值来控制是否包含某些声明:
- <!ENTITY % include.optional "IGNORE">
复制代码
4. 文档注释
在DTD中添加详细的注释,提高可读性和可维护性。
- <!--
- 图书目录DTD
- 版本: 1.0
- 日期: 2023-05-20
- 描述: 定义图书目录XML文档的结构
-
- 元素:
- - library: 根元素,包含一个或多个book元素
- - book: 表示一本书,包含title、author、publisher、year和可选的price元素
- - title: 书名
- - author: 作者,可以有多个
- - publisher: 出版社
- - year: 出版年份
- - price: 价格,可选
-
- 属性:
- - book@id: 书的唯一标识符,必须提供
- - book@category: 书的类别,可以是fiction、non-fiction或biography,默认为fiction
- - book@available: 是否可用,可以是true或false,默认为true
- -->
复制代码
5. 版本控制
为DTD添加版本信息,便于管理和更新。
- <!ENTITY % version "1.0">
- <!ENTITY % last-updated "2023-05-20">
- <!--
- 图书目录DTD
- 版本: %version;
- 最后更新: %last-updated;
- -->
复制代码
6. 验证工具集成
将DTD验证集成到构建过程和开发工作流中,确保文档质量。
Maven集成示例:
- <project>
- <!-- ... -->
- <build>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>xml-maven-plugin</artifactId>
- <version>1.0.2</version>
- <executions>
- <execution>
- <goals>
- <goal>validate</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <validationSets>
- <validationSet>
- <dir>src/main/resources/xml</dir>
- <includes>
- <include>**/*.xml</include>
- </includes>
- <validating>true</validating>
- </validationSet>
- </validationSets>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <!-- ... -->
- </project>
复制代码
7. 渐进式验证
对于大型XML文档,考虑使用渐进式验证策略,先验证基本结构,再验证细节。
- import javax.xml.parsers.DocumentBuilder;
- import javax.xml.parsers.DocumentBuilderFactory;
- import org.xml.sax.ErrorHandler;
- import org.xml.sax.SAXException;
- import org.xml.sax.SAXParseException;
- import org.w3c.dom.Document;
- import org.w3c.dom.Element;
- import org.w3c.dom.NodeList;
- import java.io.File;
- public class ProgressiveValidation {
- public static void main(String[] args) {
- try {
- // 第一阶段:基本结构验证
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setValidating(true);
- DocumentBuilder builder = factory.newDocumentBuilder();
-
- builder.setErrorHandler(new ErrorHandler() {
- public void warning(SAXParseException e) {
- System.out.println("警告: " + e.getMessage());
- }
-
- public void error(SAXParseException e) throws SAXException {
- System.out.println("错误: " + e.getMessage());
- }
-
- public void fatalError(SAXParseException e) throws SAXException {
- System.out.println("致命错误: " + e.getMessage());
- throw e;
- }
- });
-
- Document document = builder.parse(new File("library.xml"));
- System.out.println("第一阶段验证通过:基本结构正确");
-
- // 第二阶段:业务规则验证
- NodeList books = document.getElementsByTagName("book");
- for (int i = 0; i < books.getLength(); i++) {
- Element book = (Element) books.item(i);
- String id = book.getAttribute("id");
- String category = book.getAttribute("category");
-
- // 检查ID是否唯一
- for (int j = i + 1; j < books.getLength(); j++) {
- Element otherBook = (Element) books.item(j);
- if (id.equals(otherBook.getAttribute("id"))) {
- System.out.println("错误:ID '" + id + "' 不是唯一的");
- }
- }
-
- // 检查特定类别的书籍是否有价格
- if ("non-fiction".equals(category)) {
- NodeList prices = book.getElementsByTagName("price");
- if (prices.getLength() == 0) {
- System.out.println("警告:非虚构类书籍 '" + id + "' 没有价格信息");
- }
- }
- }
-
- System.out.println("第二阶段验证通过:业务规则检查完成");
- } catch (Exception e) {
- System.out.println("验证失败: " + e.getMessage());
- e.printStackTrace();
- }
- }
- }
复制代码
结论
DTD作为XML文档结构验证的重要工具,尽管有其局限性,但在许多场景下仍然是一个简单有效的选择。通过深入理解DTD中的属性定义机制,我们可以更好地定义XML文档的结构,确保数据的一致性和有效性。
在实际应用中,我们需要根据具体需求选择合适的验证技术。对于简单的文档结构,DTD可能是一个轻量级且易于维护的选择;而对于复杂的业务规则和数据类型约束,XML Schema、RELAX NG或Schematron可能更为适合。
无论选择哪种技术,遵循最佳实践都是至关重要的。模块化设计、参数实体的使用、详细的文档注释以及验证工具的集成,都可以提高DTD的质量和可维护性。同时,渐进式验证策略可以帮助我们更有效地处理大型XML文档的验证工作。
随着XML技术的发展,虽然出现了更强大的替代方案,但DTD凭借其简单性和广泛支持,在特定领域仍然具有重要价值。通过本文的介绍,希望读者能够深入理解DTD中的属性定义机制,掌握其在XML文档结构验证中的实际应用,并能够有效解决常见问题,从而更好地利用DTD来确保XML文档的质量和一致性。 |
|