从XML元素内容中获取InputStream

时间:2012-02-22 17:44:53

标签: java xml stream sax

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

<filedata encoding="base64">largeChunkEncodedHere</filedata>

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

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

感谢您的想法。

格伦

编辑1:请注意JB {Nizet在this post中的悲观回答。

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

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

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

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

<强>更新

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

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

    Reader r = new StringReader("<foo><filedata encoding=\"base64\">largeChunkEncodedHere</filedata></foo>");
    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);

答案 2 :(得分:0)

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

this article中有一个很好的概述。

从XMLInputFactory我们可以调用createXMLStreamReader(java.io.InputStream stream)使用ServletInputStream。这将返回一个XMLStreamReader2,它 有一个getText(Writer w,boolean preserveContents)方法,返回一个int for 写入的字节数。必须实施此方法。在里面 实现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)使用的方法。实际上是多参数的javadoc XMLStreamReader.getTextCharacters()显示以下实现。

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;
    }
}