почему org.apache.xerces.parsers.SAXParser не пропускает спецификацию в xml, закодированном в utf8?

У меня есть xml с кодировкой utf8. И этот файл содержит спецификацию начала файла. Поэтому во время синтаксического анализа я сталкиваюсь с org.xml.sax.SAXParseException: содержимое не разрешено в прологе. Я не могу удалить эти 3 байта из файлов. Я не могу загрузить файл в память и удалить их здесь (файлы большие). Поэтому по соображениям производительности я использую парсер SAX и хочу просто пропустить эти 3 байта, если они присутствуют перед тегом "". Должен ли я наследовать InputStreamReader для этого?

Я новичок в java - покажите мне правильный путь, пожалуйста.


person denys    schedule 18.03.2011    source источник


Ответы (3)


Это уже возникало раньше, и я нашел ответ о переполнении стека, когда это случилось со мной. Связанный ответ использует PushbackInputStream для проверки спецификации.

person Adrian Cox    schedule 18.03.2011

У меня возникла та же проблема, и я решил ее с помощью этого кода:

private static InputStream checkForUtf8BOM(InputStream inputStream) throws IOException {
    PushbackInputStream pushbackInputStream = new PushbackInputStream(new BufferedInputStream(inputStream), 3);
    byte[] bom = new byte[3];
    if (pushbackInputStream.read(bom) != -1) {
        if (!(bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF)) {
            pushbackInputStream.unread(bom);
        }
    }
    return pushbackInputStream;
}
person javanna    schedule 18.03.2011
comment
Это для UTF8 ... Я предполагаю, что UTF16 будет отличаться (я полагаю, что это всего 2 байта)? - person Trinition; 25.03.2011
comment
Извини за опоздание. Да, в UTF16 спецификация состоит всего из двух байтов: 0xFE 0xFF (с прямым порядком байтов) или 0xFF 0xFE (с прямым порядком байтов). - person javanna; 01.04.2011

private static char[] UTF32BE = { 0x0000, 0xFEFF };
private static char[] UTF32LE = { 0xFFFE, 0x0000 };
private static char[] UTF16BE = { 0xFEFF };
private static char[] UTF16LE = { 0xFFFE };
private static char[] UTF8 = { 0xEFBB, 0xBF };

private static boolean removeBOM(Reader reader, char[] bom) throws Exception {
    int bomLength = bom.length;
    reader.mark(bomLength);
    char[] possibleBOM = new char[bomLength];
    reader.read(possibleBOM);
    for (int x = 0; x < bomLength; x++) {
        if ((int) bom[x] != (int) possibleBOM[x]) {
            reader.reset();
            return false;
        }
    }
    return true;
}

private static void removeBOM(Reader reader) throws Exception {
    if (removeBOM(reader, UTF32BE)) {
        return;
    }
    if (removeBOM(reader, UTF32LE)) {
        return;
    }
    if (removeBOM(reader, UTF16BE)) {
        return;
    }
    if (removeBOM(reader, UTF16LE)) {
        return;
    }
    if (removeBOM(reader, UTF8)) {
        return;
    }
}

Применение:

// xml can be read from a file, url or string through a stream
URL url = new URL("some xml url");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
removeBOM(bufferedReader);
person tuku    schedule 06.05.2013