Лучший способ кодирования текстовых данных для XML в Java?

Очень похоже на этот вопрос , кроме Java.

Каков рекомендуемый способ кодирования строк для вывода XML в Java. Строки могут содержать символы типа «&», «<» и т. Д.

Очень просто: используйте библиотеку 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; } 

Вышеприведенное содержит несколько разных вещей:

  1. избегает использования логики, основанной на символах, до тех пор, пока она абсолютно не понадобится - улучшает совместимость с юникодом
  2. попытки быть настолько эффективными, насколько это возможно, учитывая вероятность того, что второе условие «если», вероятно, является наиболее используемым путем
  3. является чистой функцией; т.е. поточно-безопасный
  4. прекрасно оптимизируется с сборщиком мусора, возвращая только содержимое 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 ' 
  • «Тип не ожидается», используя DataContractSerializer - но это просто class, не смешные вещи?
  • Java-реализация преобразования JSON в XML
  • Как бы вы сравнили два XML-документа?
  • android.view.InflateException: двоичная строка XML-файла # 12: ошибка раздувания classа
  • Как использовать XPath с XElement или LINQ?
  • xml.LoadData. Данные на корневом уровне недопустимы. Строка 1, позиция 1
  • Что такое пространство приложений Android для Android?
  • Округленный угол SVG
  • Java-анализ XML-документа дает «Недопустимый контент в prologе». Error
  • XML - данные на корневом уровне недействительны
  • Создание формы треугольника с использованием определений xml?
  • Давайте будем гением компьютера.