Очень похоже на этот вопрос , за исключением Java.
Каков рекомендуемый способ кодирования строк для вывода XML в Java. Строки могут содержать такие символы, как «&», «<» и т. Д.
Очень похоже на этот вопрос , за исключением Java.
Каков рекомендуемый способ кодирования строк для вывода XML в Java. Строки могут содержать такие символы, как «&», «<» и т. Д.
Ответы:
Очень просто: используйте библиотеку XML. Таким образом, это действительно будет правильно, вместо того, чтобы требовать подробных знаний отдельных частей спецификации XML.
Как уже упоминалось, использование библиотеки XML - самый простой способ. Если вы хотите , чтобы избежать себя, вы можете посмотреть в StringEscapeUtils
из Apache Commons Lang библиотеки.
StringEscapeUtils.escapeXml(str)
из commons-lang
. Я использую его в приложении App Engine - работает как шарм. Вот Java Doc для этой функции:
\t
, \n
и \r
.
\t
, \n
или \r
нужно убежать ?
Просто используйте.
<![CDATA[ your text here ]]>
Это позволит использовать любые символы, кроме окончания
]]>
Таким образом, вы можете включать запрещенные символы, такие как & и>. Например.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
Однако атрибуты необходимо экранировать, поскольку для них нельзя использовать блоки CDATA.
Это хорошо помогло мне предоставить экранированную версию текстовой строки:
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();
}
}
Попробуй это:
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();
}
t==null
.
Этому вопросу восемь лет, и он все еще не является полностью правильным! Нет, вам не нужно импортировать весь сторонний 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, не всегда лучший вариант.
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))
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
replaceAll
вызовов очень неэффективно, особенно для больших строк. Каждый вызов приводит к созданию нового объекта String, который будет висеть до тех пор, пока не будет собран мусор. Кроме того, каждый вызов требует повторного прохождения строки. Это можно объединить в один ручной цикл со сравнениями с каждым целевым символом на каждой итерации.
В то время как идеализм говорит, что используйте 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
Для тех, кто ищет наиболее быстрое решение: используйте методы из 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» и «это некоторый текст». Кодировка - это то, что вы указываете в заголовке XML (UTF-8, ISO-8859-1 и т. Д.).
Прежде всего, как все говорили, используйте библиотеку XML. XML выглядит простым, но кодирование + экранирование - это темное вуду (которое вы заметите, как только встретите умляуты, японский язык и другие странные вещи, такие как « цифры полной ширины » (& # FF11; равно 1)). Обеспечение удобочитаемости XML - это задача Сизифа.
Я предлагаю никогда не хитрить в кодировке текста и экранировании в XML. Но не позволяйте этому останавливать вас от попыток; просто помните, когда он вас укусит (и будет).
Тем не менее, если вы используете только UTF-8, чтобы сделать вещи более читаемыми, вы можете рассмотреть эту стратегию:
<![CDATA[ ... ]]>
Я использую это в редакторе SQL, и это позволяет разработчикам вырезать и вставлять SQL из стороннего инструмента SQL в XML, не беспокоясь об экранировании. Это работает, потому что в нашем случае SQL не может содержать умляутов, так что я в безопасности.
Хотя я в принципе согласен с Джоном Скитом, иногда у меня нет возможности использовать внешнюю библиотеку XML. И мне кажется странным, что две функции для экранирования / отмены экранирования простого значения (атрибута или тега, а не полного документа) недоступны в стандартных библиотеках 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_NULL = "" + ((char)0x00); //null
private static String UNICODE_LOW = "" + ((char)0x20); //space
private static String UNICODE_HIGH = "" + ((char)0x7f);
//should only be used 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 {
//Per URL reference below, Unicode null character is always restricted from XML
//URL: https://en.wikipedia.org/wiki/Valid_characters_in_XML
if (character.compareTo(UNICODE_NULL) != 0) {
stringBuilder.append("&#" + ((int)character.charAt(0)) + ";");
}
modified = true;
}
}
}
if (modified) {
result = stringBuilder.toString();
}
}
return result;
}
Вышеупомянутое включает несколько разных вещей:
В какой-то момент я напишу инверсию этой функции toUnescaped (). У меня просто нет на это времени сегодня. Когда я это сделаю, я обновлю этот ответ кодом. :)
null
символ. Можете ли вы объяснить определение двух значений UNICODE_LOW
и UNICODE_HIGH
? Пожалуйста, перечитайте, if
что использует эти два значения. Уведомление null
( \u0000
которое есть (int)0
) не находится между этими двумя значениями. Читайте о том, как она становится правильно «убежала» так же , как существующие вне ALL Unicode символов UNICODE_LOW
и UNICODE_HIGH
диапазона, используя &#
технику.
Чтобы избежать символов XML, проще всего использовать проект Apache Commons Lang, JAR загружаемый с: http://commons.apache.org/lang/
Это класс: org.apache.commons.lang3.StringEscapeUtils;
У него есть метод с именем "escapeXml", который возвращает строку с соответствующим экранированием.
Если вы ищете библиотеку для работы, попробуйте:
Guava 26.0 задокументирован здесь
return XmlEscapers.xmlContentEscaper().escape(text);
Примечание: есть также
xmlAttributeEscaper()
Документированный здесь Apache Commons Text 1.4
StringEscapeUtils.escapeXml11(text)
Примечание: существует также
escapeXml10()
метод
Вот простое решение, и оно отлично подходит для кодирования акцентированных символов!
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!
Вы можете использовать библиотеку Enterprise Security API (ESAPI) , которая предоставляет такие методы, как encodeForXML
и encodeForXMLAttribute
. Взгляните на документацию интерфейса Encoder ; он также содержит примеры того, как создать экземпляр DefaultEncoder .
Просто замените
& with &
И для других персонажей:
> with >
< with <
\" with "
' with '
Используйте JAXP и забудьте об обработке текста, это будет сделано за вас автоматически.
Попробуйте закодировать XML с помощью сериализатора Apache XML
//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());
Вот что я нашел после повсеместных поисков решения:
Получите библиотеку Jsoup:
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
Затем:
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Entities
import org.jsoup.parser.Parser
String xml = '''<?xml version = "1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV = "http://www.w3.org/2001/12/soap-envelope"
SOAP-ENV:encodingStyle = "http://www.w3.org/2001/12/soap-encoding">
<SOAP-ENV:Body xmlns:m = "http://www.example.org/quotations">
<m:GetQuotation>
<m:QuotationsName> MiscroSoft@G>>gle.com </m:QuotationsName>
</m:GetQuotation>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'''
Document doc = Jsoup.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")), "UTF-8", "", Parser.xmlParser())
doc.outputSettings().charset("UTF-8")
doc.outputSettings().escapeMode(Entities.EscapeMode.base)
println doc.toString()
Надеюсь, это кому-то поможет
Я создал здесь свою оболочку, надеюсь, она мне очень поможет. Нажмите здесь. Вы можете изменить в зависимости от ваших требований.