在j2ee的世界中,配置文件是不可或缺的组成部分。对于绝大多数应用和框架来讲,最常用的配置文件的格式是xml。那么,在java中是如何读取和解析这些配置文件呢?
java操作xml文件的方式有多种,如jDom,Dom4j和jaxp等。在本文中,关于jaxp的背景和来历在本文中将不做过多复述,只是介绍jaxp读取xml的方法。
jaxp读取xml的代码实现是基于工厂模式,首先需要创建能够生成DocumentBuilder的工厂:DocumentBuilderFactory,可以通过为这个factory设置属性来控制生成的DocumentBuilder的特性和行为。有了DocumentBuilder,就可以读取xml文件,构建Document对象了。
具体的实例代码如下:
String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //设置使用schema来验证xml文件 factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE); factory.setValidating(true); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(new SchemaLoder()); //读取并解析xml文件,创建Document对象 Document doc = builder.parse(new File("config.xml"));
在读取xml文件之前,可以setValidating方法来指定是否对xml进行验证,如果不满足格式的xml可以不执行读取操作。比较常用的xml的格式验证方法有两种:DTD和schema。默认情况下,jaxp会使用DTD来验证xml文档,如果需要使用schema来验证,那么需要这行语句:factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
现在存在这样一个问题,xml的验证文件如何读取?即程序是如何定位到DTD或者是schema文件呢?答案在EntityResolver。可以通过实现这个借口来指明如何加载验证文件。下面是一个实例代码
class SchemaLoder implements EntityResolver { @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if (systemId.endsWith(".xsd")) { return new InputSource(SchemaLoder.class.getClassLoader() .getResourceAsStream("test.xsd")); } return null; } } }
实现了EntityResolver后,可以通过setEntityResolver方法来将其传递给builder。这样,builder就能够取得验证文件,先执行验证,通过验证后执行解析。
通过以上的一系列代码,取得了Document对象,这是xml文件的对象表示,那么如何解析这个Document对象呢?下面来分别看一下ibatis和spring是如何处理的。
首先来看一下ibatis,它解析Document的方法是基于策略模式,对于不同的xpath节点,有不同的解析方法。程序默认注册若干个解析策略,当程序读取xml后,遍历xml节点时,根据节点的xpath来取得相应的解析策略进行解析和处理。下面看一下ibatis解析节点的策略接口:
public interface Nodelet { void process (Node node) throws Exception; }
接口中的process方法的Node参数即为当前需要解析的节点,接口的实现中只需要关注当前节点的解析即可。
在Spring中,并没有采用ibatis这种策略模式来解析,而是在遍历document时直接进行解析,究其原因是spring的xml节点配置比较灵活,节点的嵌套方式也是多种多样,因此不能够像ibatis那样通过xpath来选择解析策略。
这两个框架解析xml的方式各不相同,但各自有各自的优点。ibatis解析xml的思路非常清晰,而且对于每个xml节点的解析方式都是一目了然的。但这种解析方式只能适合于xpath不多的情况,如果有过多的xpath需要解析,那么这种方式就不合适了。而spring的解析方式比较灵活,而且也容易扩展,缺点在于节点的解析过程与document的遍历过程融合在一起,不能够很清晰的看到整个xml解析的全貌。