Le meilleur moyen d'encoder des données texte pour XML en Java?

93

Très similaire à cette question , sauf pour Java.

Quelle est la méthode recommandée pour encoder des chaînes pour une sortie XML en Java. Les chaînes peuvent contenir des caractères tels que "&", "<", etc.

Epaga
la source

Réponses:

41

Très simplement: utilisez une bibliothèque XML. De cette façon, ce sera en fait correct au lieu d'exiger une connaissance détaillée des bits de la spécification XML.

Jon Skeet
la source
25
Pouvez-vous recommander une telle bibliothèque? (Je trouve surprenant que ce ne soit pas une partie standard de l'édition Java 5 ... une tâche aussi courante).
Tim Cooper
4
XML fait partie du framework Java standard - regardez dans org.w3c.sax et org.w3c.dom. Cependant, il existe également un cadre plus facile à utiliser, tel que JDom. Notez qu'il n'y a peut-être pas de méthode "d'encodage de chaînes pour la sortie XML" - je recommandais plutôt que toute la tâche XML soit effectuée avec une bibliothèque plutôt que de faire des bits à la fois avec une manipulation de chaînes.
Jon Skeet
1
Ce n'est pas un conseil si utile lors de la sortie XHTML - FlyingSaucer nécessite du XML, mais il n'y a aucun moyen de créer un modèle via une bibliothèque XML :). Heureusement, StringTemplate me permet d'échapper rapidement à tous les objets String.
Stephen
4
@mice: La question est étiquetée Java, et Java a beaucoup de bibliothèques XML. En effet, il existe des API XML intégrées à Java, il ne serait donc pas nécessaire d'ajouter quoi que ce soit d' autre ... mais même si vous le faisiez, quelques centaines de K sont rarement un problème en dehors du mobile de nos jours. Même si ce n'était pas Java, je me méfierais beaucoup de développer sur une plate-forme qui n'a pas d'API XML ...
Jon Skeet
2
@mice: L'API DOM est parfaitement capable de générer du XML. Ou il existe d'assez petites bibliothèques tierces. (Le fichier jar de JDom pèse par exemple 114 Ko.) L' utilisation d'une API XML est toujours la méthode recommandée pour créer du XML.
Jon Skeet
124

Comme d'autres l'ont mentionné, l'utilisation d'une bibliothèque XML est le moyen le plus simple. Si vous voulez vous échapper, vous pouvez consulter StringEscapeUtilsla bibliothèque Apache Commons Lang .

Fabian Steeg
la source
Cela pourrait être la voie à suivre si vous ne vous souciez pas de l'exactitude absolue, par exemple si vous créez un prototype.
Chase Seibert
2
Utiliser à StringEscapeUtils.escapeXml(str)partir de commons-lang. Je l'utilise dans l'application App Engine - fonctionne comme un charme. Voici le Java Doc pour cette fonction:
Oleg K
La méthode escapeXml de StringEscapeUtils semble être un peu coûteuse. Existe-t-il une méthode plus efficace qui opère sur un StringBuffer au lieu d'un String?
CKing le
Cette méthode fonctionne-t-elle pour le contenu XML et les attributs? Pour moi, il semble que cela ne fonctionne pas pour les attributs. Il ne semble pas s'échapper \t, \net \r.
Lii du
@Lii et \t, \nou \rdoit être échappé?
Betlista le
20

Utilisez simplement.

<![CDATA[ your text here ]]>

Cela permettra à tous les caractères sauf la fin

]]>

Vous pouvez donc inclure des caractères qui seraient illégaux tels que & et>. Par exemple.

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

Cependant, les attributs devront être échappés car les blocs CDATA ne peuvent pas être utilisés pour eux.

ng.
la source
11
Dans la plupart des cas, ce n'est pas ce que vous devriez faire. Trop de gens abusent des balises CDATA. Le but du CDATA est de dire au processeur de ne pas le traiter comme XML et de simplement le transmettre. Si vous essayez de créer un fichier XML, vous devez créer du XML, pas simplement passer des octets à travers un élément d'encapsulation.
Mads Hansen
2
@Mads, l'utilisation de CDATA aboutit à un fichier XML valide, c'est donc aussi bien que de le faire de la «bonne manière». Si vous ne l'aimez pas, analysez-le ensuite, transformez-le et imprimez-le.
Thorbjørn Ravn Andersen
24
Si vous encapsulez du texte dans un élément CDATA, vous devez échapper le marqueur de fermeture CDATA: "]]>" ... sauf que vous ne pouvez pas y échapper. Donc, à la place, vous devez diviser votre code en morceaux où vous mettez la moitié des données dans un élément CDATA et l'autre moitié en une seconde: <! [CDATA [Ces données contiennent un marqueur de fermeture CDATA: "]]]]> <! [CDATA [> "c'est pourquoi il a fallu le séparer.]]> ... En fin de compte, il peut être beaucoup plus simple d'échapper à '<', '>' et '&' à la place. Bien sûr, de nombreuses applications ignorent le problème potentiel des marqueurs de fermeture CDATA dans les données. L'ignorance est un bonheur je suppose. :)
Stijn de Witt
3
@StijndeWitt a tout à fait raison. CDATA n'est pas une panacée pour échapper des caractères spéciaux.
dnault
C'est une mauvaise idée. CDATA n'autorise aucun caractère en dehors du codage XML.
Florian F
14

Cela a bien fonctionné pour moi pour fournir une version échappée d'une chaîne de texte:

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();
}

}
Thorbjørn Ravn Andersen
la source
1
stringBuffer.append ("& #" + (int) ch + ";"); Cela ne fonctionnera pas pour les caractères multi-octets. Je rencontre ça en ce moment avec un caractère emoji, séquence UTF8 F0 9F 98 8D.
Kylar
14

Essaye ça:

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();
}
Pointeur nul
la source
8
Vous avez au moins deux bugs que je peux voir. L'un est subtil, l'autre non. Je n'aurais pas un tel bug - parce que je ne réinventerais pas la roue en premier lieu.
Jon Skeet
1
Et itérer sur des chaînes Unicode est un peu plus compliqué. Voir ici: stackoverflow.com/q/1527856/402322
ceving
1
Je ne suis pas sûr que ce soit subtil mais il vaut mieux considérer le cas où t==null.
Myobis
1
@ user1003916: l'échappement XML est conçu pour convertir toute & occurrence en & amp; c'est ainsi que cela doit fonctionner. Si vous excape déjà une chaîne échappée, c'est de votre faute.
Pointer Null
3
Je suis content de la version finale. Java SE est compact, rapide et efficace. Faire juste ce qui doit être fait plutôt que de télécharger 100 Mo supplémentaires de bloatware est toujours mieux dans mon livre.
Roger F. Gay
11

Cette question a huit ans et n'est toujours pas une réponse entièrement correcte! Non, vous ne devriez pas avoir à importer une API tierce entière pour effectuer cette tâche simple. Mauvais conseil.

La méthode suivante:

  • gérer correctement les caractères en dehors du plan multilingue de base
  • caractères d'échappement requis dans XML
  • échapper à tous les caractères non ASCII, ce qui est facultatif mais courant
  • remplacez les caractères non autorisés dans XML 1.0 par le caractère de substitution Unicode. Il n'y a pas de meilleure option ici - les supprimer est tout aussi valable.

J'ai essayé d'optimiser le cas le plus courant, tout en veillant à ce que vous puissiez diriger / dev / random à travers cela et obtenir une chaîne valide en 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("&#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: pour ceux qui continuent d'insister sur le fait qu'il est insensé d'écrire votre propre code pour cela alors qu'il existe de très bonnes API Java pour traiter XML, vous voudrez peut-être savoir que l'API StAX incluse avec Oracle Java 8 (je n'en ai pas testé d'autres ) ne parvient pas à encoder correctement le contenu CDATA: il n'échappe pas aux séquences]]> du contenu. Une bibliothèque tierce, même celle qui fait partie du noyau Java, n'est pas toujours la meilleure option.

Mike B
la source
+1 pour le code autonome. En comparant simplement votre code avec l' implémentation de goyave , je me demande qu'en est-il de '\ t', '\ n', '\ r'? Voir aussi les notes sur
guava
2
Il n'est pas nécessaire d'échapper \ n, \ r et \ t, ils sont valides, bien qu'ils rendent le formatage un peu laid. J'ai modifié le code pour montrer comment les supprimer si c'est ce que vous voulez.
Mike B
1
Il n'y a aucun moyen d '"échapper]]>" dans CDATA.
kmkaplan
1
Ensuite, il doit rejeter le contenu en lançant une IllegalArgumentException. En aucun cas, il ne doit prétendre réussir mais toujours afficher un XML invalide.
Mike B
Au lieu de remplacer les caractères illégaux dans XML 1.0 par le caractère de substitution Unicode, vous pouvez utiliser mes méthodes ici stackoverflow.com/a/59475093/3882565 .
stonar96
8

StringEscapeUtils.escapeXml()n'échappe pas aux caractères de contrôle (<0x20). XML 1.1 autorise les caractères de contrôle; XML 1.0 ne le fait pas. Par exemple, XStream.toXML()sérialisera volontiers les caractères de contrôle d'un objet Java en XML, ce qu'un analyseur XML 1.0 rejettera.

Pour échapper aux caractères de contrôle avec Apache commons-lang, utilisez

NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
Steve Mitchell
la source
7
public String escapeXml(String s) {
    return s.replaceAll("&", "&amp;").replaceAll(">", "&gt;").replaceAll("<", "&lt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
}
iCrazybest
la source
5
Le chaînage des replaceAllappels est très inefficace, en particulier pour les grandes chaînes. Chaque appel entraîne la création d'un nouvel objet String, qui restera en place jusqu'à la récupération de la mémoire. En outre, chaque appel nécessite de boucler à nouveau la chaîne. Cela pourrait être consolidé en une seule boucle manuelle avec des comparaisons avec chaque caractère cible à chaque itération.
daiscog
Cela devrait être la réponse acceptée, même si elle est inefficace. Il résout le problème en une seule ligne.
Stimpson Cat
Et il a de nombreux bugs. Voir ce commentaire ci
David Balažic
Pour corriger ces bogues, vous pouvez également utiliser ma méthode ici stackoverflow.com/a/59475093/3882565 . Notez qu'il ne s'agit pas d'un remplacement mais qu'il peut être utilisé en plus.
stonar96
6

Alors que l'idéalisme dit d'utiliser une bibliothèque XML, à mon humble avis, si vous avez une idée de base de XML, le bon sens et les performances indiquent le modèle jusqu'au bout. C'est sans doute plus lisible aussi. Bien que l'utilisation des routines d'échappement d'une bibliothèque soit probablement une bonne idée.

Considérez ceci: XML était destiné à être écrit par des humains.

Utilisez des bibliothèques pour générer du XML lorsque votre XML comme "objet" modélise mieux votre problème. Par exemple, si des modules enfichables participent au processus de construction de ce XML.

Edit: quant à la façon d'échapper réellement au XML dans les modèles, l'utilisation de CDATA ou escapeXml(string)de JSTL sont deux bonnes solutions, escapeXml(string)peuvent être utilisées comme ceci:

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

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

Le comportement de StringEscapeUtils.escapeXml () est passé de Commons Lang 2.5 à 3.0. Il n'échappe plus aux caractères Unicode supérieurs à 0x7f.

C'est une bonne chose, l'ancienne méthode était d'être un peu trop désireux d'échapper aux entités qui pouvaient simplement être insérées dans un document utf8.

Les nouveaux escapers à inclure dans Google Guava 11.0 semblent également prometteurs: http://code.google.com/p/guava-libraries/issues/detail?id=799

Jasper Krijgsman
la source
1
Voici l'escaper XML de Guava: code.google.com/p/guava-libraries/source/browse/guava/src/com/… . En général, j'ai trouvé que Guava était mieux architecturée qu'Apache Commons.
jhclark
6

Pour ceux qui recherchent la solution la plus rapide à écrire: utilisez les méthodes d' apache commons-lang :

N'oubliez pas d'inclure la dépendance:

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>3.5</version> <!--check current version! -->
</dependency>
Dariusz
la source
5

Remarque: votre question concerne l' échappement , pas l' encodage . L'échappement consiste à utiliser <, etc. pour permettre à l'analyseur de distinguer «ceci est une commande XML» et «ceci est du texte». L'encodage est ce que vous spécifiez dans l'en-tête XML (UTF-8, ISO-8859-1, etc.).

Tout d'abord, comme tout le monde l'a dit, utilisez une bibliothèque XML. XML semble simple mais l'encodage + les éléments d'échappement sont du vaudou sombre (que vous remarquerez dès que vous rencontrerez des trémas et du japonais et d'autres trucs bizarres comme des " chiffres pleine largeur " (& # FF11; vaut 1)). Garder XML lisible par l'homme est une tâche de Sisyphe.

Je suggère de ne jamais essayer d'être intelligent en matière d'encodage de texte et d'échappatoire en XML. Mais ne laissez pas cela vous empêcher d'essayer; rappelez-vous simplement quand il vous mord (et il le fera).

Cela dit, si vous n'utilisez que UTF-8, pour rendre les choses plus lisibles, vous pouvez envisager cette stratégie:

  • Si le texte contient «<», «>» ou «&», enveloppez-le <![CDATA[ ... ]]>
  • Si le texte ne contient pas ces trois caractères, ne le déformez pas.

J'utilise ceci dans un éditeur SQL et cela permet aux développeurs de couper et coller du SQL à partir d'un outil SQL tiers dans le XML sans se soucier de s'échapper. Cela fonctionne parce que le SQL ne peut pas contenir de trémas dans notre cas, donc je suis en sécurité.

Aaron Digulla
la source
5

Bien que je sois d'accord avec Jon Skeet en principe, je n'ai parfois pas la possibilité d'utiliser une bibliothèque XML externe. Et je trouve étrange que les deux fonctions pour échapper / échapper à une valeur simple (attribut ou balise, pas de document complet) ne sont pas disponibles dans les bibliothèques XML standard incluses avec Java.

En conséquence et sur la base des différentes réponses que j'ai vues postées ici et ailleurs, voici la solution que j'ai fini par créer (rien ne fonctionnait comme un simple copier / coller):

  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_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;
  }

Ce qui précède s'adapte à plusieurs choses différentes:

  1. évite d'utiliser la logique basée sur les caractères jusqu'à ce que cela soit absolument nécessaire - améliore la compatibilité unicode
  2. tente d'être aussi efficace que possible étant donné que la probabilité est que la deuxième condition «si» est probablement la voie la plus utilisée
  3. est une fonction pure; ie est thread-safe
  4. optimise bien avec le garbage collector en ne retournant le contenu de StringBuilder que si quelque chose a réellement changé - sinon, la chaîne d'origine est retournée

À un moment donné, j'écrirai l'inversion de cette fonction, toUnescaped (). Je n'ai tout simplement pas le temps de faire ça aujourd'hui. Quand je le ferai, je viendrai mettre à jour cette réponse avec le code. :)

équilibre chaotique
la source
Ça me semble plutôt bien. Je ne souhaite pas ajouter un autre pot à mon projet pour une seule méthode. Si vous accordez la permission, puis-je copier-coller votre code dans le mien?
RuntimeException
1
@SatishMotwani Bien sûr, vous pouvez prendre le code ci-dessus et en faire ce que vous voulez. Je crois comprendre que tout code publié sur StackOverflow est supposé être libre de droits d'auteur (n'est pas couvert comme une œuvre dans sa totalité). D'un autre côté, il serait extrêmement difficile pour quelqu'un de faire valoir n'importe quelle sorte de revendication de droit d'auteur et de s'attendre à une sorte de résultat pour lui-même.
chaotic3quilibrium
1
Merci d'avoir permis :-) Je vais l'utiliser.
RuntimeException le
Vous avez oublié de gérer les caractères NUL. Et peut-être d'autres choses aussi.
David Balažic
@ DavidBalažic D'accord, veuillez expliquer plus en détail ce que j'ai pu manquer? Veuillez lire le code de plus près. J'ai manipulé CHAQUE caractère Unicode (sur les 1 111 998), y compris le nullcaractère. Pouvez-vous expliquer la définition des deux valeurs, UNICODE_LOWet UNICODE_HIGH? Veuillez relire le ifqui utilise ces deux valeurs. Remarquez null( \u0000ce qui est (int)0) ne tombe pas entre ces deux valeurs. Lisez comment il devient correctement «échappé», tout comme TOUS les caractères Unicode existant en dehors de la plage UNICODE_LOWet UNICODE_HIGH, en utilisant la &#technique.
chaotic3quilibrium
3

Pour échapper aux caractères XML, le moyen le plus simple est d'utiliser le projet Apache Commons Lang, JAR téléchargeable sur: http://commons.apache.org/lang/

La classe est la suivante: org.apache.commons.lang3.StringEscapeUtils;

Il a une méthode nommée "escapeXml", qui renverra une chaîne d'échappement appropriée.

Greg Burdett
la source
Mise à jour: escapeXml est désormais obsolète - utilisez escapeXml10. Ref commons.apache.org/proper/commons-lang/javadocs/api-3.3/org/…
Daniel
3

Si vous recherchez une bibliothèque pour faire le travail, essayez:

  1. Guava 26.0 documenté ici

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

    Remarque: il existe également un xmlAttributeEscaper()

  2. Apache Commons Text 1.4 documenté ici

    StringEscapeUtils.escapeXml11(text)

    Remarque: il existe également une escapeXml10()méthode

jschnasse
la source
1

Voici une solution simple et idéale pour encoder des caractères accentués!

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);

Les sorties

Hi L&#226;rry &#38; M&#244;e!
Mike
la source
Le "31" de la première ligne du "si" ne devrait-il pas être "32"; c'est à dire moins que le caractère espace? Et si "31" doit rester, alors ne devrait-il pas être corrigé pour lire "si (c <= 31 || ..." (signe égal supplémentaire après le signe inférieur à)?
chaotic3quilibrium
1

Remplacez simplement

 & with &amp;

Et pour les autres personnages:

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

Utilisez JAXP et oubliez la gestion du texte, cela se fera automatiquement pour vous.

Fernando Miguélez
la source
Votre lien est en espagnol, ce qui n'est pas très utile pour la plupart d'entre nous. Mieux vaut celui-ci .
Vivit
0

Essayez d'encoder le XML à l'aide du sérialiseur XML Apache

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

Voici ce que j'ai trouvé après avoir cherché partout une solution:

Obtenez la bibliothèque Jsoup:

<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.12.1</version>
</dependency>

Ensuite:

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()

J'espère que cela aide quelqu'un

Wizston
la source