我如何处理InputStream的XML事件通过几个处理程序和另一个输入流在Java中使用StAX?



我需要使用StAX解析XML文件(因为文件太大而无法将它们保存在内存中)并在此过程中转换某些事件/元素。我手头有一个与XML文件相关联的InputStream。我的想法是设计几个处理程序,将输入流通过所有处理程序提供给另一个输入流(因为转换的客户端期望输入流)。到目前为止,我已经编写了以下代码:

所有处理程序实现的接口:

public interface EventHandler {
XMLEvent process(XMLEvent event);
}

下面的几个处理程序。例如,一个这样的处理程序可以为元素添加属性,另一个处理程序可以以某种方式转换元素的文本,等等。

public class Handler1 implements EventHandler {
@Override
public XMLEvent process(XMLEvent event) {
if (supports(event)) {
// processing logic omitted
}
}
private boolean supports(XMLEvent event) {
// condition to process an event omitted
}
}

获取原始输入流并返回处理后的输入流的处理类:

public class XmlProcessor {

@Autowired
private Set<EventHandler> eventHandlers;
public InputStream process(InputStream inputStream) {
InputStream result;
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLStreamReader xmlReader = xmlInputFactory.createXMLStreamReader(inputStream);
XMLEvent event = null;
while (xmlReader.hasNext()) {
event = xmlReader.next();
for (EventHandler eh : eventHandlers) {
event = eh.process(event);
}
// here I need to somehow add the processed event to the resulting input stream
// that I will return from this method.
}
return result;
}
}

我一直在试图找到一种方法来将处理过的事件提供给结果InputStream。我该怎么做呢?我是否需要在另一个线程中运行while循环,并为此进程使用PipedInputStreamPipedOutputStream,或者我可以在单个线程中实现这一点?

在我看来,在推送模式下实现管道通常更简单(其中数据提供者进行"发送")。调用接收方),而不是在拉模式下(接收方执行"readnext";调用供应商)。当事件之间没有一对一的对应关系时,这通常会使它变得更简单,例如,当第一个筛选步骤中的一个事件变成下一个筛选步骤中的多个事件时。

但是,无论使用拉模式还是推模式,在管道中各个阶段之间传递的对象都应该是XML事件流,而不是字节流。如果传递一个字节流,那么管道中的每个阶段都必须进行XML解析和序列化,这使得效率非常低。使用字节流的唯一好处是,如果管道的各个阶段在不同的进程中运行(可能是在不同的机器上),那么它们就不会共享内存。

你观察到的是正确的,如果管道中的一个阶段想要从前一个阶段拉出并推到下一个阶段(也就是说,如果它想拥有控制循环),那么每个阶段都必须在一个单独的线程中运行——除非你使用支持协同例程的编程语言,比如c#或Javascript的"yield"构造。

另一个选择是将转换步骤写成XSLT 3.0流转换。XSLT 3.0流的两种实现已经产生:Saxon在内部以推送模式工作,Exselt(目前不可用)在内部以拉模式工作,但如果您的代码在XSLT中,那么您将与此隔离,因为您自己的代码完全是声明性的。

参见我的论文你拉,我将推动:关于管道的极性发表在Balisage 2009 (http://www.balisage.net/Proceedings/vol3/html/Kay01/BalisageVol3-Kay01.html)

相关内容

  • 没有找到相关文章

最新更新