Java DOM преобразовывает и анализирует произвольные строки с недопустимыми символами XML? - PullRequest
4 голосов
/ 22 декабря 2019

Прежде всего я хочу упомянуть, что это не дубликат Как разобрать недопустимый (плохой / не правильно сформированный) XML? , потому что у меня нет заданного недопустимого (или не очень хорошо)-formed) XML-файл, а точнее произвольная Java String, которая может содержать или не содержать недопустимый символ XML. Я хочу создать DOM Document, содержащий узел Text с указанным String, а затем преобразовать его в файл. Когда файл анализируется в DOM Document, я хочу получить String, который равен начальному заданному String. Я создаю Text узел с org.w3c.dom.Document#createTextNode(String data) и получаю String с org.w3c.dom.Node#getTextContent().

Как вы можете видеть в https://stackoverflow.com/a/28152666/3882565, есть несколько недопустимых символов для Text узлов вXML-файлНа самом деле есть два разных типа «недопустимых» символов для Text узлов. Существуют предопределенные объекты, такие как ", &, ', < и >, которые автоматически экранируются DOM API с помощью &quot;, &amp;, &apos;, &lt; и&gt; в результирующем файле, который отменяется API DOM при анализе файла. Теперь проблема в том, что это не относится к другим недопустимым символам, таким как '\u0000' или '\uffff'. При синтаксическом анализе файла возникает исключительная ситуация, поскольку '\u0000' и '\uffff' являются недопустимыми символами.

Возможно, мне нужно реализовать метод, который экранирует эти символы в данном String уникальным способом, прежде чем отправлять его вAPI DOM и отмените это позже, когда я верну String, верно? Есть лучший способ это сделать? Кто-то реализовывал эти или подобные методы в прошлом?

Редактировать: Этот вопрос был помечен как дубликат Лучший способ кодировать текстовые данные для XML в Java? . Теперь я прочитал все ответы, но ни один из них не решил мою проблему. Все ответы предполагают:

  • Использование библиотеки XML, такой как DOM API, которую я уже делаю, и ни одна из этих библиотек фактически не заменяет недопустимые символы, кроме ", &, ',<, > и еще несколько.
  • Замена всех недопустимых символов на "&#number;", что приводит к исключению для недопустимых символов, таких как "&#0;" при разборе файла.
  • Использование сторонней библиотеки с методом кодирования XML, который не поддерживает недопустимые символы, такие как "&#0;" (они пропускаются в некоторых библиотеках).
  • Использование раздела CDATA, который также не поддерживает недопустимые символы.

Ответы [ 2 ]

1 голос
/ 02 января 2020

Я думаю, что самое простое решение - использовать XML 1.1 (поддерживается org.w3c.dom), используя этот препроцессор:

<?xml <b>version=1.1</b> encoding=UTF-8 standalone=yes?>

Согласно Википедии единственноенедопустимыми символами в XML 1.1 являются U + 0000, суррогаты , U + FFFE и U + FFFF

Этот фрагмент кода гарантирует, что вы всегда получите правильную строку XML 1.1,опуская недопустимые символы (возможно, это не то, что вы ищете, если вам нужна та же самая строка назад):

public static String escape(String orig) {
    StringBuilder builder = new StringBuilder();

    for (char c : orig.toCharArray()) {
        if (c == 0x0 || c == 0xfffe || c == 0xffff || (c >= 0xd800 && c <= 0xdfff)) {
            continue;
        } else if (c == '\'') {
            builder.append("&apos;");
        } else if (c == '"') {
            builder.append("&quot;");
        } else if (c == '&') {
            builder.append("&amp;");
        } else if (c == '<') {
            builder.append("&lt;");
        } else if (c == '>') {
            builder.append("&gt;");
        } else if (c <= 0x1f) {
            builder.append("&#" + ((int) c) + ";");
        } else {
            builder.append(c);
        }
    }

    return builder.toString();
}
1 голос
/ 02 января 2020

Один из методов заключается в кодировании всей строки как Base64-encoded-UTF8.

Но если «специальные» символы встречаются редко, это значительная жертва в удобочитаемости и размере файла.

Другой метод заключается в представлении специальных символов в качестве инструкций обработки, например, <?U 0000?> для кодовой точки 0.

Другой способ заключается в использовании экранирования обратной косой черты, например, \ u0000 для кодовой точки 0 и, конечно, \ для самой обратной косой черты. Это имеет то преимущество, что вы, вероятно, можете найти существующие библиотечные подпрограммы, которые делают это для вас (например, библиотеки преобразования JSON). Я не могу представить, почему ваши требования говорят, что вы не можете использовать такие библиотеки;но если вы действительно не можете, то нетрудно написать код самостоятельно.

...