使用 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元素的内容不同,因此必须进行不同的验证。

还要注意,在此示例中,存在一个默认名称空间,该名称空间属于不合格的元素名称employeename。为了正确验证文档,必须声明该命名空间的架构以及taxhiring命名空间的架构。


注意- 默认名称空间实际上是一个特定的名称空间。它定义为“没有名称的命名空间”。因此,您不能简单地将一个名称空间用作本周的默认名称,而将另一名称空间用作稍后的默认名称。此“未命名名称空间”(或“空名称空间”)就像数字零。它没有任何价值可言(没有名字),但是它仍然是精确定义的。因此,具有名称的名称空间永远不能用作默认名称空间。


解析后,只要声明了这些 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声明是您之前看到的,最后两个条目也是如此,它们定义了命名空间前缀taxhiring。新增的是中间的条目,该条目定义了用于文档中引用的每个命名空间的架构的位置。

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选项告诉DOMEchopersonal\-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 文件。