`
cuijiemin
  • 浏览: 265347 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Geronimo 叛逆者: 使用集成软件包:Codehaus 的 Woodstox

阅读更多

转自:http://www.ibm.com/developerworks/cn/opensource/os-ag-renegade15/

XML 的重要性

XML 是由 Tim Bray 和 Michael Sperberg-McQueen 于 1996 年引入的。它的潜力已获得广泛公认,但是很难想象那时候会有哪个人能够知道 XML 会成为怎样的一种主要技术。企业 Java 开发人员将使用 XML 用于配置、用作数据存储以及最常见的是用作数据交换的格式。它是 Web 服务和 SOAP 的基础,从而也是现代面向服务的架构(Service-Oriented Architecture,SOA)设计模式的基础。但是 XML 并没有止步在那里。它将 X 融入 Ajax 或 Asynchronous JavaScript + XML 中,成为现代 Web 应用程序能够提供前所未有的丰富体验的关键。

但是,XML 也不是包治百病的灵丹妙药;它也有不足之处。XML 文档往往都很大。XML 文档都有通用树结构,但是这些 XML 文档的可扩展性意味着它的模式可以千变万化。这些方面向高效解析 XML 提出了挑战。克服 XML 解析挑战的传统方法有两种:DOM 和 SAX。

XML 处理:DOM 和 SAX

DOM 和 SAX 是解析 XML 的两种典型策略。它们在许多方面都是性质对立的策略。DOM 将为 XML 文档提供一个简单的对象模型。DOM 解析器将把 XML 文档转换成表示文档中所有数据的易于使用的对象。但是,这样如实地表示 XML 文档需要付出一定的代价:DOM 解析往往需要占用很多内存。

内存对 SAX 来说不是问题。SAX 解析器将生成一系列解析事件。注册这些事件的回调并随后对来自这些事件的数据执行某种逻辑都由 handler 来完成。它快速且高效,但是要求有复杂的编程模型。

了解使用 DOM 与 SAX 之间差异的最简单方法 —— 并且因而了解 StAX 的动机和优点 —— 是查看具体示例。





回页首


使用 Flickr 解析示例

找到一些 XML 来解析并不难。到处都在使用 XML。现在的大多数 Web 站点都提供了某种基于 XML 的 Web 服务。Flickr 是归 Yahoo 所有的一个流行的照片分享站点,它拥有强大而灵活的 API。让我们来看一看访问 Flickr 的 “有趣” 照片的一些简单代码(要获得本文中使用的所有源代码,请参阅 下载,并确保把 Woodstox 放入类路径中或者使用 JDK 1.6)。代码如清单 1 所示:


清单 1. 使用 Flickr API

                String apiKey = "c4579586f41a90372f762cb65c78be5d";
String urlStr = "http://api.flickr.com/services/rest/?" + 
"method=flickr.interestingness.getList&per_page=20&api_key="+apiKey;
URL request = new URL(urlStr);
InputStream input = request.openStream();

这段代码将使用 Flickr 的代表性状态传输(Representational State Transfer,REST)API(有关 Flickr 的 API 和 REST 格式的更多信息,请参阅 参考资料 部分)。以上调用的一些样例输出如清单 2 所示:


清单 2. Flickr 的 XML

                <?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<photos page="1" pages="25" per_page="20" total="500">
     <photo id="469774979" owner="35373726@N00" secret="c8a1be2012" server="183" 
farm="1" title="Where will it lead me......?" ispublic="1" isfriend="0" 
isfamily="0" />
     <photo id="470281793" owner="73955226@N00" secret="49612a2794" server="212" 
farm="1" title="Island Beauty" ispublic="1" isfriend="0" isfamily="0" />
     <photo id="469808244" owner="43568064@N00" secret="26b71544a3" server="227" 
farm="1" title="" ispublic="1" isfriend="0" isfamily="0" />
</photos>
</rsp>

注意清单 2 只显示了三张照片。API 调用实际上将返回 20(URL 字符串中的 per_page 参数)。结果十分简单,因此来看一看如何解析这个 XML。在示例中,将解析出每张照片的标题及其 ID。该 ID 可用于创建该照片的 URL,因此不难想象 Web 应用程序(可能是 mashup)只使用此信息。首先需要使用 DOM 来提取此数据。





回页首


DOM 示例

要使用 DOM,需要把文档解析成文档对象。这是表示已被解析的 XML 文档的内存中树结构。随后遍历 DOM 树来查找每张照片的标题和 ID。将此数据放入简单映射中。完成此过程的代码如清单 3 所示:


清单 3. 用 DOM 进行解析

                Map<String,String> map = new HashMap<String,String>();
DocumentBuilder builder =    DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document dom = builder.parse(input);
Element root = dom.getDocumentElement();
NodeList childNodes = root.getChildNodes();
Node photosNode = null;
for (int i=0;i<childNodes.getLength();i++){
     Node node = childNodes.item(i);
     if (node.getNodeName().equalsIgnoreCase("photos")){
          photosNode = node;
          break;
     }
}
childNodes = photosNode.getChildNodes();
for (int i=0;i<childNodes.getLength();i++){
     Node node = childNodes.item(i);
     if (node.getNodeName().equalsIgnoreCase("photo")){
          String title = node.getAttributes().getNamedItem("title").getTextContent();
          String id = node.getAttributes().getNamedItem("id").getTextContent();
          map.put(id,title);
     }
}

DOM 十分流行,因为它非常易于使用。只需将输入源传入解析器中,然后解析器将为您提供 document 对象。然后,您可以遍历子节点,直至找到照片节点。每个照片节点都是照片节点的子节点,因此您将遍历每个照片节点,然后访问每个照片节点的 titleid 属性并将其存储到映射中。

但是,DOM 也有一些明显的效率低下之处。您要存储大量的可能并不关心的数据,例如每张照片的所有者。您还将浏览所有数据两次:第一次浏览用于将其读入文档对象,然后在遍历文档对象时进行第二次浏览。避免这些效率低下之处的传统方法是使用 SAX。





回页首


SAX 示例

SAX 解析器并不像 DOM 解析器一样返回一个精密的 document 对象。相反,SAX 解析器将在遍历 XML 文档时给出一系列事件。必须通过实现接口或者扩展 DefaultHandler 类并根据需要重写它的方法,创建这些事件的 handler。清单 4 将演示 Flickr XML 文档的 SAX 解析。


清单 4. 用 SAX 进行解析

                SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
DefaultHandler handler = new DefaultHandler(){
     @Override
     public void startElement(String uri, String localName, 
     String qName, Attributes attributes) throws SAXException {
          if (qName.equalsIgnoreCase("photo")){
               String title = attributes.getValue("title");
               String id = attributes.getValue("id");
               // map is static so we can access it here
               map.put(id, title);
          }
     }
};
parser.parse(input, handler);

很明显,清单 4 中所示的代码比 清单 3 中的 DOM 代码难于理解一些。您需要使用 ContentHandler 来处理 SAX 事件,因此创建了 DefaultHandler 并重写了它的 startElement 回调方法。查看它是不是一个照片元素,并且如果是照片元素,则访问它的 titleid 属性。

代码十分简洁并且在运行时非常高效。它仅存储您所关心的数据,并且只遍历文档一次。它是更为复杂的代码,要求扩展类才能注册事件侦听程序。如果能够高效地解析 XML 而且可以使用更直观的编程模型那就太好了。StAX 于是应运而生。





回页首


StAX 备选方案

SAX 中的复杂度来自它实现的 Observer 设计模式。它是一个 push 模型,因为解析器将把事件 push 到随后作用于事件的 observer 中。StAX 模型类似于 SAX。它将来自 XML 文档的数据和事件流线化,使其可以像 SAX 一样快速且高效。最大的不同之处是它使用 pull 模型。这将允许应用程序代码从解析器中 pull 事件。

这可能听起来像是一个细微的差异,但是它将允许使用更简单的编程模型。查阅清单 5 以查看 StAX 的运作。


清单 5. 用 StAX 进行解析

                Map<String,String> map = new HashMap<String,String>();
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
QName qId = new QName("id");
QName qTitle = new QName("title");
QName qPhoto = new QName("photo");
XMLEventReader  reader = inputFactory.createXMLEventReader(input);
while (reader.hasNext()){
     XMLEvent event = reader.nextEvent();
     if (event.isStartElement()){
          StartElement element = event.asStartElement();
          if (element.getName().equals(qPhoto)){
               String id = element.getAttributeByName(qId).getValue();
               String title = element.getAttributeByName(qTitle).getValue();
               map.put(id,title);
          }
     }
}
reader.close();

首先,您不必扩展任何类。那是因为您无需为事件进行注册。使用 StAX,您可以控制事件流,因为将从解析器中 pull 这些事件流。您可以使用一种熟悉的类似迭代器的语法来搜索整个文档以查找所需的数据。您仍将只存储所需的数据,并且只需浏览 XML 文档一次。您将获得与使用 SAX 时一样的效率,但是代码将直观得多。





回页首


使用 Woodstox 作为 Geronimo 的 StAX 提供程序

现在您已经看到了 StAX 解析的优点。它被广泛公认为 XML 技术中的重大进步。因而,当它成为 Java EE 5 规范的一部分时并不令人惊讶(它甚至还包含在 Java Platform, Standard Edition [Java SE] 6 中)。由于它是 Java EE 5 的一部分,因此它必须由 Geronimo 2.0 来实现。

Geronimo 团队十分幸运,有若干个开源 StAX 实现可供选择。团队选取了 Woodstox 作为 Geronimo 所附带的 StAX 解析器。Woodstox 被视为执行效果最佳的 StAX 实现之一(要比较各种 StAX 解析器,请参阅 参考资料)。此外,Woodstox 是在 Lesser General Public License (LGPL) 和 Apache 2.0 许可下双重授权的。因此您可以不受任何限制地将 Woodstox 及其源代码集成到 Geronimo 中。

应用程序性能调优:发挥 Woodstox 的最大功效

性能很明显是 Woodstox 带给 Geronimo 的优点之一。就像使用其他高性能技术一样,了解如何使用 Woodstox 才能获得最佳性能非常重要。清单 5 中的代码将使用 XMLEventReader 接口,这是 StAX 规范包含的一个高级 API。用于获得高性能的较低级 API 是 XMLStreamReader 接口。清单 6 显示了使用此接口的 StAX 解析器。


清单 6. 用 XMLStreamReader 进行 StAX 解析

                Map<String,String> map = new HashMap<String,String>();
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
QName qId = new QName("id");
QName qTitle = new QName("title");
QName qPhoto = new QName("photo");
XMLStreamReader reader = inputFactory.createXMLStreamReader(input);
while (reader.hasNext()){
    int event = reader.next();
    if (event == START_ELEMENT){ // statically included constant from XMLStreamConstants
         if (reader.getName().equals(qPhoto)){
               String id = reader.getAttributeValue(null, qId.getLocalPart());
               String title = reader.getAttributeValue(null, qTitle.getLocalPart());
               map.put(id,title);
          }
     } 
}
reader.close();

清单 6 中的代码类似于 清单 5 中的代码;虽然它很明显有些低级,但是您将获得很大的性能提高。

结束语

您已经了解了使用 StAX 解析器解析 XML 文档的一些优点。StAX 在 SAX 与 DOM 之间提供了很好的折衷。您可以通过使用它作为 Geronimo 2.0 的一部分立即利用 StAX。您不但将开始使用 StAX 的直观 pull API,而且将获得在 Woodstox 中使用 StAX 的高性能实现的额外优势。

分享到:
评论

相关推荐

    geronimo-config:Apache Geronimo配置

    Java SE和EE的配置 地位 MicroProfile Config规范的实现。 基本原理 许多项目工件(例如WAR,EAR)仅应创建一次,然后在不同的客户,阶段等安装,它们需要针对那些不同的执行环境,而无需进行任何重新包装。...

    geronimo-jta_1.0.1B_spec-1.0.1.jar

    java运行依赖jar包

    geronimo-repices:用CodeSandbox创建

    【标题】"geronimo-repices:用CodeSandbox创建" 涉及到的知识点主要集中在使用CodeSandbox这个在线代码编辑器来开发JavaScript项目。CodeSandbox是一款非常流行的Web应用程序,它允许开发者在浏览器中编写、运行和...

    geronimo-javamail_1.4_spec-1.7.1.jar

    geronimo-javamail_1.4_spec-1.7.1.jar

    geronimo-annotation_1.0_spec-1.1.1-API文档-中文版.zip

    赠送jar包:geronimo-annotation_1.0_spec-1.1.1.jar; 赠送原API文档:geronimo-annotation_1.0_spec-1.1.1-javadoc.jar; 赠送源代码:geronimo-annotation_1.0_spec-1.1.1-sources.jar; 赠送Maven依赖信息文件:...

    geronimo-jta-1.1-spec-1.1.1-API文档-中文版.zip

    赠送jar包:geronimo-jta_1.1_spec-1.1.1.jar; 赠送原API文档:geronimo-jta_1.1_spec-1.1.1-javadoc.jar; 赠送源代码:geronimo-jta_1.1_spec-1.1.1-sources.jar; 赠送Maven依赖信息文件:geronimo-jta_1.1_spec...

    geronimo-jcache_1.0_spec-1.0-alpha-1-API文档-中文版.zip

    赠送jar包:geronimo-jcache_1.0_spec-1.0-alpha-1.jar; 赠送原API文档:geronimo-jcache_1.0_spec-1.0-alpha-1-javadoc.jar; 赠送源代码:geronimo-jcache_1.0_spec-1.0-alpha-1-sources.jar; 赠送Maven依赖信息...

    geronimo-jaspic_1.0_spec-1.0-API文档-中文版.zip

    赠送jar包:geronimo-jaspic_1.0_spec-1.0.jar; 赠送原API文档:geronimo-jaspic_1.0_spec-1.0-javadoc.jar; 赠送源代码:geronimo-jaspic_1.0_spec-1.0-sources.jar; 赠送Maven依赖信息文件:geronimo-jaspic_...

    geronimo-j2ee-management_1.1_spec-1.0.1-API文档-中文版.zip

    赠送jar包:geronimo-j2ee-management_1.1_spec-1.0.1.jar; 赠送原API文档:geronimo-j2ee-management_1.1_spec-1.0.1-javadoc.jar; 赠送源代码:geronimo-j2ee-management_1.1_spec-1.0.1-sources.jar; 包含...

    Geronimo服务器下部署Seam程序

    - 使用Eclipse、NetBeans等集成开发环境(IDE),创建一个Seam项目,选择对应的Java EE版本和服务器配置(这里是Geronimo)。 - 在项目中添加Seam库依赖,如seam.jar、jboss-seam.jar等。 - 编写Seam组件,包括...

    geronimo-jcache_1.0_spec-1.0-alpha-1-API文档-中英对照版.zip

    赠送jar包:geronimo-jcache_1.0_spec-1.0-alpha-1.jar; 赠送原API文档:geronimo-jcache_1.0_spec-1.0-alpha-1-javadoc.jar; 赠送源代码:geronimo-jcache_1.0_spec-1.0-alpha-1-sources.jar; 赠送Maven依赖信息...

    geronimo-jms-1.1-spec-1.1.1-API文档-中英对照版.zip

    赠送jar包:geronimo-jms_1.1_spec-1.1.1.jar; 赠送原API文档:geronimo-jms_1.1_spec-1.1.1-javadoc.jar; 赠送源代码:geronimo-jms_1.1_spec-1.1.1-sources.jar; 包含翻译后的API文档:geronimo-jms_1.1_...

    Geronimo的Eclipse插件

    Geronimo的Eclipse插件是为开发者提供的一种集成开发环境(IDE)扩展,旨在简化在Eclipse中使用Apache Geronimo服务器进行Java应用开发的过程。这个插件允许用户直接在Eclipse内管理、部署和调试基于J2EE的应用程序...

    Apache Geronimo Documentation 3.0

    10. **开发与调试**:针对开发者,文档可能包含关于如何使用Geronimo进行开发和调试的技巧,例如IDE集成、日志记录和调试工具。 11. **性能优化**:提供有关如何调整Geronimo以提高性能的建议,包括内存配置、...

    geronimo-jms_1.1_spec-1.1.1-API文档-中文版.zip

    赠送jar包:geronimo-jms_1.1_spec-1.1.1.jar; 赠送原API文档:geronimo-jms_1.1_spec-1.1.1-javadoc.jar; 赠送源代码:geronimo-jms_1.1_spec-1.1.1-sources.jar; 包含翻译后的API文档:geronimo-jms_1.1_...

    Apache Geronimo 中部署 Web 服務

    文章中提到了使用 Amazon Web 服务 (AWS) 作为示例来展示如何在 Geronimo 中部署 Web 服务。这个过程包括了从获取 AWS 的 WSDL 文件到生成 Java 代码,再到最终部署 Web 服务的全过程。 1. **获取 AWS 的 WSDL 文件...

    Apache Geronimo配置文件geronimo-web.xml各个标签的讲解

    `geronimo-web.xml`是Geronimo针对Web应用的特定部署计划文件,它与标准的`web.xml`文件一起使用,用于在Geronimo服务器上部署包含JSP和Servlet的Web应用程序。虽然`geronimo-web.xml`是可选的,但在某些情况下,如...

    Geronimo 和 Spring

    通过本系列教程的学习,开发者可以逐步掌握如何在Geronimo应用服务器上使用Spring框架构建和部署高效、可靠的企业级应用程序。随着对Spring框架的深入理解,开发者将能够更好地利用其优势来解决实际开发中的问题。

    geronimo的service化工具

    这通常涉及到将Geronimo的启动脚本或可执行文件与Windows服务管理机制集成。 标签"geronimo service"直接关联到Geronimo作为服务运行的概念。在Windows操作系统中,服务是一种在后台运行的应用程序类型,它们可以...

    geronimo-jta_1.1_spec-1.1-sources.jar.zip

    《深入理解Geronimo JTA 1.1规范与Hibernate集成》 在Java世界中,事务处理是确保数据一致性、可靠性和并发控制的关键组件。Geronimo JTA 1.1规范是Java Transaction API(JTA)的一个实现,它定义了在分布式环境中...

Global site tag (gtag.js) - Google Analytics