Лучший способ кодирования текстовых данных для XML в Java?
Очень похоже на этот вопрос , кроме Java.
Каков рекомендуемый способ кодирования строк для вывода XML в Java. Строки могут содержать символы типа «&», «<» и т. Д.
- Не запрашивать проблему Window.FEATURE_ACTION_BAR
- Могут ли SAX Parsers использовать XPath в Java?
- Grep и Sed Equivalent для обработки командной строки XML
- Округлые обрезанные углы Android XML
- XmlSerializer: удалить ненужные пространства имен xsi и xsd
- Предотrotation ссылок на сборку PDB и XML-файлов, скопированных на вывод
- Самый быстрый способ конвертировать XML в JSON в Java
- Нужны ли параметры SVG, такие как «xmlns» и «версия»?
- Создание допустимого XML с кодировкой Java и UTF-8
- Может ли JAXB быть маршалом сдерживанием сначала, а затем маршалом by @XmlIDREF для последующих ссылок?
- Является ли XML чувствительным к регистру?
- Как перехватывать защищенные страницы в R (https-ссылки) (используя readHTMLTable из пакета XML)?
- Получение значения атрибута в элементе xml
Очень просто: используйте библиотеку XML. Таким образом, это будет фактически правильным, вместо того, чтобы требовать подробного знания бит спецификации XML.
Как отмечали другие, использование XML-библиотеки – самый простой способ. Если вы хотите сбежать, вы можете посмотреть в StringEscapeUtils
из библиотеки Apache Commons Lang .
Просто используйте.
Это позволит использовать любые символы, кроме конечных
]]>
Таким образом, вы можете включать символы, которые были бы незаконными, такие как & и>. Например.
are allowed ]]>
Тем не менее, атрибуты должны быть экранированы, поскольку блоки CDATA не могут быть использованы для них.
Это сработало для меня, чтобы обеспечить экранированную версию текстовой строки:
public class XMLHelper { /** * Returns the string where all non-ascii and <, &, > are encoded as numeric entities. Ie "<A & B >" * .... (insert result here). The result is safe to include anywhere in a text field in an XML-string. If there was * no characters to protect, the original string is returned. * * @param originalUnprotectedString * original string which may contain characters either reserved in XML or with different representation * in different encodings (like 8859-1 and UFT-8) * @return */ public static String protectSpecialCharacters(String originalUnprotectedString) { if (originalUnprotectedString == null) { return null; } boolean anyCharactersProtected = false; StringBuffer stringBuffer = new StringBuffer(); for (int i = 0; i < originalUnprotectedString.length(); i++) { char ch = originalUnprotectedString.charAt(i); boolean controlCharacter = ch < 32; boolean unicodeButNotAscii = ch > 126; boolean characterWithSpecialMeaningInXML = ch == '<' || ch == '&' || ch == '>'; if (characterWithSpecialMeaningInXML || unicodeButNotAscii || controlCharacter) { stringBuffer.append("" + (int) ch + ";"); anyCharactersProtected = true; } else { stringBuffer.append(ch); } } if (anyCharactersProtected == false) { return originalUnprotectedString; } return stringBuffer.toString(); } }
Попробуй это:
String xmlEscapeText(String t) { StringBuilder sb = new StringBuilder(); for(int i = 0; i < t.length(); i++){ char c = t.charAt(i); switch(c){ case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '\"': sb.append("""); break; case '&': sb.append("&"); break; case '\'': sb.append("'"); break; default: if(c>0x7e) { sb.append(""+((int)c)+";"); }else sb.append(c); } } return sb.toString(); }
StringEscapeUtils.escapeXml()
не StringEscapeUtils.escapeXml()
управляющие символы (<0x20). XML 1.1 позволяет управлять символами; В XML 1.0 нет. Например, XStream.toXML()
будет счастливо сериализовать управляющие символы объекта Java в XML, который будет отклонять парсер XML 1.0.
Чтобы избежать контрольных символов с помощью Apache commons-lang, используйте
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
Хотя идеализм говорит, что использует библиотеку XML, ИМХО, если у вас есть основная идея XML, тогда здравый смысл и производительность говорят, что шаблон полностью. Это, возможно, более читаемо. Хотя использование ускользающих подпрограмм библиотеки, вероятно, хорошая идея.
Рассмотрим это: XML должен был быть написан людьми.
Использовать библиотеки для генерации XML, когда ваш XML как «объект» лучше моделирует вашу проблему. Например, если подключаемые модули участвуют в процессе построения этого XML.
Изменить: как для того, чтобы фактически избежать XML в шаблонах, использование CDATA или escapeXml(string)
из JSTL – это два хороших решения, escapeXml(string)
можно использовать следующим образом:
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> - ${fn:escapeXml(value)}
Поведение StringEscapeUtils.escapeXml () изменилось с Commons Lang 2.5 до 3.0. Теперь он больше не выходит за символы Unicode, превышающие 0x7f.
Это хорошо, старый метод должен был немного стремиться избежать объектов, которые могут быть просто вставлены в документ utf8.
Новые эсперанты, которые будут включены в Google Guava 11.0, также кажутся многообещающими: http://code.google.com/p/guava-libraries/issues/detail?id=799
Примечание. Ваш вопрос касается экранирования , а не кодирования . Escaping использует <и т. Д., Чтобы позволить синтаксическому анализатору различать «это XML-команда» и «это какой-то текст». Кодировка - это материал, который вы указываете в заголовке XML (UTF-8, ISO-8859-1 и т. Д.).
Прежде всего, как и все остальные, используйте библиотеку XML. XML выглядит просто, но кодирование + экранирование – это темное вуду (которое вы заметите, как только увидите столкновение с умляутами и японскими и другими странными вещами, такими как « цифры полной ширины » (& # FF11; равно 1)). Хранение XML-данных для чтения является задачей Sisyphus.
Я предлагаю никогда не пытаться быть умным в кодировании и экранировании текста в XML. Но не позволяйте этому мешать вам пытаться; просто помните, когда он кусает вас (и это будет).
Тем не менее, если вы используете только UTF-8, чтобы сделать чтение более понятным, вы можете рассмотреть эту страtagsю:
- Если текст содержит «<», «>» или «&», заверните его в
- Если текст не содержит этих трех символов, не деформируйте его.
Я использую это в редакторе SQL, и это позволяет разработчикам вырезать и вставлять SQL из стороннего SQL-инструмента в XML, не беспокоясь об экранировании. Это работает, потому что SQL не может содержать umlauts в нашем случае, поэтому я в безопасности.
public String escapeXml(String s) { return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'"); }
Хотя я согласен с Джоном Скитом в принципе, иногда у меня нет возможности использовать внешнюю библиотеку XML. И я считаю, что две функции для escape / unescape простого значения (атрибут или тег, а не полный документ) недоступны в стандартных библиотеках XML, включенных в Java.
В результате и на основе различных ответов, которые я видел здесь и в других местах, вот решение, которое я создал (ничего не работает как простая копия / вставка):
public final static String ESCAPE_CHARS = "<>&\"\'"; public final static List ESCAPE_STRINGS = Collections.unmodifiableList(Arrays.asList(new String[] { "<" , ">" , "&" , """ , "'" })); private static String UNICODE_LOW = "" + ((char)0x20); //space private static String UNICODE_HIGH = "" + ((char)0x7f); //should only use for the content of an attribute or tag public static String toEscaped(String content) { String result = content; if ((content != null) && (content.length() > 0)) { boolean modified = false; StringBuilder stringBuilder = new StringBuilder(content.length()); for (int i = 0, count = content.length(); i < count; ++i) { String character = content.substring(i, i + 1); int pos = ESCAPE_CHARS.indexOf(character); if (pos > -1) { stringBuilder.append(ESCAPE_STRINGS.get(pos)); modified = true; } else { if ( (character.compareTo(UNICODE_LOW) > -1) && (character.compareTo(UNICODE_HIGH) < 1) ) { stringBuilder.append(character); } else { stringBuilder.append("&#" + ((int)character.charAt(0)) + ";"); modified = true; } } } if (modified) { result = stringBuilder.toString(); } } return result; }
Вышеприведенное содержит несколько разных вещей:
- избегает использования логики, основанной на символах, до тех пор, пока она абсолютно не понадобится - улучшает совместимость с юникодом
- попытки быть настолько эффективными, насколько это возможно, учитывая вероятность того, что второе условие «если», вероятно, является наиболее используемым путем
- является чистой функцией; т.е. поточно-безопасный
- прекрасно оптимизируется с сборщиком мусора, возвращая только содержимое StringBuilder, если что-то действительно изменилось - в противном случае возвращается исходная строка
В какой-то момент я напишу инверсию этой функции, toUnescaped (). У меня просто нет времени делать это сегодня. Когда я это сделаю, я приду обновить этот ответ с помощью кода. 🙂
Чтобы избежать символов XML, самый простой способ – использовать проект Apache Commons Lang, JAR, загружаемый с: http://commons.apache.org/lang/
Класс выглядит следующим образом: org.apache.commons.lang3.StringEscapeUtils;
У него есть метод под названием «escapeXml», который вернет соответствующую экранированную строку.
Для тех, кто ищет самое быстрое решение: используйте методы из apache commons-lang :
-
StringEscapeUtils.escapeXml10()
для xml 1.0 -
StringEscapeUtils.escapeXml11()
для xml 1.1 -
StringEscapeUtils.escapeXml()
теперь устарел, но использовался обычно в прошлом
Не забудьте включить зависимость:
org.apache.commons commons-lang3 3.5
Этот вопрос составляет восемь лет и все еще не полностью правильный ответ! Нет, вам не нужно будет импортировать весь сторонний API для выполнения этой простой задачи. Плохой совет.
Следующий способ:
- правильно обрабатывать символы вне базовой многоязычной плоскости
- требуемые символы в XML
- избегать любых символов, отличных от ASCII, что является необязательным, но общим
- замените незаконные символы в XML 1.0 символом замещения Unicode. Здесь нет лучшего варианта – удаление их так же важно.
Я попытался оптимизировать для наиболее распространенного случая, все еще гарантируя, что вы могли бы передать / dev / random через это и получить правильную строку в XML.
public static String encodeXML(CharSequence s) { StringBuilder sb = new StringBuilder(); int len = s.length(); for (int i=0;i= 0xd800 && c <= 0xdbff && i + 1 < len) { c = ((c-0xd7c0)<<10) | (s.charAt(++i)&0x3ff); // UTF16 decode } if (c < 0x80) { // ASCII range: test most common case first if (c < 0x20 && (c != '\t' && c != '\r' && c != '\n')) { // Illegal XML character, even encoded. Skip or substitute sb.append("�"); // Unicode replacement character } else { switch(c) { case '&': sb.append("&"); break; case '>': sb.append(">"); break; case '<': sb.append("<"); break; // Uncomment next two if encoding for an XML attribute // case '\'' sb.append("'"); break; // case '\"' sb.append("""); break; default: sb.append((char)c); } } } else if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) { // Illegal XML character, even encoded. Skip or substitute sb.append("�"); // Unicode replacement character } else { sb.append("&#x"); sb.append(Integer.toHexString(c)); sb.append(';'); } } return sb.toString(); }
Изменить: для тех, кто продолжает настаивать на том, чтобы глупо было писать свой собственный код для этого, когда есть превосходные API Java для работы с XML, вам может быть интересно узнать, что StAX API включен в Oracle Java 8 (я еще не тестировал другие ) неправильно кодирует содержимое CDATA: он не убегает]]> последовательностей в контенте. Сторонняя библиотека, даже одна из которых является частью ядра Java, не всегда является лучшим вариантом.
Вот простое решение, и это отлично подходит для кодирования символов с акцентом!
String in = "Hi Lârry & Môe!"; StringBuilder out = new StringBuilder(); for(int i = 0; i < in.length(); i++) { char c = in.charAt(i); if(c < 31 || c > 126 || "<>\"'\\&".indexOf(c) >= 0) { out.append("" + (int) c + ";"); } else { out.append(c); } } System.out.printf("%s%n", out);
Выходы
Hi Lârry & Môe!
Используйте JAXP и забудьте о обработке текста, это будет сделано для вас автоматически.
Попробуйте кодировать XML с помощью сериализатора XML Apache
//Serialize DOM OutputFormat format = new OutputFormat (doc); // as a String StringWriter stringOut = new StringWriter (); XMLSerializer serial = new XMLSerializer (stringOut, format); serial.serialize(doc); // Display the XML System.out.println(stringOut.toString());
Вы можете использовать библиотеку Enterprise Security API (ESAPI) , которая предоставляет такие методы, как encodeForXML
и encodeForXMLAttribute
. Взгляните на документацию интерфейса Encoder ; он также содержит примеры того, как создать экземпляр DefaultEncoder .
Просто замените
& with &
И для других персонажей:
> with > < with < \" with " ' with '