wake-up-neo.com

Bester Weg, um Textdaten für XML in Java zu kodieren?

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.

82
Epaga

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.

39
Jon Skeet

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 aus der Apache Commons Lang Bibliothek schauen.

113
Fabian Steeg

Benutz einfach.

<![CDATA[ your text here ]]>

Dies erlaubt alle Zeichen außer der Endung 

]]>

Sie können also unzulässige Zeichen wie & und> einfügen. Zum Beispiel.

<element><![CDATA[ characters such as & and > are allowed ]]></element>

Attribute müssen jedoch mit Escapezeichen versehen werden, da für sie keine CDATA-Blöcke verwendet werden können.

18
ng.

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("&lt;"); break;
      case '>': sb.append("&gt;"); break;
      case '\"': sb.append("&quot;"); break;
      case '&': sb.append("&amp;"); break;
      case '\'': sb.append("&apos;"); break;
      default:
         if(c>0x7e) {
            sb.append("&#"+((int)c)+";");
         }else
            sb.append(c);
      }
   }
   return sb.toString();
}
14
Pointer Null

Das hat gut funktioniert für mich, um eine Escape-Version einer Textzeichenfolge zur Verfügung zu stellen:

public class XMLHelper {

/**
 * Returns the string where all non-ascii and <, &, > are encoded as numeric entities. I.e. "&lt;A &amp; B &gt;"
 * .... (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() escape Steuerzeichen nicht (<0x20). XML 1.1 erlaubt Steuerzeichen. XML 1.0 nicht. Beispielsweise serialisiert XStream.toXML() die Steuerzeichen eines Java-Objekts glücklich in XML, die ein XML 1.0-Parser zurückweist.

Um Steuerzeichen mit Apache commons-lang zu umgehen, verwenden Sie

NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
8
Steve Mitchell
public String escapeXml(String s) {
    return s.replaceAll("&", "&amp;").replaceAll(">", "&gt;").replaceAll("<", "&lt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
}
6
iCrazybest

Diese Frage ist acht Jahre alt und noch immer keine vollkommen richtige Antwort! Nein, Sie müssen nicht die gesamte API eines Drittanbieters importieren müssen, um diese einfache Aufgabe auszuführen. Schlechter Rat.

Die folgende Methode wird:

  • mit Zeichen außerhalb der mehrsprachigen Grundebene korrekt umgehen
  • escape-Zeichen in XML erforderlich
  • nicht-ASCII-Zeichen darf nicht verwendet werden. Dies ist optional, aber häufig
  • ersetzen Sie illegal - Zeichen in XML 1.0 durch das Unicode-Ersetzungszeichen. Es gibt keine beste Option hier - das Entfernen von ihnen ist genauso gültig.

Ich habe versucht, die Optimierung für den häufigsten Fall zu optimieren, wobei sichergestellt ist, dass Sie/dev/random durchlaufen und einen gültigen String 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("&#xfffd;");   // Unicode replacement character
            } else {
                switch(c) {
                  case '&':  sb.append("&amp;"); break;
                  case '>':  sb.append("&gt;"); break;
                  case '<':  sb.append("&lt;"); break;
                  // Uncomment next two if encoding for an XML attribute
//                  case '\''  sb.append("&apos;"); break;
//                  case '\"'  sb.append("&quot;"); break;
                  // Uncomment next three if you prefer, but not required
//                  case '\n'  sb.append("&#10;"); break;
//                  case '\r'  sb.append("&#13;"); break;
//                  case '\t'  sb.append("&#9;"); 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("&#xfffd;");   // Unicode replacement character
        } else {
            sb.append("&#x");
            sb.append(Integer.toHexString(c));
            sb.append(';');
        }
    }
    return sb.toString();
}

Edit: für diejenigen, die weiterhin darauf bestehen, dass es dumm ist, eigenen Code dafür zu schreiben, wenn es vollkommen gute Java-APIs für den Umgang mit XML gibt, möchten Sie vielleicht wissen, dass die in Oracle Java 8 enthaltene StAX-API (ich habe keine Andere getestet) codiert den CDATA-Inhalt nicht richtig: Es entgeht nicht]]> Sequenzen im Inhalt. Eine Drittanbieter-Bibliothek, auch wenn sie zum Java-Kern gehört, ist nicht immer die beste Option.

6
Mike B

Während Idealismus sagt, verwenden Sie eine XML-Bibliothek. Wenn Sie eine grundlegende Vorstellung von XML haben, sagt IMHO, dass der gesunde Menschenverstand und die Leistung es als Ganzes bezeichnen. Es ist wohl auch lesbarer. Die Verwendung der Fluchtroutinen einer Bibliothek ist jedoch wahrscheinlich eine gute Idee.

Bedenken Sie Folgendes: XML war soll von Menschen geschrieben werden.

Verwenden Sie Bibliotheken zum Generieren von XML, wenn Ihr XML als "Objekt" das Problem besser modelliert. Zum Beispiel, wenn steckbare Module an der Erstellung dieser XML beteiligt sind.

Edit: Wie Sie XML in Templates tatsächlich entziehen, sind die Verwendung von CDATA oder escapeXml(string) aus JSTL zwei gute Lösungen. escapeXml(string) kann folgendermaßen verwendet werden:

<%@taglib prefix="fn" uri="http://Java.Sun.com/jsp/jstl/functions"%>

<item>${fn:escapeXml(value)}</item>
6
Amr Mostafa

Das Verhalten von StringEscapeUtils.escapeXml () hat sich von Commons Lang 2.5 in 3.0 .. geändert. Jetzt werden Unicode-Zeichen, die größer als 0x7f sind, nicht mehr entgangen.

Das ist eine gute Sache, die alte Methode war etwas zu eifrig, um Entitäten zu entgehen, die nur in ein utf8-Dokument eingefügt werden konnten.

Vielversprechend scheinen auch die neuen Escapers in Google Guava 11.0 zu sein: http://code.google.com/p/guava-libraries/issues/detail?id=799

6

Hinweis: Ihre Frage bezieht sich auf escaping, nicht auf encoding. Für das Escaping wird <, usw. verwendet, damit der Parser zwischen "Dies ist ein XML-Befehl" und "Dies ist etwas Text" unterscheiden kann. Die Kodierung ist das, was Sie im XML-Header angeben (UTF-8, ISO-8859-1 usw.).

Verwenden Sie, wie alle anderen sagten, zunächst eine XML-Bibliothek. XML sieht zwar einfach aus, aber die Kodierung + das Escape-Zeug ist dunkles Voodoo (was Sie sofort bemerken werden, wenn Sie auf Umlaute und japanische und andere seltsame Dinge wie " full width digits " (& # FF11; ist 1)) stoßen. XML lesbar zu halten ist eine Aufgabe von Sisyphus.

Ich schlage vor, niemals zu versuchen, klug über das Kodieren von Text und das Fluchen in XML zu sein. Aber lassen Sie sich nicht davon abhalten, es zu versuchen. Erinnere dich einfach, wann es dich beißt (und es wird).

Wenn Sie jedoch nur UTF-8 verwenden, können Sie die folgende Strategie in Betracht ziehen, um die Lesbarkeit zu verbessern.

  • Wenn der Text '<', '>' oder '&' enthält, wickeln Sie ihn in <![CDATA[ ... ]]> ein.
  • Wenn der Text diese drei Zeichen nicht enthält, verzerren Sie ihn nicht.

Ich verwende dies in einem SQL-Editor und ermöglicht es den Entwicklern, SQL aus einem SQL-Tool eines Drittanbieters in XML zu kopieren, ohne sich Gedanken darüber machen zu müssen, wie es umgeht. Das funktioniert, weil die SQL in unserem Fall keine Umlaute enthalten kann, also bin ich sicher.

5
Aaron Digulla

Für diejenigen, die die schnellste Lösung suchen: Verwenden Sie Methoden aus Apache commons-lang :

Denken Sie daran, die Abhängigkeit einzubeziehen:

<dependency>
  <groupId>org.Apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>3.5</version> <!--check current version! -->
</dependency>
4
Dariusz

Obwohl ich mit Jon Skeet grundsätzlich einverstanden bin, habe ich manchmal keine Möglichkeit, eine externe XML-Bibliothek zu verwenden. Und ich finde es eigenartig, dass die beiden Funktionen, um einen einfachen Wert (Attribut oder Tag, nicht volles Dokument) zu umgehen/zu entschlüsseln, 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 gepostet habe, ist hier die Lösung, die ich am Ende erstellt habe (nichts funktionierte als einfaches Kopieren/Einfügen):

  public final static String ESCAPE_CHARS = "<>&\"\'";
  public final static List<String> ESCAPE_STRINGS = Collections.unmodifiableList(Arrays.asList(new String[] {
      "&lt;"
    , "&gt;"
    , "&amp;"
    , "&quot;"
    , "&apos;"
  }));

  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 beherbergt verschiedene Dinge:

  1. vermeidet die Verwendung einer char-basierten Logik, bis dies unbedingt erforderlich ist - verbessert die Unicode-Kompatibilität
  2. versuche, so effizient wie möglich zu sein, angesichts der Wahrscheinlichkeit ist die zweite "Wenn" -Bedingung wahrscheinlich der am häufigsten verwendete Weg
  3. ist eine reine Funktion; d.h. ist fadensicher
  4. optimiert den Garbage Collector, indem er den Inhalt des StringBuilder nur dann zurückgibt, wenn sich tatsächlich etwas geändert hat - andernfalls wird der ursprüngliche String zurückgegeben

Irgendwann werde ich die Inversion dieser Funktion schreiben, toUnescaped (). Ich habe heute einfach keine Zeit dafür. Wenn ich dies tue, werde ich diese Antwort mit dem Code aktualisieren. :)

4

Um XML-Zeichen zu umgehen, verwenden Sie das Apache Commons Lang-Projekt. JAR kann von folgender Website heruntergeladen werden: http://commons.Apache.org/lang/

Die Klasse ist dies: org.Apache.commons.lang3.StringEscapeUtils;

Es hat eine Methode mit dem Namen "escapeXml", die einen entsprechend maskierten String zurückgibt. 

3
Greg Burdett

Hier ist eine einfache Lösung, die sich hervorragend für das Kodieren 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);

Ausgaben

Hi L&#226;rry &#38; M&#244;e!
1
Mike

Wenn Sie nach einer Bibliothek suchen, um die Arbeit zu erledigen, versuchen Sie Folgendes:

  1. Guave 26. dokumentiert hier

    return XmlEscapers.xmlContentEscaper().escape(text);

    Hinweis: Es gibt auch eine xmlAttributeEscaper()

  2. Apache Commons Text 1.4 dokumentiert hier

    StringEscapeUtils.escapeXml11(text)

    Hinweis: Es gibt auch eine escapeXml10() -Methode

1
jschnasse

Verwenden Sie JAXP und vergessen Sie die Textverarbeitung, die für Sie automatisch erledigt wird.

0

Einfach austauschen

 & with &amp;

Und für andere Charaktere:

> with &gt;
< with &lt;
\" with &quot;
' with &apos;
0
raman rayat

Versuchen Sie, das XML mit dem XML-Serializer von Apache zu kodieren 

//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());
0
K Victor Rajan

Sie können die Bibliothek Enterprise Security API (ESAPI) verwenden, die Methoden wie encodeForXML und encodeForXMLAttribute bereitstellt. Sehen Sie sich die Dokumentation der Encoder -Schnittstelle an. Es enthält auch Beispiele zum Erstellen einer Instanz von DefaultEncoder .

0
Vivit