Очень похоже на этот вопрос, за исключением Java.
Каков рекомендуемый способ кодирования строк для вывода XML в Java. Строки могут содержать символы типа "&", "<" и т.д.
Очень похоже на этот вопрос, за исключением Java.
Каков рекомендуемый способ кодирования строк для вывода XML в Java. Строки могут содержать символы типа "&", "<" и т.д.
Очень просто: используйте библиотеку XML. Таким образом, на самом деле это будет правильно, вместо того чтобы требовать подробного знания битов спецификации XML.
Как уже упоминалось, использование библиотеки XML является самым простым способом. Если вы хотите сбежать, вы можете посмотреть StringEscapeUtils
из Библиотека Apache Commons Lang.
Просто используйте.
<![CDATA[ your text here ]]>
Это позволит использовать любые символы, кроме окончания
]]>
Таким образом, вы можете включать символы, которые были бы незаконными, такие как и и > . Например.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
Однако атрибуты должны быть экранированы, поскольку для них нельзя использовать блоки CDATA.
Попробуйте следующее:
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();
}
Это сработало для меня, чтобы обеспечить экранированную версию текстовой строки:
public class XMLHelper {
/**
* Returns the string where all non-ascii and <, &, > are encoded as numeric entities. I.e. "<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();
}
}
StringEscapeUtils.escapeXml()
не выходит из управляющих символов (< 0x20). XML 1.1 позволяет управлять символами; В XML 1.0 нет. Например, XStream.toXML()
с радостью будет сериализовать символы управления объектами Java в XML, которые будет отклонять парсер XML 1.0.
Чтобы избежать контроля над символами с помощью Apocal 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"%>
<item>${fn:escapeXml(value)}</item>
Поведение 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
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
Примечание. Ваш вопрос касается экранирования, а не кодирования. Escaping использует <, и т.д., Чтобы позволить синтаксическому анализатору различать "это XML-команда" и "это какой-то текст". Кодировка - это материал, который вы указываете в заголовке XML (UTF-8, ISO-8859-1 и т.д.).
Прежде всего, как и все остальные, используйте библиотеку XML. XML выглядит просто, но кодирование + экранирование - это темное вуду (которое вы заметите, как только увидите столкновение с умляутами и японскими и другими странными вещами вроде " цифры полной ширины" (& # FF11; 1)). Хранение XML-данных для чтения является задачей Sisyphus.
Я предлагаю никогда не пытаться быть умным в кодировании и экранировании текста в XML. Но не позволяйте этому мешать вам пытаться; просто помните, когда он вас укусит (и он будет).
Тем не менее, если вы используете только UTF-8, чтобы сделать чтение более понятным, вы можете рассмотреть эту стратегию:
<![CDATA[ ... ]]>
Я использую это в редакторе SQL, и это позволяет разработчикам разрезать и вставлять SQL из стороннего SQL-инструмента в XML, не беспокоясь об экранировании. Это работает, потому что SQL не может содержать umlauts в нашем случае, поэтому я в безопасности.
Этот вопрос восемь лет и до сих пор не совсем правильный ответ! Нет, вам не нужно импортировать весь сторонний API для выполнения этой простой задачи. Плохой совет
Следующий метод будет:
Я попытался оптимизировать работу для наиболее распространенного случая, при этом гарантируя, что вы сможете передать через него /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("�"); // 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;
// Uncomment next three if you prefer, but not required
// case '\n' sb.append(" "); break;
// case '\r' sb.append(" "); break;
// case '\t' 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();
}
Редактировать: для тех, кто продолжает настаивать на том, что глупо писать свой собственный код для этого, когда есть совершенно хорошие Java API для работы с XML, вам может быть интересно узнать, что StAX API включен в Oracle Java 8 (другие я не тестировал ) не может правильно кодировать содержимое CDATA: оно не скрывается]]> последовательностей в содержимом. Сторонняя библиотека, даже та, которая является частью ядра Java, не всегда является лучшим вариантом.
Хотя я согласен с Джоном Скитом в принципе, иногда у меня нет возможности использовать внешнюю библиотеку XML. И я считаю, что две функции для escape/unescape простого значения (атрибут или тег, а не полный документ) недоступны в стандартных XML-библиотеках, включенных в Java.
В результате и на основе разных ответов, которые я видел здесь и в других местах, вот решение, которое я создал (ничего не работает как простая копия/вставка):
public final static String ESCAPE_CHARS = "<>&\"\'";
public final static List<String> 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;
}
Вышеприведенное содержит несколько разных вещей:
В какой-то момент я напишу инверсию этой функции, toUnescaped(). У меня просто нет времени делать это сегодня. Когда я это сделаю, я приду обновить этот ответ с помощью кода.:)
Для тех, кто ищет самое быстрое решение: используйте методы из apache commons-lang:
StringEscapeUtils.escapeXml10()
для xml 1.0StringEscapeUtils.escapeXml11()
для xml 1.1StringEscapeUtils.escapeXml()
теперь устарел, но использовался обычно в прошломНе забудьте включить зависимость:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version> <!--check current version! -->
</dependency>
Чтобы избежать символов XML, самый простой способ - использовать проект Apache Commons Lang, JAR, загружаемый из: http://commons.apache.org/lang/
Класс выглядит следующим образом: org.apache.commons.lang3.StringEscapeUtils;
У него есть метод с именем "escapeXml", который вернет соответствующую экранированную строку.
Здесь простое решение, и оно отлично подходит для кодирования символов с акцентом!
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.
Если вы ищете библиотеку, чтобы выполнить работу, попробуйте:
Гуава 26.0 документирована здесь
return XmlEscapers.xmlContentEscaper().escape(text);
Примечание: есть также
xmlAttributeEscaper()
Apache Commons Text 1.4 задокументирован здесь
StringEscapeUtils.escapeXml11(text)
Примечание. Существует также метод
escapeXml10()
Просто замени
& with &
И для других персонажей:
> with >
< with <
\" with "
' with '