是否有可能创建一个"TransformerOutputStream",它扩展了标准的java.io.OutputStream,封装了提供的输出流并应用了XSL转换?我找不到允许我这样做的任何API组合。
关键是,一旦创建了TransformerOutputStream,就可以将其传递给其他接受标准java.io.OutputStream的API。
最低限度的使用将类似于:
java.io.InputStream in = getXmlInput();
java.io.OutputStream out = getTargetOutput();
javax.xml.transform.Templates templates = createReusableTemplates(); // could also use S9API
TransformerOutputStream tos = new TransformerOutputStream(out, templates); // extends OutputStream
com.google.common.io.ByteStreams.copy(in, tos);
// possibly flush/close tos if required by implementation这是一个JAXP示例,但由于我目前使用的是Saxon,所以S9API解决方案也可以。
我所说服的主要途径是:
java.io.OutputStream并实现org.xml.sax.ContentHandler的类org.xml.sax.ContentHandler的XSL变压器但我找不到这两种方法的实现,这似乎表明,要么是没有其他人尝试过这样做,要么是有一些问题使其不切实际,或者我的搜索技能不是很好。
我可以理解,对于某些模板,XML转换器可能需要访问整个文档,因此SAX内容处理程序可能没有提供任何优势,但也必须有简单的转换,这些转换可以在流经过时应用到流中?这种接口将由转换器实现来决定。
我已经编写了一个类,目前正在使用一个提供此接口的类,但是它只是在内部缓冲区中收集输出数据,然后使用标准的JAXP StreamSource在刷新或关闭时读取该数据,因此最终会缓冲整个文档。
发布于 2019-06-14 08:35:59
您可以使您的TransformerOutputStream扩展ByteArrayOutputStream,它的close()方法可以接受底层的byte[]数组,将其包装在ByteArrayInputStream中,并使用从该InputStream获取的输入调用转换。
但是,您似乎也希望避免将流的全部内容放入内存中。因此,让我们假设要应用的转换是XSLT3.0可流转换。不幸的是,尽管Saxon作为一个流XSLT转换器主要在push模式下工作( " push“指的是数据提供者调用数据使用者,而" pull”则意味着数据使用者调用数据提供者),但是读取和解析输入的第一阶段总是处于拉式--我不知道有一个XML解析器可以将词法XML输入推送到其中。
这意味着这里有推拉冲突。推拉冲突有两种解决办法.一种是在内存中缓冲数据(这是前面提到的ByteArrayOutputStream方法)。另一个是使用两个线程,一个线程写入共享缓冲区,另一个线程从共享缓冲区读取。这可以使用写入线程中的PipedOutputStream (https://docs.oracle.com/javase/8/docs/api/index.html?java/io/PipedOutputStream.html)和读取线程中的PipedInputStream来实现。
警告:我还没有试过这个,但我看不出为什么它不起作用。
请注意,XSLT3.0中的流主题相当复杂;在这里取得很大进展之前,您需要了解它。我将从Abel Braaksma 2014年在XML London的演讲开始:https://xmllondon.com/2014/presentations/braaksma
https://stackoverflow.com/questions/56590224
复制相似问题