Lors de la création manuelle de données JSON, comment dois-je échapper aux champs de chaîne? Devrais-je utiliser quelque chose comme StringEscapeUtilities.escapeHtml
, StringEscapeUtilities.escapeXml
d'Apache Commons Lang ou devrais-je utiliser Java.net.URLEncoder
?
Le problème est que lorsque j'utilise SEU.escapeHtml
, les guillemets ne sont pas échappés et que, lorsque j'emballe la chaîne entière dans une paire de '
s, un JSON mal formé est généré.
Idéalement, trouvez une bibliothèque JSON dans votre langue à 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. Cela vous gardera beaucoup plus sain. Si, pour une raison quelconque, vous n'avez pas de bibliothèque dans votre langue, vous ne voulez pas en utiliser une (je ne le suggérerais pas¹), ou si vous écrivez une bibliothèque JSON, continuez.
Échappez-vous selon le RFC. JSON est assez libéral: les seuls caractères que vous devez échapper sont \
, "
et les codes de contrôle (toute valeur inférieure à U + 0020).
Cette structure d'échappement est spécifique à JSON. Vous aurez besoin d'une fonction spécifique à JSON. Tous les caractères d'échappement peuvent être écrits sous la forme \uXXXX
, où XXXX
est l'unité de code UTF-16¹ pour ce caractère. Il existe quelques raccourcis, tels que \\
, qui fonctionnent également. (Et ils résultent en une sortie plus petite et plus claire.)
Pour plus de détails, voir le RFC .
L'échappement de ¹JSON est construit sur JS, il utilise donc \uXXXX
, où XXXX
est une unité de code UTF-16. Pour les points de code extérieurs au BMP, cela signifie qu’il faut coder des paires de substitution, ce qui peut devenir un peu poilu. (Vous pouvez aussi simplement sortir le caractère directement, car JSON est codé pour du texte Unicode et autorise ces caractères particuliers.)
Extrait de Jettison :
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échargez-le ici: http://mvnrepository.com/artifact/org.codehaus.jettison/jettison
org.json.simple.JSONObject.escape () échappe aux guillemets, \, /,\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 supporte maintenant cela. Assurez-vous simplement d'avoir une version assez récente d'Apache commons lang sur votre chemin de classe. Vous aurez besoin de la version 3.2+
Notes de publication de la version 3.2
LANG-797: Ajouté escape/unescapeJson à StringEscapeUtils.
org.json.JSONObject
quote(String data)
méthode fait le travail
import org.json.JSONObject;
String jsonEncodedString = JSONObject.quote(data);
Extrait de la documentation:
Encode les données sous forme de chaîne JSON. Ceci s'applique aux guillemets et à tout caractère nécessaire s'échappant . [...] Null sera interprété comme une chaîne vide
StringEscapeUtils.escapeJavaScript
/StringEscapeUtils.escapeEcmaScript
devrait faire l'affaire aussi.
Si vous utilisez fastexml jackson, vous pouvez utiliser les éléments suivants: com.fasterxml.jackson.core.io.JsonStringEncoder.getInstance().quoteAsString(input)
Si vous utilisez Codehaus Jackson, vous pouvez utiliser les éléments suivants: org.codehaus.jackson.io.JsonStringEncoder.getInstance().quoteAsString(input)
Vous ne savez pas ce que vous entendez par "créer JSON manuellement", mais vous pouvez utiliser quelque chose comme gson ( http://code.google.com/p/google-gson/ ), et cela transformerait votre HashMap, Array , Chaîne, etc., en une valeur JSON. Je recommande d'aller avec un cadre pour cela.
Je n'ai pas passé le temps nécessaire pour être certain à 100%, mais cela a suffisamment fonctionné pour mes entrées pour être accepté par les validateurs JSON en ligne:
org.Apache.velocity.tools.generic.EscapeTool.EscapeTool().Java("input")
bien que cela ne semble pas meilleur que org.codehaus.jettison.json.JSONObject.quote("your string")
J'utilise déjà simplement des outils de vélocité dans mon projet - mon bâtiment "manuel JSON" était dans un modèle de vélocité
Utilisez la classe EscapeUtils dans l'API commun de lang.
EscapeUtils.escapeJavaScript("Your JSON string");
Pour ceux qui sont venus ici à la recherche d'une solution de ligne de commande, comme moi, le paramètre --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 volumineuses peuvent être placées dans un fichier et vous utiliseriez la syntaxe @ pour spécifier un fichier à scinder 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 [email protected] 'https://www.googleapis.com/freebase/v1/mqlread'
Et maintenant, c’est aussi un tutoriel sur la manière d’interroger Freebase à partir de la ligne de commande :-)
Considérez Moshi 's JsonWriter class. Il a une merveilleuse API et réduit au minimum la copie, tout peut être jeté en streaming dans 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 corde en main:
Buffer b = new Buffer(); // okio.Buffer
JsonWriter writer = new JsonWriter(b);
//...
String jsonString = b.readUtf8();
Je pense que la meilleure réponse en 2017 est d'utiliser les API javax.json. Utilisez javax.json.JsonBuilderFactory pour créer vos objets json, puis écrivez-les à l'aide de javax.json.JsonWriterFactory. Très belle combinaison constructeur/écrivain.
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 l'enregistrement, vous pouvez facilement convertir ce code C #:
Gracieuseté 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();
}
}
Apache commons-text a maintenant un StringEscapeUtils.escapeJson (String) .
Si vous avez besoin d'échapper à JSON dans une chaîne JSON, utilisez org.json.JSONObject.quote ("votre chaîne json qui doit être échappée") semble bien fonctionner