从XML元素内容中获取InputStream

我的servlet的doPost()接收一个HttpServletRequest,其ServletInputStream向我发送了一大堆用XML包装的uuencoded数据。 例如,有一个元素:

largeChunkEncodedHere 

我需要解码块并将其写入文件。 我想从块中获取一个InputStream,使用MimeUtility将其解码为流,并使用该流写入文件—我宁愿不将这个大块读入内存。

XML是平的; 也就是说,没有太多的嵌套。 我的第一个想法是使用SAX解析器,但我不知道如何切换到流来读取块。

谢谢你的想法。

格伦

编辑1:请注意JB Nizet在这篇文章中的悲观回答。

编辑2:我在下面肯定地回答了我自己的问题,并在下面将maximdim的答案标记为正确,即使它没有完全回答这个问题,它确实指引我使用StAX API和Woodstox。

您可以使用SAXfilter或XPath来获取您感兴趣的元素。一旦获得元素的内容,将其传递给MimeUtility.decode()并将流写入文件。

我建议您使用代码示例更新您的问题,并告诉我们什么不起作用。

更新:

以下是使用StaX2解析器(Woodstox)的示例代码。 出于某种原因,JDK中包含的StaX解析器似乎没有类似的getText()方法,至少在快速浏览时。

显然输入(r)和输出(w)可以是任何读/写器或流 – 仅使用字符串在这里。

  Reader r = new StringReader("largeChunkEncodedHere"); Writer w = new StringWriter(); XMLInputFactory2 xmlif = (XMLInputFactory2)XMLInputFactory2.newInstance(); XMLStreamReader2 sr = (XMLStreamReader2)xmlif.createXMLStreamReader(r); boolean flag = false; while (sr.hasNext()) { sr.next(); if (sr.getEventType() == XMLStreamConstants.START_ELEMENT) { if ("filedata".equals(sr.getLocalName())) { flag = true; } } else if (sr.getEventType() == XMLStreamConstants.CHARACTERS) { if (flag) { sr.getText(w, false); break; } } } System.out.println(w); 

以下是使用Woodstox框架在使用StAX解析时如何从元素流式传输的一些细节。

本文有一个很好的概述。

从XMLInputFactory我们可以使用ServletInputStream调用createXMLStreamReader(java.io.InputStream流)。 这将返回一个XMLStreamReader2,它有一个getText(Writer w,boolean preserveContents)方法,该方法返回一个int,表示写入的字节数。 必须实施此方法。 在实现Stax2ReaderImpl中有这个实现

 // // // StAX2, Pass-through text accessors public int getText(Writer w, boolean preserveContents) throws IOException, XMLStreamException { char[] cbuf = getTextCharacters(); int start = getTextStart(); int len = getTextLength(); if (len > 0) { w.write(cbuf, start, len); } return len; } 

在这段代码中,我们需要更改getTextCharacters()方法,以便从InputStream中读取。 在Woodstox测试TestGetSegmentedText testSegmentedGetCharacters()方法中我们看到了一个sr.getTextCharacters(offset,buf,start,len)方法。 事实上,多参数XMLStreamReader.getTextCharacters()的javadoc显示了以下实现。

 int length = 1024; char[] myBuffer = new char[ length ]; for ( int sourceStart = 0 ; ; sourceStart += length ) { int nCopied = stream.getTextCharacters( sourceStart, myBuffer, 0, length ); if (nCopied < length) { break; } } 

Woodstox还有一个建议:它还可以有效地从内部解码base64编码的东西。 为此,您需要将XMLStreamReader转换为XMLStreamReader2 (或TypedXMLStreamReader ),它是Stax2扩展API的一部分。

但是,通过它,您可以获得自动处理Base64解码的方法readElementAsBinary()getElementAsBinary()XMLStreamWriter2类似地具有用于编写二进制数据的Base64编码方法。