Как разобрать файл XML, содержащий спецификацию?

Я хочу проанализировать файл XML из URL-адреса с помощью JDOM. Но при попытке это:

SAXBuilder builder = new SAXBuilder();
builder.build(aUrl);

Я получаю это исключение:

Invalid byte 1 of 1-byte UTF-8 sequence.

Я думал, что это может быть проблема с BOM. Итак, я проверил источник и увидел спецификацию в начале файла. Я попытался прочитать URL-адрес с помощью aUrl.openStream() и удалить спецификацию с помощью Commons IO BOMInputStream. Но, к моему удивлению, он не обнаружил никакой спецификации. Я попытался прочитать из потока и записать в локальный файл и проанализировать локальный файл. Я установил все кодировки для InputStreamReader и OutputStreamWriter на UTF8, но когда я открыл файл, в нем были сумасшедшие символы.

Я думал, что проблема в кодировке исходного URL. Но когда я открываю URL-адрес в браузере, сохраняю XML в файл и читаю этот файл с помощью описанного выше процесса, все работает нормально.

Я ценю любую помощь по возможной причине этой проблемы.


person doctrey    schedule 12.12.2011    source источник
comment
Можете ли вы загрузить оскорбительный файл куда-нибудь?   -  person millimoose    schedule 13.12.2011
comment
Есть ли в SAXBuilder известная ошибка со спецификациями в UTF-8? Парсеры XML должны обрабатывать их без ошибок. В любом случае, исходя из этого описания, я был бы более склонен подозревать, что это вовсе не UTF-8.   -  person Jon Hanna    schedule 13.12.2011
comment
@JonHanna Не знаю о SAXBuilder. Я не смог найти ничего, что указывало бы на проблему с SAXBuilder. Но что касается второго пункта, в файле указано, что это UTF-8 в прологе. Также, когда я пытаюсь просмотреть его в любых других кодировках, в начале появляется спецификация.   -  person doctrey    schedule 13.12.2011
comment
Для проблемы Bom вы можете посмотреть здесь   -  person javanna    schedule 13.12.2011


Ответы (2)


Этот HTTP-сервер отправляет содержимое в формате GZIP (Content-Encoding: gzip; см. http://en.wikipedia.org/wiki/HTTP_compression, если вы не знаете, что это значит), поэтому вам нужно обернуть aUrl.openStream() в GZIPInputStream, который будет распаковывать его для вас. Например:

builder.build(new GZIPInputStream(aUrl.openStream()));

Отредактировано для добавления на основе последующего комментария: Если вы заранее не знаете, будет ли URL-адрес сжат GZIP, вы можете написать что-то вроде этого:

private InputStream openStream(final URL url) throws IOException
{
    final URLConnection cxn = url.openConnection();
    final String contentEncoding = cxn.getContentEncoding();
    if(contentEncoding == null)
        return cxn.getInputStream();
    else if(contentEncoding.equalsIgnoreCase("gzip")
               || contentEncoding.equalsIgnoreCase("x-gzip"))
        return new GZIPInputStream(cxn.getInputStream());
    else
        throw new IOException("Unexpected content-encoding: " + contentEncoding);
}

(предупреждение: не проверено), а затем используйте:

builder.build(openStream(aUrl.openStream()));

. Это в основном эквивалентно приведенному выше aUrl.openStream(), который явно задокументирован как сокращение для aUrl.openConnection().getInputStream(), за исключением того, что он проверяет заголовок Content-Encoding, прежде чем решить, следует ли обернуть поток в GZIPInputStream.

См. документацию для java.net.URLConnection.

person ruakh    schedule 12.12.2011
comment
Чувак, спасибо, что решил проблему. Вы не представляете, как сильно вы мне помогли. Однако один вопрос: если я использую GzipInputStream для переноса любого входного потока, вызовет ли это какие-либо проблемы с теми, которые не сжаты gzip? - person doctrey; 13.12.2011
comment
Я проверил это, и да, это создает проблемы. Он выдает IOException, если поток не в формате Gzip. - person doctrey; 13.12.2011
comment
@doctrey: Добро пожаловать! Re: потоки, не сжатые GZIP: Да, это будет проблемой, поскольку GZIPInputStream требует, чтобы его ввод был сжат GZIP. Я отредактировал свой ответ, чтобы дать (непроверенный) код для обработки обоих случаев. - person ruakh; 13.12.2011

Вы можете обнаружить, что можете избежать обработки закодированных ответов, отправив пустой заголовок Accept-Encoding. См. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html: «Если в запросе нет поля Accept-Encoding, сервер МОЖЕТ предположить, что клиент примет любую кодировку контента». Кажется, это происходит здесь.

person Danny Thomas    schedule 12.12.2011