Обнаружен недопустимый символ XML (Unicode: 0xc)

Анализ файла XML с использованием анализатора Java DOM приводит к:

[Fatal Error] os__flag_8c.xml:103:135: An invalid XML character (Unicode: 0xc) was found in the element content of the document.
org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0xc) was found in the element content of the document.
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)

12 ответов

Решение

Есть несколько символов, которые не допускаются в документах XML, даже если вы инкапсулируете данные в CDATA-блоки.

Если вы сгенерировали документ, вам нужно будет кодировать его или удалять. Если у вас есть ошибочный документ, вы должны удалить эти символы, прежде чем пытаться его проанализировать.

Смотрите ответ дольменов в этой теме: Недопустимые символы в XML

Где он ссылается на эту статью: http://www.w3.org/TR/xml/

В основном все символы ниже 0x20 запрещены, кроме 0x9 (TAB), 0xA (CR?), 0xD (LF?)

public String stripNonValidXMLCharacters(String in) {
    StringBuffer out = new StringBuffer(); // Used to hold the output.
    char current; // Used to reference the current character.

    if (in == null || ("".equals(in))) return ""; // vacancy test.
    for (int i = 0; i < in.length(); i++) {
        current = in.charAt(i); // NOTE: No IndexOutOfBoundsException caught here; it should not happen.
        if ((current == 0x9) ||
            (current == 0xA) ||
            (current == 0xD) ||
            ((current >= 0x20) && (current <= 0xD7FF)) ||
            ((current >= 0xE000) && (current <= 0xFFFD)) ||
            ((current >= 0x10000) && (current <= 0x10FFFF)))
            out.append(current);
    }
    return out.toString();
}    

Всякий раз, когда недопустимый символ xml приходит xml, он выдает такую ​​ошибку. Когда вы открываете его в notepad++, это выглядит как VT, SOH,FF, как будто это недопустимые символы xml. Я использую XML версии 1.0, и я проверяю текстовые данные, прежде чем вводить их в базу данных по шаблону

Pattern p = Pattern.compile("[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u10000-\u10FFF]+"); 
retunContent = p.matcher(retunContent).replaceAll("");

Это гарантирует, что в xml не войдет неправильный специальный символ

Символ 0x0C недопустим в XML 1.0, но будет допустимым символом в XML 1.1. Таким образом, если файл xml не указывает версию 1.1 в прологе, он просто недействителен, и вам следует пожаловаться производителю этого файла.

Вы можете отфильтровать все "недопустимые" символы с помощью пользовательского класса FilterReader:

public class InvalidXmlCharacterFilter extends FilterReader {

    protected InvalidXmlCharacterFilter(Reader in) {
        super(in);
    }

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        int read = super.read(cbuf, off, len);
        if (read == -1) return read;

        for (int i = off; i < off + read; i++) {
            if (!XMLChar.isValid(cbuf[i])) cbuf[i] = '?';
        }
        return read;
    }
}

И запустите это так:

InputStream fileStream = new FileInputStream(xmlFile);
Reader reader = new BufferedReader(new InputStreamReader(fileStream, charset));
InvalidXmlCharacterFilter filter = new InvalidXmlCharacterFilter(reader);
InputSource is = new InputSource(filter);
xmlReader.parse(is);

В UTF-8 не разрешены все коды в этих диапазонах, для XML 1.0:

  • 0..8
  • ДО Н.Э
  • Э..1Ф
  • Д800..ДФФФ
  • FFFE..FFFF

Затем можно удалить регулярное выражение:

      text.replaceAll('[\\x{0}-\\x{8}]|[\\x{B}-\\x{C}]|[\\x{E}-\\x{1F}]|[\\x{D800}-\\x{DFFF}]|[\\x{FFFE}-\\x{FFFF}]', "")

Примечание: если вы работаете с XML 1.1, вам также необходимо удалить эти интервалы:

  • 7Ф..84
  • 86..9F

Ссылки:

Эта ссылка имеет Java-код, который прекрасно работает.

http://blog.mark-mclaren.info/2007/02/invalid-xml-characters-when-valid-utf8_5873.html

Я только что использовал этот проект и нашел его очень удобным: https://github.com/rwitzel/streamflyer

Использование InvalidXmlCharacterModifier, как сказано в документации.

Как в этом примере:

      public String stripNonValidXMLCharacters(final String in) {

  final Modifier modifier = new InvalidXmlCharacterModifier("",
    InvalidXmlCharacterModifier.XML_10_VERSION);

  final ModifyingReader modifyingReader = 
         new ModifyingReader(new StringReader(in), modifier);

  return IOUtils.toString(modifyingReader);
}

Все эти ответы, похоже, предполагают, что пользователь генерирует плохой XML, а не получает его от gSOAP, который должен знать лучше!

Для людей, которые читают байтовый массив в String и пытаются преобразовать его в объект с помощью JAXB, вы можете добавить кодировку "iso-8859-1", создав String из байтового массива следующим образом:

String JAXBallowedString = new String (byte [] input, "iso-8859-1");

Это заменит конфликтующий байт на однобайтовую кодировку, которую может обрабатывать JAXB. Очевидно, что это решение только для анализа XML.

Я столкнулся с аналогичной проблемой, когда XML содержал управляющие символы. Изучив код, я обнаружил, что устаревший класс StringBufferInputStream использовался для чтения содержимого строки.

http://docs.oracle.com/javase/7/docs/api/java/io/StringBufferInputStream.html

This class does not properly convert characters into bytes. As of JDK 1.1, the preferred way to create a stream from a string is via the StringReader class.

Я изменил его на ByteArrayInputStream, и он работал нормально.

Сегодня у меня похожая ошибка:

Servlet.service() for servlet [remoting] in context with path [/***] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: buildDocument failed.] with root cause org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 91; An invalid XML character (Unicode: 0xc) was found in the value of attribute "text" and element is "label".


После моего первого столкновения с ошибкой я повторно набрал всю строку вручную, так что не было возможности для появления специального символа, а Notepad++ не отображал никаких непечатаемых символов (черный на белом), тем не менее, я получал одну и ту же ошибку снова и снова.

Когда я посмотрел, что я сделал не так, как мои предшественники, оказалось, что это было еще одно дополнительное пространство непосредственно перед закрытием /> (как я слышал, рекомендовалось для старых парсеров, но это не должно иметь никакого значения, по стандартам XML):

<label text="this label's text" layout="cell 0 0, align left" />

Когда я удалил пробел:

<label text="this label's text" layout="cell 0 0, align left"/>

все работало нормально.


Так что это определенно вводящее в заблуждение сообщение об ошибке.

Другие вопросы по тегам