web-dev-qa-db-fra.com

Comment dois-je m'échapper des chaînes dans JSON?

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é.

135
Behrang

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

141
Thanatos

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

Essayez ceci org.codehaus.jettison.json.JSONObject.quote("your string").

Téléchargez-le ici: http://mvnrepository.com/artifact/org.codehaus.jettison/jettison

35
dpetruha

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");
22
Dan-Dev

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.

21
NS du Toit

org.json.JSONObjectquote(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

9
I.G. Pascual

StringEscapeUtils.escapeJavaScript/StringEscapeUtils.escapeEcmaScript devrait faire l'affaire aussi.

6
Hanubindh Krishna

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)

4
Dhiraj

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. 

3
Vladimir

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é

2
Tjunkie

Utilisez la classe EscapeUtils dans l'API commun de lang.

EscapeUtils.escapeJavaScript("Your JSON string");
2
Jsm

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

2
vijucat

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();
1
orip

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.

0
absmiths

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

0
David

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

Apache commons-text a maintenant un StringEscapeUtils.escapeJson (String) .

0
Mohsen

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

0
webjockey