Лучший способ кодировать текстовые данные для XML в Java? - PullRequest
85 голосов
/ 13 января 2009

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

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

Ответы [ 20 ]

114 голосов
/ 13 января 2009

Как уже упоминалось, использование библиотеки XML является самым простым способом. Если вы действительно хотите убежать от себя, вы можете заглянуть в StringEscapeUtils из библиотеки Apache Commons Lang .

39 голосов
/ 13 января 2009

Очень просто: использовать библиотеку XML. Таким образом, на самом деле это будет правильно вместо того, чтобы требовать детального знания битов спецификации XML.

18 голосов
/ 13 января 2009

Просто используйте.

<![CDATA[ your text here ]]>

Это позволит использовать любые символы, кроме окончания

]]>

Таким образом, вы можете включить недопустимые символы, такие как & и>. Например.

<element><![CDATA[ characters such as & and > are allowed ]]></element>

Однако атрибуты необходимо экранировать, поскольку блоки CDATA не могут использоваться для них.

14 голосов
/ 06 апреля 2012

Попробуйте это:

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("&lt;"); break;
      case '>': sb.append("&gt;"); break;
      case '\"': sb.append("&quot;"); break;
      case '&': sb.append("&amp;"); break;
      case '\'': sb.append("&apos;"); break;
      default:
         if(c>0x7e) {
            sb.append("&#"+((int)c)+";");
         }else
            sb.append(c);
      }
   }
   return sb.toString();
}
13 голосов
/ 13 января 2009

Это помогло мне предоставить экранированную версию текстовой строки:

public class XMLHelper {

/**
 * Returns the string where all non-ascii and <, &, > are encoded as numeric entities. I.e. "&lt;A &amp; B &gt;"
 * .... (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();
}

}
8 голосов
/ 31 августа 2012

StringEscapeUtils.escapeXml() не экранирует управляющие символы (<0x20). XML 1.1 позволяет контролировать символы; XML 1.0 нет. Например, <code>XStream.toXML() успешно сериализует управляющие символы объекта Java в XML, который синтаксический анализатор XML 1.0 отклонит.

Чтобы избежать управляющих символов с помощью Apache commons-lang, используйте

NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
8 голосов
/ 02 февраля 2018

Этому вопросу восемь лет, и он до сих пор не совсем правильный ответ! Нет, вам не нужно импортировать весь сторонний 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<len;i++) {
        int c = s.charAt(i);
        if (c >= 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("&#xfffd;");   // Unicode replacement character
            } else {
                switch(c) {
                  case '&':  sb.append("&amp;"); break;
                  case '>':  sb.append("&gt;"); break;
                  case '<':  sb.append("&lt;"); break;
                  // Uncomment next two if encoding for an XML attribute
//                  case '\''  sb.append("&apos;"); break;
//                  case '\"'  sb.append("&quot;"); break;
                  // Uncomment next three if you prefer, but not required
//                  case '\n'  sb.append("&#10;"); break;
//                  case '\r'  sb.append("&#13;"); break;
//                  case '\t'  sb.append("&#9;"); 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("&#xfffd;");   // Unicode replacement character
        } else {
            sb.append("&#x");
            sb.append(Integer.toHexString(c));
            sb.append(';');
        }
    }
    return sb.toString();
}

Редактировать: для тех, кто продолжает настаивать на том, что глупо писать свой собственный код для этого, когда есть совершенно хорошие Java API для работы с XML, вам может быть полезно знать, что StAX API включен в Oracle Java 8 ( Я не проверял других) не в состоянии правильно кодировать содержимое CDATA: он не экранирует]]> последовательности в содержимом. Сторонняя библиотека, даже та, которая является частью ядра Java, не всегда является лучшим вариантом.

6 голосов
/ 01 декабря 2011

Поведение 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

6 голосов
/ 16 сентября 2014
public String escapeXml(String s) {
    return s.replaceAll("&", "&amp;").replaceAll(">", "&gt;").replaceAll("<", "&lt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
}
6 голосов
/ 19 мая 2010

В то время как идеализм говорит, что используйте библиотеку XML, ИМХО, если у вас есть базовое представление об XML, тогда здравый смысл и производительность говорят о том, что шаблон должен быть полностью. Возможно, это более читабельно. Хотя использование экранирующих подпрограмм библиотеки, вероятно, хорошая идея.

Подумайте об этом: XML был предназначен для написания людьми.

Использование библиотек для генерации XML, когда ваш XML в качестве "объекта" лучше моделирует вашу проблему. Например, если подключаемые модули участвуют в процессе создания этого XML.

Редактировать: что касается того, как на самом деле экранировать XML в шаблонах, использование CDATA или escapeXml(string) из JSTL - это два хороших решения, escapeXml(string) можно использовать так:

<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

<item>${fn:escapeXml(value)}</item>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...