Bardzo podobne do tego pytania , z wyjątkiem Javy.
Jaki jest zalecany sposób kodowania ciągów znaków wyjściowych XML w języku Java. Ciągi mogą zawierać znaki takie jak „&”, „<” itp.
Bardzo podobne do tego pytania , z wyjątkiem Javy.
Jaki jest zalecany sposób kodowania ciągów znaków wyjściowych XML w języku Java. Ciągi mogą zawierać znaki takie jak „&”, „<” itp.
Odpowiedzi:
Bardzo prosto: użyj biblioteki XML. W ten sposób faktycznie będzie to właściwe, zamiast wymagać szczegółowej znajomości bitów specyfikacji XML.
Jak wspominali inni, użycie biblioteki XML jest najłatwiejszym sposobem. Jeśli chcesz uciec samemu, można spojrzeć StringEscapeUtils
z Apache Commons Lang bibliotece.
StringEscapeUtils.escapeXml(str)
z commons-lang
. Używam go w aplikacji App Engine - działa jak marzenie. Oto dokument Java dla tej funkcji:
\t
, \n
i \r
.
\t
, \n
czy \r
trzeba uciekać?
Po prostu użyj.
<![CDATA[ your text here ]]>
Pozwoli to na dowolne znaki z wyjątkiem zakończenia
]]>
Możesz więc dołączyć znaki, które byłyby nielegalne, takie jak & i>. Na przykład.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
Jednak atrybuty będą musiały być chronione, ponieważ nie można do nich używać bloków CDATA.
Pomogło mi to, udostępniając wersję ciągu tekstowego z ucieczką:
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();
}
}
Spróbuj tego:
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
.
To pytanie ma już osiem lat i nadal nie jest w pełni poprawną odpowiedzią! Nie, nie musisz importować całego interfejsu API innej firmy, aby wykonać to proste zadanie. Zła rada.
Następująca metoda:
Próbowałem zoptymalizować pod kątem najczęstszego przypadku, jednocześnie zapewniając, że możesz przez to potokować / dev / random i uzyskać prawidłowy ciąg w 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();
}
Edycja: dla tych, którzy nadal upierają się, że pisanie własnego kodu do tego celu jest głupie, gdy istnieją doskonale dobre API Java do obsługi XML, możesz chcieć wiedzieć, że StAX API zawarte w Oracle Java 8 (nie testowałem innych ) nie koduje poprawnie zawartości CDATA: nie zmienia sekwencji]]> w treści. Biblioteka innej firmy, nawet taka, która jest częścią rdzenia Java, nie zawsze jest najlepszą opcją.
StringEscapeUtils.escapeXml()
nie zmienia znaczenia znaków kontrolnych (<0x20). XML 1.1 umożliwia stosowanie znaków sterujących; XML 1.0 nie. Na przykład, XStream.toXML()
szczęśliwie zserializuje znaki sterujące obiektu Java do XML, które parser XML 1.0 odrzuci.
Aby uciec przed postaciami sterującymi z Apache commons-lang, użyj
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
replaceAll
wywołań jest bardzo nieefektywny, szczególnie w przypadku dużych ciągów. Każde wywołanie skutkuje utworzeniem nowego obiektu String, który będzie się zawieszał do czasu zebrania śmieci. Ponadto każde wywołanie wymaga ponownego zapętlenia ciągu. Można to skonsolidować w pojedynczej ręcznej pętli z porównaniami dla każdego znaku docelowego w każdej iteracji.
Podczas gdy idealizm mówi, że używaj biblioteki XML, IMHO jeśli masz podstawową koncepcję XML, wtedy zdrowy rozsądek i wydajność mówi, że szablon to wszystko. Jest też prawdopodobnie bardziej czytelny. Chociaż użycie procedur ucieczki biblioteki jest prawdopodobnie dobrym pomysłem.
Rozważ to: XML została przeznaczona do napisany przez ludzi.
Korzystaj z bibliotek do generowania XML, gdy plik XML jako „obiekt” lepiej modeluje problem. Na przykład, jeśli dołączane moduły uczestniczą w procesie tworzenia tego XML.
Edycja: jeśli chodzi o to, jak faktycznie uciec XML w szablonach, użycie CDATA lub escapeXml(string)
z JSTL to dwa dobre rozwiązania, escapeXml(string)
można ich użyć w następujący sposób:
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<item>${fn:escapeXml(value)}</item>
Zachowanie StringEscapeUtils.escapeXml () zmieniło się z Commons Lang 2.5 na 3.0. Teraz nie wymyka się już znakom Unicode większym niż 0x7f.
To dobrze, stara metoda miała być trochę zbyt chętna do ucieczki z jednostek, które można po prostu wstawić do dokumentu utf8.
Obiecujące wydają się również nowe ucieczki, które zostaną uwzględnione w Google Guava 11.0: http://code.google.com/p/guava-libraries/issues/detail?id=799
Dla tych, którzy szukają rozwiązania najszybszego do napisania: użyj metod z apache commons-lang :
StringEscapeUtils.escapeXml10()
dla xml 1.0StringEscapeUtils.escapeXml11()
dla xml 1.1StringEscapeUtils.escapeXml()
jest obecnie przestarzały, ale w przeszłości był powszechnie używanyPamiętaj o uwzględnieniu zależności:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version> <!--check current version! -->
</dependency>
Uwaga: Twoje pytanie dotyczy ucieczki , a nie kodowania . Escaping polega na użyciu <itp., Aby umożliwić parserowi rozróżnienie między „to jest polecenie XML” a „to jest jakiś tekst”. Kodowanie to to, co określasz w nagłówku XML (UTF-8, ISO-8859-1 itd.).
Przede wszystkim, jak wszyscy mówili, użyj biblioteki XML. XML wygląda na prosty, ale kodowanie i ucieczka to ciemne voodoo (które zauważysz, gdy tylko napotkasz umlauty, japoński i inne dziwne rzeczy, takie jak „ cyfry o pełnej szerokości ” (& # FF11; to 1)). Zapewnienie czytelności XML dla człowieka to zadanie Syzyfa.
Sugeruję, aby nigdy nie próbować być sprytnym w kwestii kodowania tekstu i ucieczki w XML. Ale nie pozwól, aby to powstrzymało cię od prób; pamiętaj tylko, kiedy cię ugryzie (i to zrobi).
To powiedziawszy, jeśli używasz tylko UTF-8, aby uczynić rzeczy bardziej czytelnymi, możesz rozważyć tę strategię:
<![CDATA[ ... ]]>
Używam tego w edytorze SQL i umożliwia programistom wycinanie i wklejanie kodu SQL z narzędzia SQL innej firmy do XML bez martwienia się o ucieczkę. To działa, ponieważ w naszym przypadku SQL nie może zawierać umlautów, więc jestem bezpieczny.
Chociaż zasadniczo zgadzam się z Jonem Skeetem, czasami nie mam możliwości korzystania z zewnętrznej biblioteki XML. Uważam, że jest to osobliwe, że dwie funkcje pozwalające na uniknięcie / cofnięcie prostej wartości (atrybut lub znacznik, a nie pełny dokument) nie są dostępne w standardowych bibliotekach XML dołączonych do języka Java.
W rezultacie i w oparciu o różne odpowiedzi, które widziałem zamieszczone tutaj i gdzie indziej, oto rozwiązanie, które ostatecznie stworzyłem (nic nie działało jako proste kopiowanie / wklejanie):
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;
}
Powyższe obejmuje kilka różnych rzeczy:
W pewnym momencie napiszę odwrócenie tej funkcji, toUnescaped (). Po prostu nie mam dzisiaj na to czasu. Kiedy to zrobię, zaktualizuję tę odpowiedź o kod. :)
null
znak. Czy możesz wyjaśnić definicję dwóch wartości UNICODE_LOW
i UNICODE_HIGH
? Przeczytaj ponownie, if
który używa tych dwóch wartości. Uwaga null
( \u0000
która jest (int)0
) nie mieści się między tymi dwiema wartościami. Przeczytaj, w jaki sposób staje się on prawidłowo „uciekany”, tak jak WSZYSTKIE znaki Unicode istniejące poza zakresem UNICODE_LOW
i UNICODE_HIGH
, używając tej &#
techniki.
Aby uniknąć znaków XML, najłatwiej jest użyć projektu Apache Commons Lang, JAR do pobrania z: http://commons.apache.org/lang/
Jest to klasa: org.apache.commons.lang3.StringEscapeUtils;
Ma metodę o nazwie „escapeXml”, która zwróci ciąg znaków o odpowiednim znaku ucieczki.
Jeśli szukasz biblioteki do wykonania pracy, spróbuj:
Guawa 26,0 udokumentowana tutaj
return XmlEscapers.xmlContentEscaper().escape(text);
Uwaga: istnieje również plik
xmlAttributeEscaper()
Dokumentacja Apache Commons Text 1.4 tutaj
StringEscapeUtils.escapeXml11(text)
Uwaga: jest też
escapeXml10()
metoda
Oto proste rozwiązanie, które świetnie nadaje się również do kodowania znaków akcentowanych!
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);
Wyjścia
Hi Lârry & Môe!
Możesz użyć biblioteki Enterprise Security API (ESAPI) , która udostępnia metody takie jak encodeForXML
i encodeForXMLAttribute
. Zapoznaj się z dokumentacją interfejsu Encodera ; zawiera również przykłady tworzenia instancji DefaultEncoder .
Po prostu wymień
& with &
A dla innych postaci:
> with >
< with <
\" with "
' with '
Skorzystaj z JAXP i zapomnij o obsłudze tekstu, zostanie to zrobione automatycznie.
Spróbuj zakodować XML za pomocą serializatora 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());
Oto, co znalazłem po przeszukaniu wszędzie w poszukiwaniu rozwiązania:
Pobierz bibliotekę Jsoup:
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
Następnie:
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()
Mam nadzieję, że to komuś pomoże