Comment devrais-je échapper des chaînes dans JSON?
Lors de la création manuelle de données JSON, Comment dois-je échapper des champs de chaîne? Devrais-je utiliser quelque chose comme Apache Commons Lang StringEscapeUtilities.escapeHtml
, StringEscapeUtilities.escapeXml
, ou devrais-je utiliser java.net.URLEncoder
?
Le problème est que lorsque j'utilise SEU.escapeHtml
, Il n'échappe pas aux guillemets et lorsque j'enveloppe toute la chaîne dans une paire de '
s, un JSON mal formé sera généré.
18 réponses
Idéalement, trouvez une bibliothèque JSON dans votre langue {[9] } à laquelle vous pouvez alimenter une structure de données appropriée, et laissez-la s'inquiéter de la façon d'échapper aux choses . Il va vous garder beaucoup plus saine. Si pour une raison quelconque vous n'avez pas de bibliothèque dans votre langue, vous ne voulez pas en utiliser une (Je ne suggérerais pas this1), ou vous écrivez une bibliothèque JSON, lisez la suite.
Échapper selon la RFC. JSON est assez libéral: les seuls caractères que vous devez échapper sont \
, "
, et codes de contrôle (rien de moins que U + 0020).
Cette structure d'échappement est spécifique à JSON. Vous aurez besoin d'une fonction spécifique JSON. Tous les échappements peuvent être écrits comme \uXXXX
Où XXXX
est L'Unité de code UTF-161 pour ce caractère. Il y a quelques raccourcis, tels que \\
, qui fonctionnent aussi bien. (Et ils se traduisent par une sortie plus petite et plus claire.)
Pour plus de détails, voir la RFC.
L'échappement de 1JSON est construit sur JS, donc il utilise \uXXXX
, Où XXXX
est un UTF-16 code de l'unité. Pour les points de code en dehors du BMP, cela signifie encoder des paires de Substitution, ce qui peut devenir un peu poilu. (Ou, vous pouvez simplement sortir le caractère directement, puisque JSON encodé pour est le texte Unicode, et permet ces caractères particuliers.)
Extrait De Largage :
public static String quote(String string) {
if (string == null || string.length() == 0) {
return "\"\"";
}
char c = 0;
int i;
int len = string.length();
StringBuilder sb = new StringBuilder(len + 4);
String t;
sb.append('"');
for (i = 0; i < len; i += 1) {
c = string.charAt(i);
switch (c) {
case '\\':
case '"':
sb.append('\\');
sb.append(c);
break;
case '/':
// if (b == '<') {
sb.append('\\');
// }
sb.append(c);
break;
case '\b':
sb.append("\\b");
break;
case '\t':
sb.append("\\t");
break;
case '\n':
sb.append("\\n");
break;
case '\f':
sb.append("\\f");
break;
case '\r':
sb.append("\\r");
break;
default:
if (c < ' ') {
t = "000" + Integer.toHexString(c);
sb.append("\\u" + t.substring(t.length() - 4));
} else {
sb.append(c);
}
}
}
sb.append('"');
return sb.toString();
}
Essayez ceci org.codehaus.jettison.json.JSONObject.quote("your string")
.
Télécharger ici: http://mvnrepository.com/artifact/org.codehaus.jettison/jettison
Org.json.simple.JSONObject.escape() échappe à la citations,\, /, \r, \n, \b, \f, \t et d'autres caractères de contrôle. Il peut être utilisé pour échapper aux codes JavaScript.
import org.json.simple.JSONObject;
String test = JSONObject.escape("your string");
Apache commons lang Le supporte maintenant. Assurez-vous simplement d'avoir une version assez récente D'Apache commons lang sur votre classpath. Vous aurez besoin de la version 3.2 +
Notes de version pour la version 3.2
LANG-797: ajout d'escape / unescapeJson à StringEscapeUtils.
org.json.JSONObject
quote(String data)
la méthode fait le travail
import org.json.JSONObject;
String jsonEncodedString = JSONObject.quote(data);
Extrait de la documentation:
Code les données sous forme de chaîne JSON. ceci applique les guillemets et tout caractère nécessaire échappant . [...] Null sera interprété comme une chaîne vide
StringEscapeUtils.escapeJavaScript
/ StringEscapeUtils.escapeEcmaScript
devrait faire l'affaire.
Vous ne savez pas ce que vous entendez par "création manuelle de json", mais vous pouvez utiliser quelque chose comme gson ( http://code.google.com/p/google-gson/), et cela transformerait votre HashMap, tableau, chaîne, etc., en une valeur JSON. Je recommande d'aller avec un cadre pour cela.
Si vous utilisez fastexml jackson, vous pouvez utiliser ce qui suit:
com.fasterxml.jackson.core.io.JsonStringEncoder.getInstance().quoteAsString(input)
Si vous utilisez codehaus jackson, vous pouvez utiliser ce qui suit:
org.codehaus.jackson.io.JsonStringEncoder.getInstance().quoteAsString(input)
Je n'ai pas passé le temps de rendre 100% certain, mais cela a fonctionné pour mes entrées suffisamment pour être accepté par les validateurs JSON en ligne:
org.apache.velocity.tools.generic.EscapeTool.EscapeTool().java("input")
Bien qu'il ne semble pas mieux que org.codehaus.jettison.json.JSONObject.quote("your string")
J'utilise simplement des outils velocity dans mon projet déjà-mon bâtiment "JSON manuel" était dans un modèle velocity
Pour ceux qui sont venus ici à la recherche d'une solution en ligne de commande, comme moi, --data-urlencode de cURL fonctionne bien:
curl -G -v -s --data-urlencode 'query={"type" : "/music/artist"}' 'https://www.googleapis.com/freebase/v1/mqlread'
Envoie
GET /freebase/v1/mqlread?query=%7B%22type%22%20%3A%20%22%2Fmusic%2Fartist%22%7D HTTP/1.1
, par exemple. Des données JSON plus grandes peuvent être placées dans un fichier et vous utiliserez la syntaxe @ pour spécifier un fichier à slurp dans les données à échapper. Par exemple, si
$ cat 1.json
{
"type": "/music/artist",
"name": "The Police",
"album": []
}
Vous utiliseriez
curl -G -v -s --data-urlencode query@1.json 'https://www.googleapis.com/freebase/v1/mqlread'
Et maintenant, c'est aussi un tutoriel sur la façon d'interroger Freebase à partir de la ligne de commande: -)
Utilisez la classe EscapeUtils dans l'API Lang de commons.
EscapeUtils.escapeJavaScript("Your JSON string");
Considérez la classejsonwriter de Moshi. Il a une API merveilleuse et il réduit la copie au minimum, Tout peut être bien diffusé à un fichier, OutputStream, etc.
OutputStream os = ...;
JsonWriter json = new JsonWriter(Okio.buffer(Okio.sink(os)));
json.beginObject();
json.name("id").value(getId());
json.name("scores");
json.beginArray();
for (Double score : getScores()) {
json.value(score);
}
json.endArray();
json.endObject();
Si vous voulez la chaîne en main:
Buffer b = new Buffer(); // okio.Buffer
JsonWriter writer = new JsonWriter(b);
//...
String jsonString = b.readUtf8();
Si vous devez échapper JSON dans la chaîne JSON, utilisez org.json.JSONObject.quote ("votre chaîne json qui doit être échappée") semble bien fonctionner
En utilisant la syntaxe \ uXXXX peut résoudre ce problème, google UTF-16 avec le nom du signe, vous pouvez trouver XXXX, par exemple: utf-16 double quote
Les méthodes ici qui montrent l'implémentation réelle sont toutes défectueuses.
Je n'ai pas de code Java, mais juste pour Info, vous pouvez facilement convertir ce code C#:
Avec L'aimable autorisation du mono-projet @ https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web/HttpUtility.cs
public static string JavaScriptStringEncode(string value, bool addDoubleQuotes)
{
if (string.IsNullOrEmpty(value))
return addDoubleQuotes ? "\"\"" : string.Empty;
int len = value.Length;
bool needEncode = false;
char c;
for (int i = 0; i < len; i++)
{
c = value[i];
if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92)
{
needEncode = true;
break;
}
}
if (!needEncode)
return addDoubleQuotes ? "\"" + value + "\"" : value;
var sb = new System.Text.StringBuilder();
if (addDoubleQuotes)
sb.Append('"');
for (int i = 0; i < len; i++)
{
c = value[i];
if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
sb.AppendFormat("\\u{0:x4}", (int)c);
else switch ((int)c)
{
case 8:
sb.Append("\\b");
break;
case 9:
sb.Append("\\t");
break;
case 10:
sb.Append("\\n");
break;
case 12:
sb.Append("\\f");
break;
case 13:
sb.Append("\\r");
break;
case 34:
sb.Append("\\\"");
break;
case 92:
sb.Append("\\\\");
break;
default:
sb.Append(c);
break;
}
}
if (addDoubleQuotes)
sb.Append('"');
return sb.ToString();
}
Cela peut être compacté dans
// https://github.com/mono/mono/blob/master/mcs/class/System.Json/System.Json/JsonValue.cs
public class SimpleJSON
{
private static bool NeedEscape(string src, int i)
{
char c = src[i];
return c < 32 || c == '"' || c == '\\'
// Broken lead surrogate
|| (c >= '\uD800' && c <= '\uDBFF' &&
(i == src.Length - 1 || src[i + 1] < '\uDC00' || src[i + 1] > '\uDFFF'))
// Broken tail surrogate
|| (c >= '\uDC00' && c <= '\uDFFF' &&
(i == 0 || src[i - 1] < '\uD800' || src[i - 1] > '\uDBFF'))
// To produce valid JavaScript
|| c == '\u2028' || c == '\u2029'
// Escape "</" for <script> tags
|| (c == '/' && i > 0 && src[i - 1] == '<');
}
public static string EscapeString(string src)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
int start = 0;
for (int i = 0; i < src.Length; i++)
if (NeedEscape(src, i))
{
sb.Append(src, start, i - start);
switch (src[i])
{
case '\b': sb.Append("\\b"); break;
case '\f': sb.Append("\\f"); break;
case '\n': sb.Append("\\n"); break;
case '\r': sb.Append("\\r"); break;
case '\t': sb.Append("\\t"); break;
case '\"': sb.Append("\\\""); break;
case '\\': sb.Append("\\\\"); break;
case '/': sb.Append("\\/"); break;
default:
sb.Append("\\u");
sb.Append(((int)src[i]).ToString("x04"));
break;
}
start = i + 1;
}
sb.Append(src, start, src.Length - start);
return sb.ToString();
}
}
Je pense que la meilleure réponse en 2017 est d'utiliser javax.API json. Utilisation javax.json.JsonBuilderFactory pour créer vos objets json, puis écrivez les objets à l'aide de javax.json.JsonWriterFactory. Très belle combinaison constructeur / écrivain.
Apache commons-texte dispose désormais d'un StringEscapeUtils.escapeJson (chaîne) .