老读者都知道 Brett McLaughlin 对 SAX 情有独钟,对 DOM 则漠不关心。他尤其反感 Sun 公司对于 API 的做法,从之前将 API 封装在 JAXP(早期版本)之类的包中到近来在最新版的 Java™ 技术和 J2SE(Java 2 Platform, Standard Edition 1.2-1.4 )中几乎完全取代了这些 API。
对于刚接触 Java 和 XML 的程序员(或者通过 Sun 和 J2SE 才接触到 XML 的程序员)来说,都有必要简要回顾一下早期的 JAXP。那时,JAXP 是 Java 和 XML 领域中排行第三的 API,风靡程度仅次于 SAX(Simple API for XML)和 DOM(Document Object Model)。JAXP 的目标非常简单:使 SAX 和 DOM 的使用更加简单,尤其是在供应商中立领域。
最初,JAXP 的目的仅仅是向 SAX 和 DOM 提供便利性和供应商中立性。根据这一点,JAXP 从未想过要替代 SAX 或 DOM;事实上,JAXP 在其早期版本中拥有一些方法,getXMLReader()
和 getDOMParser()
就是其中的两个。 显而易见,这些方法的存在表明 JAXP 的作者希望 开发人员使用 JAXP,然后操作底层的 SAX 和 DOM 实现类。
还有一点值得注意,虽然 JAXP 在这些年中不断地加入大量的功能,但是这两个方法从未修改过。有的人会说这不过是出于向后兼容性的考虑,不过这确实反应了 JAXP 从未打算将 SAX 或 DOM 取而代之。JAXP 只不过是将它们封装起来,这样开发人员就不必使用大量特定于供应商的代码来调用 SAX 或 DOM了。
在早期的 Java 和 XML 编程中,存在大量 的 XML 解析器(最初的 Xerces 和 XML4J,Sun 公司的 Crimson,Oracle 公司的 XML 解析器,以及一些如今人们从未听过的解析器。)当我们编写一个与 XML 协作和交互的应用程序时,需要将 SAX 和 DOM API 连接到这些解析器实现,通常所使用的方法是将解析器类名告知 SAX 或 DOM,有点类似如下的方式:
Parser parser = new org.apache.xercers.parsers.SAXParser(); |
注意:我有意使用了较旧的 SAX Parser
接口;它是旧的 SAX 1 解析类,在 JAXP 成为问题的时期所有人都在使用它。
JAXP 引入了一个 javax.xml.parsers.SAXParserFactory
系统属性,它允许我们指定解析器工厂实现(工厂中提供了想要使用的解析器)。可以通过一个 System.setProperty()
系统属性指定工厂,也可以通过某些位置下的 jaxp.properties 文件来指定(本质上说,即应用程序类路径中的任何位置)。
无论采用何种方式指定这一属性 — 或者其对应的 DOM 属性 javax.xml.parsers.DocumentBuilderFactory
— 都需要避免在解析代码中出现任何类名。这也是 JAXP 存在的首要原因:防止将此类信息直接放入代码。可以通过改变属性值来方便地修改各种属性,或者甚至建立多个 jaxp.properties 文件用于不同的解析器实现,并且在需要时对它们进行切换。