使用 XMLPattern 进行验证
本节介绍 XML Schema 验证的过程。尽管对 XML Schema 的全面处理不在本教程的讨论范围之内,但是本节向您展示了使用 XML Schema 定义来验证 XML 文档所采取的步骤。 (要了解有关 XML Schema 的更多信息,可以查看在线教程XMLPattern 第 0 部分:入门。在本节的最后,您还将学习如何使用 XML Schema 定义来验证包含来自多个命名空间的元素的文档。
验证过程概述
要通知 XML 文档中的验证错误,必须满足以下条件:
-
必须配置工厂,并设置适当的错误处理程序。
-
该文档必须与至少一个架构关联,并且可能与更多架构关联。
配置 DocumentBuilder 工厂
首先定义在配置工厂时将使用的常量会很有帮助。这些常量与使用 XML Schema 进行 SAX 解析时定义的常量相同,它们在DOMEcho
示例程序的开头声明。
static final String JAXP_SCHEMA_LANGUAGE =
"http://java.sun.com/xml/jaxp/properties/schemaLanguage";
static final String W3C_XML_SCHEMA =
"http://www.w3.org/2001/XMLSchema";
接下来,您配置DocumentBuilderFactory
以生成可识别名称空间的,验证使用 XML Schema 的解析器。这是通过在_实例中创建的DocumentBuilderFactory
实例dbf
上调用setValidating
方法来完成的。
// ...
dbf.setNamespaceAware(true);
dbf.setValidating(dtdValidate || xsdValidate);
if (xsdValidate) {
try {
dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
}
catch (IllegalArgumentException x) {
System.err.println("Error: JAXP DocumentBuilderFactory attribute "
+ "not recognized: " + JAXP_SCHEMA_LANGUAGE);
System.err.println("Check to see if parser conforms to JAXP spec.");
System.exit(1);
}
}
// ...
因为默认情况下,与 JAXP 兼容的解析器不支持名称空间,所以必须设置属性以使架构验证起作用。您还设置了工厂属性以指定要使用的解析器语言。 (另一方面,对于 SAX 解析,可以在工厂生成的解析器上设置属性)。
将文档与架构相关联
现在,该程序已准备好使用 XML Schema 定义进行验证,仅需要确保 XML 文档与(至少)一个关联即可。有两种方法可以做到这一点:
-
在 XML 文档中带有 Pattern 声明
-
通过指定在应用程序中使用的 Pattern
注意- 当应用程序指定要使用的架构时,它将覆盖文档中的所有架构声明。
要在文档中指定架构定义,您将创建如下所示的 XML:
<documentRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation='YourSchemaDefinition.xsd'> [...]
第一个属性定义 XML 名称空间(xmlns
)前缀xsi
,它表示“ XMLPattern 实例”。第二行指定用于文档中没有命名空间前缀的元素的 Pattern,即,您通常在任何简单,不复杂的 XML 文档中定义的元素。 (在下一节中,您将看到如何处理多个名称空间.)
您还可以在应用程序中指定架构文件,DOMEcho
就是这种情况。
static final String JAXP_SCHEMA_SOURCE =
"http://java.sun.com/xml/jaxp/properties/schemaSource";
// ...
dbf.setValidating(dtdValidate || xsdValidate);
if (xsdValidate) {
// ...
}
if (schemaSource != null) {
dbf.setAttribute(JAXP_SCHEMA_SOURCE, new File(schemaSource));
}
在这里,您也可以使用一些机制来指定多个架构。接下来我们将看看这些。
验证多个命名空间
命名空间使您可以在同一文档中合并具有不同用途的元素,而不必担心名称重叠。
注意- 本节中讨论的内容也适用于使用 SAX 解析器时的验证。您在这里看到了它,因为到此为止,您已经了解了足够的有关名称空间的知识,从而使讨论有意义。
为了构想一个例子,考虑一个跟踪人员数据的 XML 数据集。数据集可能包含来自纳税申报表的信息以及来自雇员雇用表的信息,两个元素在各自的 Pattern 中均名为form
。
如果为税名称空间定义了前缀,而为雇用名称空间定义了另一个前缀,则人员数据可以包括如下所示的段。
<employee id="...">
<name>....</name>
<tax:form>
...w2 tax form data...
</tax:form>
<hiring:form>
...employment history, etc....
</hiring:form>
</employee>
tax:form
元素的内容显然与hiring:form
元素的内容不同,因此必须进行不同的验证。
还要注意,在此示例中,存在一个默认名称空间,该名称空间属于不合格的元素名称employee
和name
。为了正确验证文档,必须声明该命名空间的架构以及tax
和hiring
命名空间的架构。
注意- 默认名称空间实际上是一个特定的名称空间。它定义为“没有名称的命名空间”。因此,您不能简单地将一个名称空间用作本周的默认名称,而将另一名称空间用作稍后的默认名称。此“未命名名称空间”(或“空名称空间”)就像数字零。它没有任何价值可言(没有名字),但是它仍然是精确定义的。因此,具有名称的名称空间永远不能用作默认名称空间。
解析后,只要声明了这些 Pattern,就将根据适当的 Pattern 验证数据集中的每个元素。同样,可以将 Pattern 声明为 XML 数据集的一部分,也可以在程序中声明。 (也可以混合使用声明.但是,一般而言,将所有声明放在一个位置是一个好主意.)
在 XML 数据集中声明架构
要声明数据集中用于上述示例的 Pattern,XML 代码应类似于以下内容。
<documentRoot
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=
"employeeDatabase.xsd"
xsi:schemaLocation=
"http://www.irs.gov.example.com/
fullpath/w2TaxForm.xsd
http://www.ourcompany.example.com/
relpath/hiringForm.xsd"
xmlns:tax=
"http://www.irs.gov.example.com/"
xmlns:hiring=
"http://www.ourcompany.example.com/"
>
noNamespaceSchemaLocation
声明是您之前看到的,最后两个条目也是如此,它们定义了命名空间前缀tax
和hiring
。新增的是中间的条目,该条目定义了用于文档中引用的每个命名空间的架构的位置。
xsi:schemaLocation
声明由条目对组成,其中每对中的第一个条目是指定名称空间的标准 URI,第二个条目包含指向架构定义的完整路径或相对路径。通常,建议使用完全限定的路径。这样,将仅存在该 Pattern 的一个副本。
请注意,定义架构位置时不能使用名称空间前缀。 xsi:schemaLocation
声明仅理解名称空间名称,而不能理解前缀。
在应用程序中声明架构
要在应用程序中声明等效的架构,代码应类似于以下内容。
static final String employeeSchema = "employeeDatabase.xsd";
static final String taxSchema = "w2TaxForm.xsd";
static final String hiringSchema = "hiringForm.xsd";
static final String[] schemas = {
employeeSchema,
taxSchema,
hiringSchema,
};
static final String JAXP_SCHEMA_SOURCE =
"http://java.sun.com/xml/jaxp/properties/schemaSource";
// ...
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance()
// ...
factory.setAttribute(JAXP_SCHEMA_SOURCE, schemas);
在这里,指向 Pattern 定义的字符串 数组(\.xsd
个文件)作为参数传递给factory\.setAttribute
方法。请注意与声明 Pattern 用作 XML 数据集的一部分时的区别。
-
默认(未命名)架构没有特殊的声明。
-
您未指定名称空间名称。相反,您仅提供指向
\.xsd
文件的指针。
为了进行名称空间分配,解析器读取\.xsd
文件,并在其中找到它们要应用的目标名称空间的名称。因为文件是用 URI 指定的,所以解析器可以使用EntityResolver
(如果已定义)来查找 Pattern 的本地副本。
如果架构定义未定义目标名称空间,则它将应用于默认(未命名或空)名称空间。因此,在我们的示例中,您将期望在 Pattern 中看到这些目标名称空间声明:
-
指向架构 URI 的字符串
-
包含 Pattern 内容的
InputStream
-
SAX
InputSource
-
A File
-
对象数组,每个对象都是此处定义的类型之一
仅当 Pattern 语言具有在运行时组装 Pattern 的能力时,才能使用对象数组。另外,当传递对象数组时,拥有共享相同名称空间的两个 Pattern 是非法的。
使用架构验证运行 DOMEcho 示例
要使用架构验证运行DOMEcho
示例,请按照以下步骤操作。
-
导航到
samples
目录.% cd install-dir/jaxp-1_4_2-release-date/samples.
-
使用您刚刚设置的 Classpath 编译示例类.
% javac dom/*
-
在 XML 文件上运行
DOMEcho
程序,指定架构验证.
在data
目录中选择一个 XML 文件,并使用指定的\-xsd
选项在其上运行DOMEcho
程序。在这里,我们选择在文件personal\-schema\.xml
上运行程序。
% java dom/DOMEcho -xsd data/personal-schema.xml
如您在配置工厂中所见,\-xsd
选项告诉DOMEcho
对personal\-schema\.xml
文件中定义的 XMLPattern 执行验证。在这种情况下,架构是文件personal\.xsd
,该文件也位于sample/data
目录中。
- 在文本编辑器中打开
personal\-schema\.xml
并删除架构声明.
从开头的\<personnel\>
标记中删除以下内容。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation='personal.xsd'
不要忘记保存文件。
- 再次运行
DOMEcho
,再次指定\-xsd
选项.% java dom/DOMEcho -xsd data/personal-schema.xml
这次,您将看到一系列错误。
- 再运行
DOMEcho
次,这次指定\-xsdss
选项并指定架构定义文件.
如您在配置工厂中所见,\-xsdss
选项告诉DOMEcho
对在程序运行时指定的 XMLPattern 定义执行验证。再次使用文件personal\.xsd
。
% java dom/DOMEcho -xsdss data/personal.xsd data/personal-schema.xml
您将看到与以前相同的输出,这意味着已针对该 Pattern 成功验证了 XML 文件。