# 使用 XML Schema 进行验证

> 原文： [https://docs.oracle.com/javase/tutorial/jaxp/dom/validating.html](https://docs.oracle.com/javase/tutorial/jaxp/dom/validating.html)

本节介绍 XML Schema 验证的过程。尽管 XML Schema 的完整处理超出了本教程的范围，但本节将向您介绍使用 XML Schema 定义验证 XML 文档的步骤。 （要了解有关 XML Schema 的更多信息，可以查看在线教程， [XML Schema Part 0：Primer](http://www.w3.org/TR/xmlschema-0/) 。在本节的最后，您还将学习如何使用 XML Schema 定义来验证文档包含来自多个名称空间的元素。

## 验证过程概述

要收到 XML 文档中验证错误的通知，必须满足以下条件：

*   必须配置工厂，并设置相应的错误处理程序。
*   该文档必须与至少一个模式相关联，甚至可能更多。

## 配置 `DocumentBuilder` Factory

首先定义配置工厂时将使用的常量是有帮助的。这些是使用 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` 方法来完成的，该方法是在 [Instantiate the Factory](readingXML.html) 中创建的。

```
// ...

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 兼容的解析器不支持名称空间，因此必须将架构验证的属性设置为有效。您还可以设置 factory 属性以指定要使用的解析器语言。 （另一方面，对于 SAX 解析，您在工厂生成的解析器上设置属性）。

## 将文档与模式相关联

既然程序已准备好使用 XML Schema 定义进行验证，则只需确保 XML 文档与（至少）一个相关联。有两种方法可以做到这一点：

*   使用 XML 文档中的模式声明
*   通过指定要在应用程序中使用的模式

* * *

**注 -** 当应用程序指定要使用的模式时，它会覆盖文档中的任何模式声明。

* * *

要在文档中指定模式定义，您可以像这样创建 XML：

`&lt; _documentRoot_ xmlns：xsi =“http://www.w3.org/2001/XMLSchema-instance”xsi：noNamespaceSchemaLocation =' _YourSchemaDefinition.xsd_ '&gt; [...]`

第一个属性定义 XML 名称空间（ `xmlns` ）前缀， `xsi` ，它代表“XML Schema instance”。第二行指定用于文档中没有名称空间前缀的元素的模式，即用于通常在任何简单，简单的 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 数据集。数据集可能包括来自纳税申报表的信息以及来自雇员招聘表的信息，其中两个元素在其各自的模式中名为。

如果为税收命名空间定义了前缀，并为招聘命名空间定义了另一个前缀，那么人事数据可能包括如下所示的段。

```
<employee id="...">
  <name>....</name>
  <tax:form>
     ...w2 tax form data...
  </tax:form>
  <hiring:form>
     ...employment history, etc....
  </hiring:form>
</employee>

```

`tax：form` 元素的内容显然不同于`招聘的内容：form` 元素，并且必须以不同方式进行验证。

另请注意，在此示例中，有一个默认命名空间，非限定元素名称 `employee` 和 `name` 属于。要正确验证文档，必须声明该命名空间的模式，以及`税`和`雇用`命名空间的模式。

* * *

**注 -** 默认命名空间实际上是一个特定的命名空间。它被定义为“没有名称的命名空间”。因此，您不能简单地在本周使用一个命名空间作为默认名称，而在以后使用另一个名称空间作为默这个“未命名的命名空间”（或“null 命名空间”）就像数字零。它没有任何价值可言（没有名字），但它仍然是精确定义的。因此，具有名称的命名空间永远不能用作默认命名空间。

* * *

解析时，只要声明了这些模式，数据集中的每个元素都将针对相应的模式进行验证。同样，模式可以声明为 XML 数据集的一部分，也可以声明在程序中。 （也可以混合声明。但是，一般来说，最好将所有声明放在一个地方。）

## 在 XML 数据集中声明模式

要声明用于数据集中前面示例的模式，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` 声明是您之前看到的，最后两个条目定义了名称空间前缀`税`和`雇佣`。新的是中间的条目，它定义了用于文档中引用的每个命名空间的模式的位置。

`xsi：schemaLocation` 声明由条目对组成，其中每对中的第一个条目是指定命名空间的完全限定 URI，第二个条目包含完整路径或模式定义的相对路径。通常，建议使用完全限定的路径。这样，只会存在一个模式副本。

请注意，在定义架构位置时，不能使用名称空间前缀。 `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);

```

这里，指向模式定义（ `.xsd` 文件）的字符串数组作为参数传递给 `factory.setAttribute` 方法。请注意与声明要用作 XML 数据集一部分的模式的区别。

*   默认（未命名）架构没有特殊声明。
*   您没有指定命名空间名称。相反，您只能指向 `.xsd` 文件。

为了进行命名空间分配，解析器读取 `.xsd` 文件，并在其中找到它们适用的目标命名空间的名称。由于文件是使用 URI 指定的，因此解析器可以使用 `EntityResolver` （如果已定义）来查找模式的本地副本。

如果架构定义未定义目标命名空间，则它将应用于默认（未命名或空）命名空间。因此，在我们的示例中，您可能希望在模式中看到这些目标名称空间声明：

*   一个指向架构 URI 的字符串
*   带有架构内容的 `InputStream`
*   SAX `输入源`
*   一份文件
*   一个对象数组，每个对象都是此处定义的类型之一

仅当模式语言能够在运行时组装模式时，才能使用对象数组。此外，当传递一个对象数组时，拥有两个共享相同名称空间的模式是非法的。

## 使用模式验证运行 `DOMEcho` 示例

要使用模式验证运行 `DOMEcho` 示例，请按照以下步骤操作。

1.  **导航至`样本`目录。** `％cd _install-dir_ `/ jaxp-1_4_2-` _ 释放日期 _ `/样品`。`
2.  **使用刚刚设置的类路径编译示例类。** `% javac dom/*`
3.  **Run the `DOMEcho` program on an XML file, specifying schema validation.**

    选择`数据`目录中的一个 XML 文件，并使用指定的 `-xsd` 选项运行 `DOMEcho` 程序。在这里，我们选择在文件 `personal-schema.xml` 上运行程序。

    `% java dom/DOMEcho -xsd data/personal-schema.xml`

    正如您在[配置工厂](readingXML.html#geswk)中看到的， `-xsd` 选项告诉 `DOMEcho` 对`个人模式中定义的 XML 模式执行验证.xml` 文件。在这种情况下，模式是文件 `personal.xsd` ，它也位于`样本/数据`目录中。

4.  **Open `personal-schema.xml` in a text editor and delete the schema declaration.**

    从开口`&lt; personnel&gt;中删除以下内容`标签。

    `xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation='personal.xsd'`

    不要忘记保存文件。

5.  **Run `DOMEcho` again, specifying the `-xsd` option once more.**`% java dom/DOMEcho -xsd data/personal-schema.xml`

    这一次，您将看到一系列错误。

6.  **Run `DOMEcho` one more time, this time specifying the `-xsdss` option and specifying the schema definition file.**

    正如您在[配置工厂](readingXML.html#geswk)中看到的， `-xsdss` 选项告诉 `DOMEcho` 对运行程序时指定的 XML 模式定义执行验证。再次使用文件 `personal.xsd` 。

    `% java dom/DOMEcho -xsdss data/personal.xsd data/personal-schema.xml`

    您将看到与以前相同的输出，这意味着已根据模式成功验证了 XML 文件。