科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道使用 JAXP 1.3 的新功能验证 XML2

使用 JAXP 1.3 的新功能验证 XML2

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

 JAXP 主要增加了新的验证 API,它提供了更好的交互性,支持 XML Schema 和 RELAX NG,能够在验证的同时即时修改。本文详细介绍这种新的 API,包括基本特性和更高级的特性。

作者:Brett McLaughlin 来源:IT专家网 2008年6月1日

关键字: XML 验证 JAXP java

  • 评论
  • 分享微博
  • 分享邮件
一旦得到了 Source 实现,就将其传递给工厂的 newSchema() 方法。返回的就是 Schema。现在,对文档进行验证就很简单了。请参阅清单 5。

  清单 5. 验证 XML

import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;

...

SchemaFactory schemaFactory =
      SchemaFactory.newInstance(XMLConstants.W3C_SCHEMA_NS_URI);
Source schemaSource = new StreamSource(new File("constraints.xml"));
Schema schema = schemaFactory.newSchema(schemaSource);

Validator validator = schema.newValidator();
validator.validate(new StreamSource("my-file.xml"));

  这里同样没有什么大的变化。只要知道要使用的类和调用的方法就很容易了。因为要进行验证,所以必须使用 Validator 类。可以使用 newValidator() 方法从 Schema 得到这个类的实例。最后可以调用 validate() 并再次传递 Source 实现,不过这一次它代表要解析和验证的 XML。

  调用该方法之后就会解析和验证目标 XML。要记住,即使用 DOMSource 提供 XML(解析过的 XML 表示),解析也可能再次发生。验证仍然和解析紧密联系在一起,因此验证过程需要一点儿时间。

  如果出现错误,就会抛出异常说明出了问题。JAXP 的多数实现都包括行号,有时候还有列号,帮助定位违反约束模型的位置。当然,仅仅抛出异常并不一定是解决问题的最佳方式。我将在 下一节 介绍一种更好的方法。

  看起来似乎工作不少:得到工厂,得到模式,得到验证器。让 JAXP 提供一个工厂方法来完成这一切是完全可能的,比方说 validate(Source schema, Source xmlDocument) 这样的方法。但是模块化有一定的好处,在 下一节 中将看到同时使用 Schema 和 Validator 类,可以解决 XML 处理中某些非常奇特的个别情况。而且如果确实需要可以自己编写,不妨当作一个很好的练习!

  深入了解验证

  对于很多应用程序来说,上面介绍的这些内容就足够了。您可以把输入文档和模式交给一个方法让它去验证。简单的 Exception 告诉您遇到了问题,甚至还提供了一些解决问题的基本信息。对于将 XML 作为数据格式的应用程序,可能仅仅是传递某些信息,关于 JAXP 的验证功能可能知道这些就足够了。

  但是,我们生活在一个到处都是 XML 编辑器、文件和代码生成器以及 Web 服务的世界中。对于这类应用程序,XML 就不仅仅起辅助作用,而 是 应用程序本身,基本的验证常常就不够了。对于这类应用程序,JAXP 提供了很多特性,这是下面要讨论的。

  处理错误

  首先,人们认为 Exception 表明发生了异常的行为。但是对于基于 XML 的应用程序而言,文件验证失败可能根本不是异常,仅仅可能的结果之一。比方说支持 XML 的编辑器或者 IDE。在这些环境中,无效的 XML 不应该造成系统崩溃和关闭。另外,如果只能以 Exception 形式报告错误 ,就过于沉重了。

  当然,对于 JAXP 老手这并不新鲜,您可能已经习惯为 SAXParser 或 DocumentBuilder 提供 org.xml.sax.ErrorHandler。这个接口提供的三个方法 warning()、error() 和 fatalError() 简化了解析中的错误处理。幸运的是,验证 XML 时也有相同的设施可用。更好的是,使用的还是同一个接口。正是如此,ErrorHandler 接口在验证中与在解析中一样有用。清单 6 提供了一个简单的例子。

  清单 6. 处理验证错误

import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;

import org.xml.sax.ErrorHandler;

...

SchemaFactory schemaFactory =
     SchemaFactory.newInstance(XMLConstants.W3C_SCHEMA_NS_URI);
Source schemaSource = new StreamSource(new File("constraints.xml"));
Schema schema = schemaFactory.newSchema(schemaSource);

Validator validator = schema.newValidator();
ErrorHandler mySchemaErrorHandler = new MySchemaErrorHandler();
validator.setErrorHandler(mySchemaErrorHandler);
validator.validate(new StreamSource("my-file.xml"));

  和 SAX 一样,可以使用该接口自定义错误的处理。从而让应用程序从容地退出验证、打印错误消息,甚至可以尝试从错误中恢复并继续验证。如果熟悉这个接口,完全不需要再重新学习!

装入多个模式

  某些很少见的情况下,可能需要从多个模式构造 Schema 对象。这有点儿费解;一个 Schema不是 对应一个模式或文件。相反,该对象表示一组约束。这些约束可以来一个文件,也可以来自多个文件。因此,可以通过 newSchema(Source[] sourceList) 为 newSchema() 方法提供一个 Source 实现数组(表示多个约束)。返回的仍然是一个 Schema 对象,表示所提供的模式的组合。

  可以预料,这种情况下会出现很多错误。因此建议为 SchemaFactory 设置 ErrorHandler。很多地方都可能出问题,因此要准备好在出现的时候解决问题。

  把验证集成到解析中

  到目前为止,我们一直把验证作为独立于解析的单独部分。但是并非必须如此。得到 Schema 对象后,就可以将其赋给 SAXParserFactory 或 DocumentBuilderFactory,都通过 setSchema() 方法(参见清单 7)。

  清单 7. 把验证集成到解析中

// Load up the document
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

// Set up an XML Schema validator, using the supplied schema
Source schemaSource = new StreamSource(new File(args[1]));
SchemaFactory schemaFactory = SchemaFactory.newInstance(
  XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaSource);

// Instead of explicitly validating, assign the Schema to the factory
factory.setSchema(schema);

// Parsers from this factory will automatically validate against the
//   associated schema
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File(args[0]));

  要注意,这里 不 需要使用 setValidating() 方法显式地打开验证。任何 Schema 不是 null 的工厂所创建的解析器都会使用那个 Schema 进行验证。可以预料,验证错误都会报告给解析器设置的 ErrorHandler。

  重要的警告

  虽然看起来不错,我认为还不够好,JAXP 的新验证 API 存在一些严重的问题。首先,即使在 Java 5.0 和 JAXP 1.3 正式版中,我也发现有很多错误和奇怪的行为。新的 API 仍然在增加解析器支持,这意味着个别情况(很少使用的特性)仅仅部分实现了(有时候根本没有实现)。我发现很多时候,能够通过独立验证器如 xmllint验证的文档却不能通过 JAXP 的验证。

  直接使用 Validator 类和 validate() 方法,与将 Schema 赋给 SAXParserFactory 或 DocumentBuilderFactory 相比,似乎更可靠。建议您采用比较保险的办法。我并不是要求您避开这种 API,而是说应该使用尽可能多的样本文档,并对验证结果检查两次,对错误处理要小心谨慎。

  结束语

  坦白地说,JAXP 验证 API 并没有明显的新东西。可以继续使用 SAX 或 DOM 解析和验证 XML,并结合 SAX 的 ErrorHandler 类,通过巧妙的编程也能对验证错误进行即时处理。但是这需要对 SAX 有充分的了解,需要很多时间去测试和调试并且仔细地管理内存(如果最终创建 DOM Document 对象的话)。这正是 JAXP 验证 API 闪光的地方。它提供了一种经过认真测试的、可以随时使用的解决方案,而不仅仅是是否启用模式验证的一个开关。它很容易与已有的 JAXP 代码结合在一起,增加模式验证非常简单。我相信,长期使用 XML 的 Java 开发人员一定会发现 JAXP 验证的一些优点。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章