Sehr ähnlich zu dieser Frage , außer Java.
Was ist die empfohlene Methode zum Codieren von Zeichenfolgen für eine XML-Ausgabe in Java? Die Zeichenfolgen können Zeichen wie "&", "<" usw. enthalten.
Sehr ähnlich zu dieser Frage , außer Java.
Was ist die empfohlene Methode zum Codieren von Zeichenfolgen für eine XML-Ausgabe in Java? Die Zeichenfolgen können Zeichen wie "&", "<" usw. enthalten.
Antworten:
Ganz einfach: Verwenden Sie eine XML-Bibliothek. Auf diese Weise ist es tatsächlich richtig, anstatt detaillierte Kenntnisse der Bits der XML-Spezifikation zu erfordern.
Wie bereits erwähnt, ist die Verwendung einer XML-Bibliothek der einfachste Weg. Wenn Sie sich selbst entziehen möchten, können Sie in StringEscapeUtils
der Apache Commons Lang- Bibliothek nachsehen .
StringEscapeUtils.escapeXml(str)
von commons-lang
. Ich benutze es in der App Engine-Anwendung - arbeite wie ein Zauber. Hier ist das Java-Dokument für diese Funktion:
\t
, \n
und \r
.
\t
, \n
oder \r
muss entkommen werden?
Benutz einfach.
<![CDATA[ your text here ]]>
Dies erlaubt alle Zeichen außer dem Ende
]]>
Sie können also unzulässige Zeichen wie & und> einfügen. Beispielsweise.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
Attribute müssen jedoch maskiert werden, da CDATA-Blöcke nicht für sie verwendet werden können.
Dies hat für mich gut funktioniert, um eine maskierte Version einer Textzeichenfolge bereitzustellen:
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();
}
}
Versuche dies:
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
.
Diese Frage ist acht Jahre alt und immer noch keine völlig richtige Antwort! Nein, Sie sollten nicht eine vollständige API eines Drittanbieters importieren müssen, um diese einfache Aufgabe auszuführen. Schlechter Rat.
Die folgende Methode wird:
Ich habe versucht, für den häufigsten Fall zu optimieren, während ich trotzdem sicherstellte, dass Sie dies durch / dev / random leiten und eine gültige Zeichenfolge in XML erhalten können.
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();
}
Bearbeiten: Für diejenigen, die weiterhin darauf bestehen, dass es dumm ist, Ihren eigenen Code dafür zu schreiben, wenn es perfekt gute Java-APIs für den Umgang mit XML gibt, möchten Sie vielleicht wissen, dass die StAX-API in Oracle Java 8 enthalten ist (andere habe ich nicht getestet ) codiert CDATA-Inhalte nicht korrekt: Es entgeht nicht]]> Sequenzen im Inhalt. Eine Drittanbieter-Bibliothek, auch eine, die Teil des Java-Kerns ist, ist nicht immer die beste Option.
StringEscapeUtils.escapeXml()
entgeht keinen Steuerzeichen (<0x20). XML 1.1 erlaubt Steuerzeichen; XML 1.0 nicht. Beispielsweise,XStream.toXML()
werden die Steuerzeichen eines Java-Objekts gerne in XML serialisiert, was ein XML 1.0-Parser ablehnt.
Verwenden Sie, um Steuerzeichen mit Apache commons-lang zu umgehen
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
replaceAll
Anrufen ist sehr ineffizient, insbesondere bei großen Zeichenfolgen. Jeder Aufruf führt dazu, dass ein neues String-Objekt erstellt wird, das so lange herumhängt, bis der Müll gesammelt wird. Außerdem muss bei jedem Aufruf die Zeichenfolge erneut durchlaufen werden. Dies könnte in einer einzigen manuellen Schleife mit Vergleichen mit jedem Zielzeichen in jeder Iteration zusammengefasst werden.
Während der Idealismus besagt, dass eine XML-Bibliothek verwendet werden soll, sagt IMHO, wenn Sie eine grundlegende Vorstellung von XML haben, der gesunde Menschenverstand und die Leistung sagen, dass die Vorlage vollständig ist. Es ist wohl auch besser lesbar. Die Verwendung der Escape-Routinen einer Bibliothek ist wahrscheinlich eine gute Idee.
Bedenken Sie: XML wurde von Menschen geschrieben werden soll.
Verwenden Sie Bibliotheken zum Generieren von XML, wenn Sie Ihr XML als "Objekt" haben, um Ihr Problem besser zu modellieren. Zum Beispiel, wenn steckbare Module am Prozess der Erstellung dieses XML beteiligt sind.
Bearbeiten: Wie man XML tatsächlich in Vorlagen maskiert, die Verwendung von CDATA oder escapeXml(string)
von JSTL sind zwei gute Lösungen, escapeXml(string)
die wie folgt verwendet werden können:
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<item>${fn:escapeXml(value)}</item>
Das Verhalten von StringEscapeUtils.escapeXml () wurde von Commons Lang 2.5 auf 3.0 geändert. Unicode-Zeichen größer als 0x7f werden jetzt nicht mehr ausgeblendet.
Dies ist eine gute Sache. Die alte Methode bestand darin, Entitäten zu entkommen, die einfach in ein utf8-Dokument eingefügt werden konnten.
Die neuen Escaper in Google Guava 11.0 scheinen ebenfalls vielversprechend: http://code.google.com/p/guava-libraries/issues/detail?id=799
Für diejenigen, die nach der am schnellsten zu schreibenden Lösung suchen: Verwenden Sie Methoden von apache commons-lang :
StringEscapeUtils.escapeXml10()
für xml 1.0StringEscapeUtils.escapeXml11()
für xml 1.1StringEscapeUtils.escapeXml()
ist jetzt veraltet, wurde aber in der Vergangenheit häufig verwendetDenken Sie daran, die Abhängigkeit einzuschließen:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version> <!--check current version! -->
</dependency>
Hinweis: Bei Ihrer Frage geht es um Escape und nicht um Codierung . Beim Escaping wird <usw. verwendet, damit der Parser zwischen "Dies ist ein XML-Befehl" und "Dies ist Text" unterscheiden kann. Die Codierung wird im XML-Header angegeben (UTF-8, ISO-8859-1 usw.).
Verwenden Sie zunächst, wie alle anderen sagten, eine XML-Bibliothek. XML sieht einfach aus, aber das Codieren + Escape-Material ist dunkles Voodoo (was Sie bemerken werden, sobald Sie auf Umlaute und japanische und andere seltsame Dinge wie " Ziffern voller Breite " stoßen (& # FF11; ist 1)). XML lesbar zu halten, ist eine Aufgabe von Sisyphus.
Ich schlage vor, niemals zu versuchen, klug in Bezug auf Textcodierung und Escape in XML zu sein. Aber lass dich nicht davon abhalten, es zu versuchen. Denken Sie daran, wann es Sie beißt (und es wird).
Wenn Sie jedoch nur UTF-8 verwenden, können Sie diese Strategie in Betracht ziehen, um die Lesbarkeit zu verbessern:
<![CDATA[ ... ]]>
Ich verwende dies in einem SQL-Editor und es ermöglicht den Entwicklern, SQL aus einem SQL-Tool eines Drittanbieters auszuschneiden und in das XML einzufügen, ohne sich Gedanken über das Entkommen machen zu müssen. Dies funktioniert, weil die SQL in unserem Fall keine Umlaute enthalten kann, also bin ich sicher.
Obwohl ich Jon Skeet im Prinzip zustimme, habe ich manchmal nicht die Möglichkeit, eine externe XML-Bibliothek zu verwenden. Und ich finde es merkwürdig, dass die beiden Funktionen zum Escape / Unscape eines einfachen Werts (Attribut oder Tag, nicht vollständiges Dokument) in den in Java enthaltenen Standard-XML-Bibliotheken nicht verfügbar sind.
Als Ergebnis und basierend auf den verschiedenen Antworten, die ich hier und anderswo gesehen habe, ist hier die Lösung, die ich letztendlich erstellt habe (nichts hat als einfaches Kopieren / Einfügen funktioniert):
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;
}
Das Obige berücksichtigt verschiedene Dinge:
Irgendwann werde ich die Inversion dieser Funktion in Uncapsed () schreiben. Ich habe heute einfach keine Zeit dafür. Wenn ich das tue, werde ich diese Antwort mit dem Code aktualisieren. :) :)
Um XML-Zeichen zu entkommen, verwenden Sie am einfachsten das Apache Commons Lang-Projekt, JAR, das heruntergeladen werden kann von: http://commons.apache.org/lang/
Die Klasse lautet wie folgt: org.apache.commons.lang3.StringEscapeUtils;
Es hat eine Methode namens "EscapeXml", die einen entsprechend maskierten String zurückgibt.
Wenn Sie nach einer Bibliothek suchen, um die Arbeit zu erledigen, versuchen Sie:
Guava 26.0 hier dokumentiert
return XmlEscapers.xmlContentEscaper().escape(text);
Hinweis: Es gibt auch eine
xmlAttributeEscaper()
Apache Commons Text 1.4 hier dokumentiert
StringEscapeUtils.escapeXml11(text)
Hinweis: Es gibt auch eine
escapeXml10()
Methode
Hier ist eine einfache Lösung, die sich auch hervorragend zum Codieren von Zeichen mit Akzent eignet!
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);
Ausgänge
Hi Lârry & Môe!
Sie können die ESAPI-Bibliothek (Enterprise Security API) verwenden , die Methoden wie encodeForXML
und bereitstellt encodeForXMLAttribute
. Schauen Sie sich die Dokumentation der Encoder- Schnittstelle an. Es enthält auch Beispiele zum Erstellen einer Instanz von DefaultEncoder .
Einfach ersetzen
& with &
Und für andere Charaktere:
> with >
< with <
\" with "
' with '
Verwenden Sie JAXP und vergessen Sie die Textverarbeitung, die automatisch für Sie erledigt wird.
Versuchen Sie, das XML mit dem Apache XML-Serializer zu codieren
//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());
Folgendes habe ich gefunden, nachdem ich überall nach einer Lösung gesucht habe:
Holen Sie sich die Jsoup-Bibliothek:
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
Dann:
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()
Hoffe das hilft jemandem