Получить InputStream из содержимого элемента XML - PullRequest
2 голосов
/ 22 февраля 2012

DoPost () моего сервлета получает запрос HttpServletRequest, ServletInputStream которого отправляет мне большой кусок uuencoded данных, завернутых в XML.Например, есть элемент:

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

Мне нужно декодировать блок и записать его в файл.Я хотел бы получить InputStream из чанка, декодировать его как поток, используя MimeUtility, и использовать этот поток для записи файла - я бы предпочел не читать этот большой чанк в память.

XMLплоский;то есть не так много вложений.Моя первая идея - использовать синтаксический анализатор SAX, но я не знаю, как выполнить эстафетную передачу в поток для чтения только фрагмента.

Спасибо за ваши идеи.

Гленн

Редактировать 1: Обратите внимание на пессимистический ответ Дж. Б. Низета в этом сообщении .

Редактировать 2: Я ответил самвопрос утвердительно ниже, и пометил ответ maximdim ниже, как правильный, хотя он и не совсем отвечает на вопрос, он направил меня к StAX API и Woodstox.

Ответы [ 3 ]

1 голос
/ 03 мая 2012

Еще одно предложение относительно Woodstox: он также может эффективно декодировать то, что закодировано в base64, изнутри. Для этого вам нужно привести XMLStreamReader в XMLStreamReader2 (или TypedXMLStreamReader), который является частью API расширения Stax2.

Но при этом вы получаете методы readElementAsBinary() и getElementAsBinary(), которые автоматически обрабатывают декодирование Base64. XMLStreamWriter2 также имеет методы кодирования Base64 для записи двоичных данных.

0 голосов
/ 24 февраля 2012

Вот некоторые подробности о том, как потоковая передача от элемента при разборе с StAX возможно, используя Woodstox framework.

В этой статье есть хороший обзор .

Из XMLInputFactory мы можем вызвать createXMLStreamReader (java.io.InputStream поток), используя ServletInputStream. Это возвращает 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, начало, лен) используемый метод. На самом деле 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;
    }
}
0 голосов
/ 23 февраля 2012

Вы можете использовать SAX фильтр или XPath, чтобы получить только интересующий вас элемент (ы). Как только вы получите содержимое своего элемента, передайте его MimeUtility.decode () и запись потока в файл.

Предлагаю обновить вопрос с примером кода и сообщить нам, что не работает.

Обновление:

Вот пример кода с использованием синтаксического анализатора StaX2 (Woodstox). По некоторым причинам, парсер StaX, включенный в JDK, похоже, не имеет сопоставимого метода getText (), по крайней мере, на первый взгляд.

Очевидно, что input (r) и output (w) могут быть любыми Reader / Writer или Stream - используя String, например, здесь.

    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);
...