这些Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
有关Java SE 9及其后续版本中更新的语言功能的摘要,请参阅Java语言变更。
有关所有JDK版本的新功能、增强功能和已删除或弃用选项的信息,请参阅JDK发布说明。
本节介绍了XML模式验证的过程。尽管XML模式的全面介绍超出了本教程的范围,但本节向您展示了使用XML模式定义验证XML文档的步骤。 (要了解有关XML模式的更多信息,可以查阅在线教程XML模式第0部分:入门。在本节的结尾,您还将学习如何使用XML模式定义验证包含多个命名空间的文档。
要在XML文档中收到验证错误的通知,必须满足以下条件:
首先,定义配置工厂时要使用的常量是有帮助的。这些常量与使用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元素的内容不同,因此需要分别进行验证。
还要注意,在这个示例中存在一个默认命名空间,未限定的元素名employee和name属于该命名空间。为了使文档能够正确验证,必须声明该命名空间的模式,以及tax和hiring命名空间的模式。
注意 - 默认命名空间实际上是一个特定的命名空间。它被定义为“没有名称的命名空间”。因此,您不能在本周将一个命名空间简单地用作默认命名空间,然后在以后将另一个命名空间用作默认命名空间。这个“未命名的命名空间”(或“空命名空间”)就像数字零一样。它没有任何实际价值(没有名称),但它仍然被明确定义。因此,具有名称的命名空间永远不能被用作默认命名空间。
解析时,数据集中的每个元素将根据相应的模式进行验证,只要这些模式已经声明。同样,模式可以作为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声明是您以前见过的,最后两个条目也是如此,它们定义了命名空间前缀tax和hiring。新的是中间的条目,它定义了文档中引用的每个命名空间所使用的模式的位置。
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示例,请按照以下步骤操作。
% cd install-dir/jaxp-1_4_2-release-date/samples
% javac dom/*
选择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。
从开始的<personnel>标记中删除以下内容。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation='personal.xsd'
不要忘记保存文件。
% java dom/DOMEcho -xsd data/personal-schema.xml
这次,您将看到一系列错误。
正如您在配置工厂中看到的那样,-xsdss选项告诉DOMEcho在运行程序时执行针对指定的XML模式定义的验证。再次使用文件personal.xsd。
% java dom/DOMEcho -xsdss data/personal.xsd data/personal-schema.xml
您将看到与之前相同的输出,这意味着XML文件已成功验证通过模式。