B.3. 验证

B.3.1. 为什么要验证您的文档

LDP 使用许多脚本来分发您的文档。这些脚本将您的文档提交到 LDP 的 CVS(一个免费的文档版本管理系统),然后将您的文档转换为用户可以阅读的其他格式。您的文档还将在全球多个站点上镜像(另一组脚本)。

为了使这些脚本正常工作,您的文档必须是“结构良好”且使用“有效标记”结构良好意味着您的文档遵循 XML 期望的规则:它符合 XML 语法规则。有效标记意味着您只使用对您的文档“有效”的元素或标签:应用 XML 词汇规则。

如果您的文档结构不良好或使用无效标记,脚本将无法处理它。因此,您修改后的文档将不会被分发。

NoteDocbook 章节
 

DocBook 章节中有关于如何验证您的文档的更多信息。查看B.3 节,以获得更多关于验证文档的帮助。

B.3.2. 轻松验证方法

在您已经很艰难的生活中,不必再为了查看是否可以通过验证而安装全套工具。您可以将原始 XML 文件上传到网站,然后访问http://validate.sf.net,输入您的文档 URL,然后进行验证。

Note外部实体
 

当此信息添加到作者指南时,外部实体尚不受支持。如果您遇到问题,请按照 Validate 网站上提供的说明进行操作。

B.3.3. 进阶验证方法

B.3.3.1. 目录

XML 和 SGML 文件包含您所需的大部分信息;但是,有时存在特定于 SGML 的实体。为了将这些实体与其真实值匹配,您需要使用目录。目录的作用是告诉您的系统在哪里找到它正在查找的文件。您可以将目录视为工具的指南(或地图)。

大多数发行版(至少 Red Hat/Fedora 和 Debian)对于主 SGML 目录文件都有一个通用位置,称为/etc/sgml/catalog。在过去,它也可能位于/usr/lib/sgml/catalog.

XML 目录文件的结构与 SGML 目录文件的结构不同。关于定制目录的部分(参见B.3.4 节)将更详细地介绍这些文件实际包含的内容。

如果您的系统找不到目录文件,或者您正在使用自定义目录文件,则可能需要设置SGML_CATALOG_FILESXML_CATALOG_FILES环境变量。使用 echo $SGML_CATALOG_FILES,检查它当前是否已设置。如果返回空行,则表示该变量尚未设置。使用相同的命令来查看是否XML_CATALOG_FILES也已设置。如果变量未设置,请使用以下示例立即设置它们。

示例 B-1. 设置 SGML_CATALOG_FILES 和 XML_CATALOG_FILES 环境变量

bash$ export SGML_CATALOG_FILES="/etc/sgml/catalog"

要使此更改永久生效,您可以将以下行添加到您的~/.bashrc文件。

SGML_CATALOG_FILES="/etc/sgml/catalog"
export SGML_CATALOG_FILES

如果您通过 RedHat 或 Debian 软件包安装了 XML 工具,则可能不需要执行此步骤。如果您正在使用自定义 XML 目录,则肯定需要执行此操作。下一节将详细介绍自定义目录。为了确保我的备份脚本抓取此自定义文件,我已将其添加到名为“docbook”的 home 目录的子目录中。

bash$ export XML_CATALOG_FILES="/home/user/docbook/db-catalog.xml"

您也可以更改您的.bashrc文件,如果您想保存这些更改。

XML_CATALOG_FILES="/home/user/docbook/db-catalog.xml"
export XML_CATALOG_FILES

如果您要将更改添加到您的.bashrc文件,您将不会看到更改,直到您打开一个新的终端窗口。要使更改在当前终端中立即生效,请“source”配置文件。

B.3.4. 创建和修改目录

在前一节中,我提到目录就像您工具的指南。具体来说,目录将来自公共标识符的规则映射到您系统的文件。

在每个 DocBook(或实际上每个 XML)文件的顶部,都有一个 DOCTYPE,它告诉处理工具它将要处理的文档类型。此声明至少将包括一个公共标识符,例如-//OASIS//DTD DocBook V4.2//EN。此公共标识符有许多部分,全部由//分隔。它包含以下信息:ISO 标准(如果有)(--- 在这种情况下没有 ISO 标准),作者 (OASIS),文档类型 (DTD DocBook V4.2),语言 (English)。您的 DOCTYPE 也可能包含 URL。

公共标识符对于处理工具来说是无用的,因为它需要能够访问实际的 DTD。如果处理工具处于脱机状态,则 URL 是无用的。为了帮助您的处理器处理这些问题,您可以下载所有必要的文件,然后使用目录为您的处理工具“映射”它们。

如果您正在使用 SGML 处理工具(例如 Jade),您将需要一个 SGML 目录。如果您正在使用 XML 处理工具(如 XSLT),您将需要一个 XML 目录。两者都包含在内。

B.3.4.1. SGML 目录

示例 B-2. SGML 目录的示例

                                                           (1)
-- Catalog for the Conectiva Styles -- 

OVERRIDE YES
                                                          (2)
PUBLIC "-//Conectiva SA//DTD DocBook Conectiva variant V1.0//EN" 
			"/home/ldp/styles/books.dtd"

DELEGATE "-//OASIS"
        	"/home/ldp/SGML/dtds/catalog.dtd"
                                                          (3)
DOCTYPE BOOK /home/ldp/SGML/dtds/docbook/db31/docbook.dtd
 
-- EOF -- 
        
(1)
注释。注释以 “--” 开头,并持续到行尾。
(2)
公共类型关联"-//Conectiva SA//DTD books V1.0//EN"与文件books.dtd位于目录/home/ldp/styles.
(3)
表示文件结尾的注释。

如上例所示,要将标识符与文件关联,只需按照显示的顺序操作

  1. 复制标识符 PUBLIC

  2. 输入标识文本

  3. 指示关联文件的路径

B.3.4.1.1. 用于目录的实用命令

目录中最常用的映射是

PUBLIC

关键字PUBLIC将公共标识符映射到系统上的标识符。

SYSTEM

关键字SYSTEM将系统标识符映射到系统上的文件。

SYSTEM "http://nexus.conectiva/utilidades/publicacoes/livros.dtd" "publicacoes/livros.dtd"

SGMLDECL

关键字SGMLDECL指定应使用的 SGML 语句的系统标识符。

SGMLDECL "publishings/books.dcl"

DTDDECL

类似于SGMLDECL关键字DTDDECL标识应使用的 SGML 语句。DTDDECL将语句与公共标识符关联到 DTD。不幸的是,可用的开源工具不支持此关联。可以通过使用多个目录文件在某种程度上实现此语句的好处。

DTDDECL "-//Conectiva SA//DTD livros V1.0//EN" "publicacoes/livros.dcl"

CATALOG

关键字CATALOG允许在一个目录中包含另一个目录。这是一种利用多个不同目录而无需更改它们的方法。

OVERRIDE

关键字OVERRIDE告知标识符是否优先于系统标识符。大多数系统上的标准是系统标识符优先于公共标识符。

DELEGATE

关键字DELEGATE允许将目录与特定类型的公共标识符关联。该子句DELEGATECATALOG非常相似,除了它在指定特定模式之前什么都不做。

DOCTYPE

如果文档以文档类型开头,但没有公共标识符和系统标识符,则子句DOCTYPE将此文档与特定的 DTD 关联。

B.3.4.2. XML 目录

以下示例目录由 Martin A. Brown 提供。

示例 B-3. 示例 XML 目录文件

<?xml version="1.0"?>
<!DOCTYPE catalog PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
          "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
    
	<public publicId="-//OASIS//DTD DocBook XML V4.2//EN"
       uri="/home/mabrown/docbook/dtds/4.2/docbookx.dtd"/>
   <uri name="http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
       uri="/home/mabrown/docbook/dtds/4.2/docbookx.dtd"/>
   <uri name="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"
       uri="/home/mabrown/docbook/xsl/xhtml/docbook.xsl"/>
   <uri name="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"
       uri="/home/mabrown/docbook/xsl/xhtml/chunk.xsl"/>
   <uri name="http://docbook.sourceforge.net/release/xsl/current/xhtml/profile-chunk.xsl"
       uri="/home/mabrown/docbook/xsl/xhtml/profile-chunk.xsl"/>
</catalog>

B.3.5. 验证 XML

B.3.5.1. nsgmls

您可以使用 nsgmls,它是 jade 套件的一部分(在 Debian 上,使用 apt-get 获取 docbook-utils 软件包,请参阅B.4.2 节),来验证 SGML 或 XML 文档。

bash$ nsgmls -s HOWTO.xml

如果没有问题,您将只返回命令提示符。以下-s告诉 nsgmls 仅显示错误。

Tip找不到函数
 

如果您收到关于找不到函数的错误,或者关于 ISO 字符没有权威来源的错误,您可能需要将 nsgmls 指向您的xml.dcl文件。对于 Red Hat 9,它看起来像这样:nsgmls -s /usr/share/sgml/xml.dcl HOWTO.xml

有关使用 Jade/OpenJade 处理文件的更多信息,请阅读使用 OpenJade 处理 DocBook XML/SGML

B.3.5.2. onsgmls

这是 nsgmls 的替代方案。它随 OpenJade 软件包一起提供。与 nsgmls 相比,此程序提供了更多选项,并允许您在尝试验证 XML 文件(而不是 SGML 文件)时,可以静默地忽略许多出现的问题。这也意味着您不必每次都输入您的xml.dcl文件的位置。

我能够简单地使用以下命令来验证文件,其中只有与我的标记错误相关的错误消息。

bash$ onsgmls -s HOWTO.xml

根据 Bob Stayton 的说法,您还可以关闭特定的错误消息。以下示例关闭特定于 XML 的错误消息。

bash$ onsgmls -s -wxml -wno-explicit-sgml-decl HOWTO.xml

B.3.5.3. xmllint

您还可以使用 xmllint 命令行工具(来自 libxml2 软件包)来验证您的文档。此工具对标签的完整性以及所有打开的标签是否也都再次关闭进行简单检查。默认情况下,xmllint 将输出结果树。因此,如果您的文档一直输出到最后一行,您就知道没有与标签不匹配、打开和关闭错误等相关的严重错误。

要防止将整个文档打印到屏幕上,请添加--noout参数。

bash$ xmllint --noout HOWTO.xml

如果没有任何返回,则您的文档不包含语法错误。否则,从报告的第一个错误开始。修复该错误,然后再次在您的文档上运行该工具。如果它仍然返回输出,则再次修复您看到的第一个错误,不要理会其余的错误,因为进一步的错误通常是由于第一个错误引起的。

如果您想检查您的文档中是否存在特定于您的文档类型定义的任何错误,请添加--valid.

bash$ xmllint --noout --valid HOWTO.xml

xmllint 工具也可用于检查 XML 目录中的错误,有关如何设置此行为的更多信息,请参阅 man 手册。

如果您是 Mac OSX 或 Windows 用户,您可能还想查看 tkxmllint,它是 xmllint 的 GUI 版本。更多信息请访问:http://tclxml.sourceforge.net/tkxmllint.html

示例 B-4. 使用 xmllint 的调试示例

下面的示例展示了如何使用 xmllint 来检查您的文档。我创建了一些作为 XML 初学者常犯的错误。起初,文档无法通过,并显示错误

bash$ xmllint ldp-history.xml
ldp-history.xml:22: error: Opening and ending tag mismatch: articlinfo line 6 and articleinfo
</articleinfo>
              ^
ldp-history.xml:37: error: Opening and ending tag mismatch: listitem line 36 and orderedlist
</orderedlist>
              ^
ldp-history.xml:39: error: Opening and ending tag mismatch: orderedlist line 34 and sect2
</sect2>
        ^
ldp-history.xml:46: error: Opening and ending tag mismatch: sect1 line 41 and para
for many authors to contribute their part in their area of specialization.</para
                                                                               ^
ldp-history.xml:57: error: Opening and ending tag mismatch: para line 55 and sect1
</sect1>
        ^
ldp-history.xml:59: error: Opening and ending tag mismatch: sect2 line 31 and article
</article>
          ^
ldp-history.xml:61: error: Premature end of data in tag sect1 line 24
 
^
ldp-history.xml:61: error: Premature end of data in tag article line 5
 
^

现在,正如我们已经提到的,除了第一个错误之外,不要担心任何事情。第一个错误表明文件第 6 行和第 22 行的标签之间存在不一致。实际上,在第 6 行,我们遗漏了 “articleinfo” 中的 “e”。修复错误,然后再次运行 xmllint。现在的第一个抱怨是关于有问题的第 37 行,其中忘记了列表项的结束标签。修复错误并再次运行验证工具,直到所有错误都消失。最常见的错误包括忘记打开或关闭段落标签、标签中的拼写错误以及混乱的节。