在上一篇技巧中,“ 使用 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 程序员的工具箱中增加一些有用的东西。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 下载本技巧的
源文件。
- 阅读 “
使用 XML 流解析器”,关于 StAX 的
developerWorks技巧系列中的第一篇(2003 年 11 月)。
- 阅读 StAX 技巧系列文章中的第 2 篇,了解如何对 StAX 解析器应用事件过滤器和流过滤器,“
使用 StAX 部分解析 XML 文档” (2003 年 12 月)。
- 本系列文章中的第 3 篇技巧介绍了如何从 XML 文档中检索特定的信息,以及如何在收集到这些信息后停止解析处理,“
使用 StAX 高效筛选 XML 文档”(2003 年 12 月)。
- 本系列文章中的 4 篇技巧说明了如何使用底层的基于指针的 API 有效地创建 XML 文档,“
使用 StAX 编写 XML 文档”(2003 年 12 月)。
- 在
Java Community Process 站点上获得更多关于 Streaming API for XML (StAX) 的信息。
- 在
developerWorks
XML 专区中可以找到更多的 XML 资源。关于最新的 XML 技巧的完整列表,请访问
技巧汇总页面。
- 了解如何才能成为一名
IBM 认证的 XML 及相关技术的开发人员。
Berthold Daum 是德国 Ltzelbach 的一名顾问和作家。他的近作有 System Architecture with XML和 Modeling Business Objects with XML Schema(均由 Morgan Kauffman 出版),要了解这些书的更多信息,请访问 http://www.bdaum.de。可以通过 berthold.daum@bdaum.de与 Berthold 联系。