文档

Java™教程
隐藏目录
使用XML模式进行验证
路径: Java XML处理API(JAXP)
课程: 文档对象模型

使用XML模式进行验证

本节介绍了XML模式验证的过程。尽管XML模式的全面介绍超出了本教程的范围,但本节向您展示了使用XML模式定义验证XML文档的步骤。 (要了解有关XML模式的更多信息,可以查阅在线教程XML模式第0部分:入门。在本节的结尾,您还将学习如何使用XML模式定义验证包含多个命名空间的文档。

验证过程概述

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

配置DocumentBuilder工厂

首先,定义配置工厂时要使用的常量是有帮助的。这些常量与使用XML模式进行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实例dbf上的setValidating方法,将其配置为生成一个命名空间感知的验证解析器,该解析器使用XML模式。

// ...

dbf.setNamespaceAware(true);
dbf.setValidating(dtdValidate || xsdValidate);

if (xsdValidate) {
    try {
        dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
    }
    catch (IllegalArgumentException x) {
        System.err.println("错误:JAXP DocumentBuilderFactory属性未被识别:" + JAXP_SCHEMA_LANGUAGE);
        System.err.println("检查解析器是否符合JAXP规范。");
        System.exit(1);
    }
}

// ...

因为JAXP兼容的解析器默认情况下不支持命名空间,所以必须设置模式验证的属性才能使其工作。您还设置了一个工厂属性以指定要使用的解析器语言。 (另一方面,对于SAX解析,您在工厂生成的解析器上设置一个属性)。

将文档与模式相关联

现在,程序准备好使用XML模式定义进行验证,只需确保XML文档与(至少)一个模式相关联即可。有两种方法可以做到这一点:


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


要在文档中指定模式定义,您可以创建如下的XML:

<文档根元素 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation='您的模式定义.xsd'> [...]

第一个属性定义了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数据集,用于跟踪人员数据。数据集可以包含来自纳税申报表以及雇员入职表的信息,两个元素的名称都是form

如果为税务命名空间定义了一个前缀,并为雇佣命名空间定义了另一个前缀,那么人员数据可以包括以下片段。

<employee id="...">
  <name>....</name>
  <tax:form>
     ...w2税表数据...
  </tax:form>
  <hiring:form>
     ...雇佣历史等....
  </hiring:form>
</employee>

tax:form元素的内容显然与hiring:form元素的内容不同,因此需要分别进行验证。

还要注意,在这个示例中存在一个默认命名空间,未限定的元素名employeename属于该命名空间。为了使文档能够正确验证,必须声明该命名空间的模式,以及taxhiring命名空间的模式。


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


解析时,数据集中的每个元素将根据相应的模式进行验证,只要这些模式已经声明。同样,模式可以作为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声明是您以前见过的,最后两个条目也是如此,它们定义了命名空间前缀taxhiring。新的是中间的条目,它定义了文档中引用的每个命名空间所使用的模式的位置。

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文件,并在其中找到它们适用的目标命名空间的名称。因为文件是通过URI指定的,所以解析器可以使用EntityResolver(如果已定义)来找到模式的本地副本。

如果模式定义没有定义目标命名空间,则它适用于默认(未命名或null)命名空间。因此,在我们的示例中,您可以在模式中看到这些目标命名空间声明:

只有在模式语言具有在运行时组装模式的能力时,才能使用对象数组。而且,当传递一个对象数组时,禁止具有共享相同命名空间的两个模式。

使用模式验证运行DOMEcho示例

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

  1. 导航到samples目录。% cd install-dir/jaxp-1_4_2-release-date/samples
  2. 使用刚设置的类路径编译示例类。% javac dom/*
  3. 在一个XML文件上运行DOMEcho程序,指定模式验证。

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

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

    正如您在配置工厂中看到的那样,-xsd选项告诉DOMEcho对在personal-schema.xml文件中定义的XML模式执行验证。在这种情况下,模式是位于sample/data目录中的文件personal.xsd

  4. 在文本编辑器中打开personal-schema.xml并删除模式声明。

    从开始的<personnel>标记中删除以下内容。

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

    不要忘记保存文件。

  5. 再次运行DOMEcho,再次指定-xsd选项。% java dom/DOMEcho -xsd data/personal-schema.xml

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

  6. 再次运行DOMEcho,这次指定-xsdss选项并指定模式定义文件。

    正如您在配置工厂中看到的那样,-xsdss选项告诉DOMEcho在运行程序时执行针对指定的XML模式定义的验证。再次使用文件personal.xsd

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

    您将看到与之前相同的输出,这意味着XML文件已成功验证通过模式。


上一页:将XML数据读入DOM
下一页:更多信息