Très semblable à cette question , sauf pour Java.
Quelle est la méthode recommandée pour coder des chaînes pour une sortie XML en Java? Les chaînes peuvent contenir des caractères tels que "&", "<", etc.
Très simplement: utilisez une bibliothèque XML. De cette façon, il s'agira bien de right au lieu de nécessiter une connaissance détaillée des bits de la spécification XML.
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 regarder dans StringEscapeUtils
dans la bibliothèque Apache Commons Lang .
Il suffit d'utiliser.
<![CDATA[ your text here ]]>
Cela permettra à tous les caractères sauf la fin
]]>
Vous pouvez donc inclure des caractères illégaux tels que & et>. Par exemple.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
Cependant, les attributs devront être protégés car les blocs CDATA ne peuvent pas être utilisés pour eux.
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("<"); 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();
}
Cela a bien fonctionné pour moi de 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. "<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();
}
}
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, qu'un analyseur XML 1.0 refusera.
Pour échapper aux caractères de contrôle avec Apache commons-lang, utilisez
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
Cette question a huit ans et n’est toujours pas une réponse tout à fait 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 va:
J'ai essayé d'optimiser le cas le plus courant, tout en m'assurant que vous puissiez canaliser/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("�"); // 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();
}
Edit: pour ceux qui insistent sur le fait qu'il est insensé d'écrire votre propre code pour cela alors qu'il existe d'excellentes API Java pour gérer XML, vous voudrez peut-être savoir que l'API StAX fournie avec Oracle testé les autres) ne parvient pas à coder le contenu CDATA correctement: il ne s'échappe pas]]> des séquences dans le contenu. Une bibliothèque tierce, même faisant partie du noyau Java, n’est pas toujours la meilleure option.
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 sens commun et les performances disent qu'il le modélise parfaitement. 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 était destiné à être écrit par des humains.
Utilisez des bibliothèques pour générer du XML lorsque votre XML en tant qu '"objet" modélise mieux votre problème. Par exemple, si des modules enfichables participent au processus de construction de ce XML.
Edit: pour savoir comment échapper au XML dans les modèles, l'utilisation de CDATA ou de escapeXml(string)
à partir de JSTL sont deux bonnes solutions, escapeXml(string)
peut être utilisé de la manière suivante:
<%@taglib prefix="fn" uri="http://Java.Sun.com/jsp/jstl/functions"%>
<item>${fn:escapeXml(value)}</item>
Le comportement de StringEscapeUtils.escapeXml () est passé de Commons Lang 2.5 à 3.0 . Il n’échappe plus les caractères Unicode supérieurs à 0x7f.
C’est une bonne chose, l’ancienne méthode était un peu trop désireuse d’échapper aux entités qui pourraient simplement être insérées dans un document utf8.
Les nouveaux évasions à intégrer à Google Guava 11.0 semblent également prometteurs: http://code.google.com/p/guava-libraries/issues/detail?id=799
Remarque: Votre question concerne escaping, pas encoding. Echapper utilise <, etc. pour permettre à l’analyseur de faire la distinction entre "ceci est une commande XML" et "ceci est du texte". Le codage 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 le dit, utilisez une bibliothèque XML. XML a l'air simple mais l'encodage + les échappements sont voodoo (ce que vous remarquerez dès que vous rencontrerez des trémas, des japonais et d'autres trucs étranges comme " 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 sur l'encodage de texte et l'échappement en XML. Mais ne laissez pas cela vous empêcher d'essayer; Rappelez-vous juste quand il vous mord (et il le fera).
Cela dit, si vous utilisez uniquement UTF-8, vous pouvez envisager cette stratégie pour rendre les choses plus lisibles:
<![CDATA[ ... ]]>
J'utilise cela dans un éditeur SQL et cela permet aux développeurs de couper et coller le code SQL 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éma dans notre cas, donc je suis en sécurité.
Pour ceux qui recherchent la solution la plus rapide à écrire: utilisez les méthodes de Apache commons-lang :
StringEscapeUtils.escapeXml10()
for xml 1.0StringEscapeUtils.escapeXml11()
for xml 1.1StringEscapeUtils.escapeXml()
est maintenant obsolète, mais était utilisé couramment dans le passé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>
Bien que je sois d’accord avec le principe de Jon Skeet, je n’ai parfois pas la possibilité d’utiliser une bibliothèque XML externe. Et je trouve étrange que les deux fonctions pour échapper/décompresser une valeur simple (attribut ou balise, document non complet) ne soient 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 publiées ici et ailleurs, voici la solution que j'ai finalement créée (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[] {
"<"
, ">"
, "&"
, """
, "'"
}));
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;
}
Ce qui précède accueille plusieurs choses différentes:
À un moment donné, j'écrirai l'inversion de cette fonction, toUnescaped (). Je n'ai tout simplement pas le temps de le faire aujourd'hui. Quand je le ferai, je viendrai mettre à jour cette réponse avec le code. :)
Pour échapper aux caractères XML, le plus simple consiste à utiliser le projet Apache Commons Lang, JAR téléchargeable à l’adresse: http://commons.Apache.org/lang/
La classe est la suivante: org.Apache.commons.lang3.StringEscapeUtils;
Il a une méthode nommée "escapeXml", qui retournera une chaîne échappée de manière appropriée.
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ârry & Môe!
Utilisez JAXP et oubliez le traitement de texte, il sera fait automatiquement pour vous.
Il suffit de remplacer
& with &
Et pour les autres personnages:
> with >
< with <
\" with "
' with '
Essayez de coder 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());
Vous pouvez utiliser la bibliothèque ESAPI (Enterprise Security API) , qui fournit des méthodes telles que encodeForXML
et encodeForXMLAttribute
. Consultez la documentation de l'interface Encoder ; il contient également des exemples sur la création d'une instance de DefaultEncoder .