Дуже схоже на це питання , за винятком Java.
Який рекомендований спосіб кодування рядків для виводу XML у Java. Рядки можуть містити символи, такі як "&", "<" тощо.
Дуже схоже на це питання , за винятком Java.
Який рекомендований спосіб кодування рядків для виводу XML у Java. Рядки можуть містити символи, такі як "&", "<" тощо.
Відповіді:
Дуже просто: використовуйте бібліотеку XML. Таким чином, насправді це буде правильно, а не вимагати детальних знань бітів специфікації XML.
Як зазначали інші, використання бібліотеки XML - це найпростіший спосіб. Якщо ви хочете , щоб уникнути себе, ви можете подивитися в StringEscapeUtils
з Apache Commons Lang бібліотеки.
StringEscapeUtils.escapeXml(str)
від commons-lang
. Я використовую його в додатку App Engine - працюйте як шарм. Ось документ Java для цієї функції:
\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();
}
Редагувати: для тих, хто продовжує наполягати на дурному написанні власного коду для цього, коли для роботи з XML існують чудові API Java, можливо, вам хотілося б знати, що 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, IMHO, якщо ви маєте базове уявлення про 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>
Примітка. Ваше питання стосується екранування , а не кодування . Escaping використовує <тощо, щоб парсер міг розрізнити "це команда XML" і "це якийсь текст". Кодування - це матеріал, який ви вказуєте в заголовку XML (UTF-8, ISO-8859-1 тощо).
Перш за все, як і всі інші, використовуйте бібліотеку XML. XML виглядає просто, але кодування та втікання - це темний вуду (що ви помітите, як тільки зіткнетеся з умлаутами та японськими та іншими дивними речами, такими як " цифри на всю ширину " (& # FF11; дорівнює 1)). Забезпечити читання XML для людей - завдання Сизіфа.
Я пропоную ніколи не намагатися бути розумним щодо кодування тексту та екранування в XML. Але нехай це не заважає вам намагатися; просто пам’ятайте, коли це вас вкусить (і так буде).
Тим не менш, якщо ви використовуєте лише UTF-8, щоб зробити речі більш читабельними, ви можете розглянути цю стратегію:
<![CDATA[ ... ]]>
Я використовую це в редакторі SQL, і це дозволяє розробникам вирізати та вставити SQL із сторонніх інструментів SQL у XML, не турбуючись про те, щоб уникнути. Це працює, оскільки SQL не може містити umlauts у нашому випадку, тому я в безпеці.
Хоча я принципово погоджуюсь з Джоном Скітом, іноді у мене немає можливості використовувати зовнішню бібліотеку 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;
}
Вищезазначене вміщує кілька різних речей:
У якийсь момент я напишу інверсію цієї функції доUnescaped (). Я просто не встигаю цього зробити сьогодні. Після цього я прийду оновити цю відповідь кодом. :)
null
персонажа. Чи можете ви пояснити визначення двох значень, UNICODE_LOW
і UNICODE_HIGH
? Перечитайте, if
що використовує ці два значення. Зверніть увагу null
( \u0000
що є (int)0
) не потрапляє між цими двома значеннями. Прочитайте, як він стає належним чином "захищеним" так само, як ВСІ символи Unicode, що існують поза діапазоном UNICODE_LOW
та UNICODE_HIGH
діапазоном, за допомогою цієї &#
техніки.
Щоб уникнути символів XML, найпростіший спосіб - використовувати проект Apache Commons Lang, JAR, який можна завантажити з: http://commons.apache.org/lang/
Клас такий: org.apache.commons.lang3.StringEscapeUtils;
Він має метод з назвою "escapeXml", який повертає належним чином екранований рядок.
Якщо ви шукаєте бібліотеку, щоб виконати роботу, спробуйте:
Гуава 26.0 задокументована тут
return XmlEscapers.xmlContentEscaper().escape(text);
Примітка: Існує також
xmlAttributeEscaper()
Текст 1.4 Apache Commons документально зафіксований тут
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
. Погляньте на документацію до інтерфейсу кодера ; він також містить приклади того, як створити екземпляр 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()
Сподіваюся, це комусь допомагає