跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

技巧: 使用 StAX 合并 XML 文档

在管道式 XML 应用程序中使用高层的、基于事件的 API

Berthold Daum (berthold.daum@bdaum.de), 总裁, BDaum Industrial Communications
Berthold Daum 是德国 Ltzelbach 的一名顾问和作家。他的近作有 System Architecture with XMLModeling Business Objects with XML Schema(均由 Morgan Kauffman 出版),要了解这些书的更多信息,请访问 http://www.bdaum.de。可以通过 berthold.daum@bdaum.de与 Berthold 联系。

简介: 从输入文档派生新的 XML 文档是 Streaming API for XML (StAX) 的闪光点之一。这篇技巧探讨了客户应用程序如何利用基于事件的 API 有效地把两个输入 XML 文档合并成一个。

发布日期: 2004 年 2 月 01 日
级别: 中级
访问情况 : 1350 次浏览
评论: 


在上一篇技巧中,“ 使用 StAX 编写 XML 文档”,我说明了如何使用底层的基于指针的 StAX API 通过编程方式创建 XML 文档。在这篇技巧中,我使用高层的基于事件的 API 演示如何建立一个程序,把两个输入的 XML 文档合并成一个。

同时处理多个 XML 文档可能是一个很大的挑战。比如,SAX 解析器通过回调客户应用程序提交解析事件。因为 SAX 解析器控制了这个过程,客户应用程序实际上没有机会同步不同的输入源。因此,在需要处理多个文档时程序员常常求助于 DOM 解析器。但是,代价是额外的资源占用——所有输入文档的节点树必须都驻留在内存中。

StAX 不存在这种缺陷。如它的名字所表明的那样,其目标就是像合并两个文档这样的流式应用程序。下面的例子说明了如何实现这种功能。假设您需要合并包含产品列表的两个文档。每个文档都有一个 <products> 元素,其中包含一个或多个 <product> 元素,根据 pid 属性按照字母顺序排序。清单 1 是一个这种文档的例子:


清单 1. 产品列表
<products>
   <product pid="01"/>
   <product pid="05"/>
   <product pid="09"/>
</products>

在清单 2 中,我使用传统的合并算法合并来自两个文档中的列表。通过比较来自两个文档的合并条件,决定从文档 1 还是文档 2 复制一个事件到输出文档。这项工作由 readToNextElement() 方法完成。该方法还有一些其他的逻辑,用于检查产品列表的结束。文档开始和文档结束都需要专门处理。


清单 2. 合并文档
import java.io.*;
import javax.xml.namespace.QName;
import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
public class Merger {
   private static final QName prodName = new QName("product");
   private static final QName pidName = new QName("pid");
   public static void main(String[] args)
      throws FileNotFoundException, XMLStreamException {
         
      // Use  the reference implementation for the  XML input factory
      System.setProperty(
         "javax.xml.stream.XMLInputFactory",
         "com.bea.xml.stream.MXParserFactory");
      // Create the XML input factory
      XMLInputFactory factory = XMLInputFactory.newInstance();
      // Create XML event reader 1
      XMLEventReader r1 = 
         factory.createXMLEventReader(new FileReader("prodList1.xml"));
      // Create XML event reader 2
      XMLEventReader r2 = 
         factory.createXMLEventReader(new FileReader("prodList2.xml"));
      // Create the output factory
      XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
      // Create XML event writer
      XMLEventWriter xmlw = xmlof.createXMLEventWriter(System.out);
      // Read to first <product> element in document 1
      // and output to result document
      String pid1 = readToNextElement(r1, xmlw, false);
      // Read to first <product> element in document 1
      // without writing to result document
      String pid2 = readToNextElement(r2, null, false);
      // Loop over both XML input streams
      while (pid1 != null || pid2 != null) {
         // Compare merge criteria
         if (pid2 == null || (pid1 != null && pid1.compareTo(pid2) <= 0))
            // Continue in document 1
            pid1 = readToNextElement(r1, xmlw, pid2 == null);
         else
            // Continue in document 2
            pid2 = readToNextElement(r2, xmlw, pid1 == null);
      }
      xmlw.close();
   }
   /**
    * @param reader - the document reader
    * @param writer - the document writer
    * @param processEnd - forces the document end to be written
    * @return - the next merge criterion value
    * @throws XMLStreamException
    */
   private static String readToNextElement(XMLEventReader reader,
         XMLEventWriter writer, boolean processEnd) throws XMLStreamException {
      // Nesting level
      int level = 0;
      while (true) {
         // Read event to be written to result document
         XMLEvent event = reader.next();
         // Avoid double processing of document end
         if (!processEnd)
            switch (event.getEventType()) {
               case XMLEvent.START_ELEMENT :
                  ++level;
                  break;
               case XMLEvent.END_ELEMENT :
                  if (--level < 0)
                     return null;
                  break;
            }
         // Output event
         if (writer != null)
            writer.add(event);
         // Look at next event
         event = reader.peek();
         switch (event.getEventType()) {
            case XMLEvent.START_ELEMENT :
               // Start element - stop at <product> element
               QName name = event.asStartElement().getName();
               if (name.equals(prodName)) {
                  return event
                     .asStartElement()
                     .getAttributeByName(pidName)
                     .getValue();
               }
               break;
            case XMLEvent.END_DOCUMENT :
               // Stop at end of document
               return null;
         }
      }
   }
}

如您所见,基于事件的 API 非常适于从其他文档派生文档。如果使用底层的基于指针的 API,您还需要对不同的事件类型调用不同的方法,而使用基于事件的 API,只需要向事件编写器的 add() 方法 传递普通事件就可以了。


结束语

这篇技巧示范了在管道式 XML 应用程序中使用 StAX 的基于事件的 API,比如文档的合并。2003 年 11 月 3 日,StAX 通过了 Final JSR-0173 Approval Ballot。它将为每个 Java 程序员的工具箱中增加一些有用的东西。


参考资料

关于作者

Berthold Daum 是德国 Ltzelbach 的一名顾问和作家。他的近作有 System Architecture with XMLModeling Business Objects with XML Schema(均由 Morgan Kauffman 出版),要了解这些书的更多信息,请访问 http://www.bdaum.de。可以通过 berthold.daum@bdaum.de与 Berthold 联系。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=22224
ArticleTitle=技巧: 使用 StAX 合并 XML 文档
publish-date=02012004
author1-email=berthold.daum@bdaum.de
author1-email-cc=

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。