Beste Möglichkeit, JSON in einem HTML-Attribut zu speichern?

112

Ich muss ein JSON-Objekt in ein Attribut eines HTML-Elements einfügen.

  1. Der HTML-Code muss nicht validiert werden.

    Antwort von Quentin: Speichern Sie den JSON in einem data-*Attribut , das gültiges HTML5 ist.

  2. Das JSON-Objekt kann eine beliebige Größe haben - dh riesig

    Antwort von Maiku Mori: Das Limit für ein HTML-Attribut beträgt möglicherweise 65536 Zeichen .

  3. Was ist, wenn der JSON Sonderzeichen enthält? z.B {foo: '<"bar/>'}

    Antwort von Quentin: Codieren Sie die JSON-Zeichenfolge, bevor Sie sie gemäß den üblichen Konventionen in das Attribut einfügen. Verwenden Sie für PHP die Funktion . htmlentities()


EDIT - Beispiellösung mit PHP und jQuery

Schreiben des JSON in das HTML-Attribut:

<?php
    $data = array(
        '1' => 'test',
        'foo' => '<"bar/>'
    );
    $json = json_encode($data);
?>

<a href="#" data-json="<?php echo htmlentities($json, ENT_QUOTES, 'UTF-8'); ?>">CLICK ME</a>

Abrufen des JSON mit jQuery:

$('a').click(function() {

    // Read the contents of the attribute (returns a string)
    var data = $(this).data('json');

    // Parse the string back into a proper JSON object
    var json = $.parseJSON($(this).data('json'));

    // Object now available
    console.log(json.foo);

});
BadHorsie
quelle
Sie sollten wahrscheinlich erklären, warum und nach einer anderen Lösung fragen, da ich mir ziemlich sicher bin, dass dies nicht die beste ist. Sie können wahrscheinlich Datenattribute verwenden, aber ich bin mir nicht sicher, ob sie "große" Textmengen enthalten können. Bei Sonderzeichen können Sie den Text einfach codieren (Escape () und Unescape ()).
Maiku Mori
Ja, das Limit beträgt 65536 Zeichen ( stackoverflow.com/questions/2752457/… )
Maiku Mori
1
Übrigens, wenn Ihr Attribut benannt ist, das data-jsonSie verwenden sollten $(this).data('json'), hat die jQuery Sie auf diesen Teil behandelt.
Ciantic
Nur eine Anmerkung, die Benennung des Datensuffixes zu json ist nicht erforderlich. Wenn Sie ein gültiges json in ein data-custom_attribute einfügen, funktioniert dies problemlos mit jQuery.
Garet Claborn
Bitte korrigieren Sie die Klammerfolge)}; =>});
MotsManish

Antworten:

41

Der HTML-Code muss nicht validiert werden.

Warum nicht? Die Validierung ist eine wirklich einfache Qualitätssicherung, die viele Fehler auffängt. Verwenden Sie ein HTML 5- data-*Attribut.

Das JSON-Objekt kann eine beliebige Größe haben (dh riesig).

Ich habe keine Dokumentation zu Browserbeschränkungen für Attributgrößen gesehen.

Wenn Sie auf sie stoßen, speichern Sie die Daten in einem <script>. Definieren Sie ein Objekt und ordnen Sie die Elemente idden Eigenschaftsnamen in diesem Objekt zu.

Was ist, wenn der JSON Sonderzeichen enthält? (zB {test: '<"myString />'})

Befolgen Sie einfach die normalen Regeln für das Einfügen nicht vertrauenswürdiger Daten in Attributwerte. Verwenden Sie &amp;und &quot;(wenn Sie den Attributwert in doppelte Anführungszeichen setzen) oder &#x27;(wenn Sie den Attributwert in einfache Anführungszeichen setzen).

Beachten Sie jedoch, dass dies kein JSON ist (was erfordert, dass Eigenschaftsnamen Zeichenfolgen sind und Zeichenfolgen nur durch doppelte Anführungszeichen getrennt werden).

QUentin
quelle
5
Sie sagen also, ich sollte es tun, htmlentities($json)bevor ich es in das HTML-Attribut einfüge? Und wie dekodiere ich das, wenn ich es in jQuery lesen möchte? Und wie schreibe ich es dann mit jQuery genauso zurück wie mit PHP?
BadHorsie
6
Sie sagen also, ich sollte html_encode ($ json) ausführen, bevor ich es in das HTML-Attribut einfüge? - Wenn Sie PHP verwenden, würde das funktionieren. Und wie dekodiere ich das, wenn ich es in jQuery lesen möchte? - Aus dem Attribut dekodieren? Der Browser tut dies, wenn er den HTML-Code in ein DOM analysiert. Und wie schreibe ich es dann mit jQuery genauso zurück wie mit PHP? - Sie legen Attribute von DOM-Knoten fest und generieren kein unformatiertes HTML. Der Browser kümmert sich darum.
Quentin
1
Momentan habe ich ein Problem, bei dem mein Browser es derzeit in Google Chrome nicht dekodiert. Wenn ich JSON analysiere, sind alle HTML-Entitäten vorhanden und schlagen fehl.
Bradley Weston
Wenn Sie es in ein Skript-Tag einfügen, müssen Sie es aufgrund der besonderen Behandlung von Skript-Tags anders maskieren. Beispiel: Ein Wert mit </ script> würde das Skript-Tag beenden.
Dobes Vandermeer
16

Je nachdem, wo Sie es setzen,

  • In einem , <div>wie Sie gefragt, müssen Sie sicherstellen , dass die JSON keine HTML - Angebote enthält , die einen Tag, HTML - Kommentar, eingebettet Doctype beginnen konnte, etc. Sie müssen mindestens entkommen <, und &in einer Art und Weise , so dass der ursprüngliche Charakter nicht erscheinen in der Escape-Sequenz.
  • In <script>Elementen müssen Sie sicherstellen, dass der JSON kein End-Tag </script>oder keine Escape-Textgrenze enthält : <!--oder -->.
  • In Ereignishandlern müssen Sie sicherstellen, dass der JSON seine Bedeutung beibehält, auch wenn er Dinge enthält, die wie HTML-Entitäten aussehen und keine Attributgrenzen ( "oder ') überschreiten .

In den ersten beiden Fällen (und in alten JSON-Parsern) sollten Sie U + 2028 und U + 2029 codieren, da dies in JavaScript Zeilenumbrüche sind, obwohl sie in in JSON nicht codierten Zeichenfolgen zulässig sind.

Für die Richtigkeit müssen Sie Escape- \und JSON-Anführungszeichen verwenden, und es ist nie eine schlechte Idee, NUL immer zu codieren.

Wenn der HTML-Code möglicherweise ohne Inhaltscodierung bereitgestellt wird, sollten Sie ihn codieren +, um UTF-7-Angriffe zu verhindern .

In jedem Fall funktioniert die folgende Escape-Tabelle:

  • NUL -> \u0000
  • CR -> \noder\u000a
  • LF -> \roder\u000d
  • " -> \u0022
  • & -> \u0026
  • ' -> \u0027
  • + -> \u002b
  • /-> \/oder\u002f
  • < -> \u003c
  • > -> \u003e
  • \-> \\oder\u005c
  • U + 2028 ->\u2028
  • U + 2029 -> \u2029

Der JSON-Zeichenfolgenwert für den Text Hello, <World>!mit einer neuen Zeile am Ende wäre also "Hello, \u003cWorld\u003e!\r\n".

Mike Samuel
quelle
1
return (input.replace(/([\s"'& + \ / \\ <> \ u2028 \ u2029 \ u0000]) / g, (match, p1) => {return \\u${p1.codePointAt(0).toString(16).padStart(4, 0)}; })); `
Denis Giffeler
14

Eine andere Möglichkeit besteht darin, JSON-Daten in das <script>Tag einzufügen, jedoch nicht mit type="text/javascript", sondern mit type="text/bootstrap"odertype="text/json" Typ, um die Ausführung von Javascript zu vermeiden.

Dann können Sie an einer Stelle Ihres Programms auf folgende Weise danach fragen:

function getData(key) {
  try {
    return JSON.parse($('script[type="text/json"]#' + key).text());
  } catch (err) { // if we have not valid json or dont have it
    return null;
  } 
}

Auf der Serverseite können Sie so etwas tun (dieses Beispiel mit PHP und Zweig ):

<script id="my_model" type="text/json">
  {{ my_model|json_encode()|raw }}
</script>
Sergey Kamardin
quelle
1
Verwenden Sie für JSON den Skripttyp "application / json". Es ist auch schön, auf lange Sicht die oberste Ebene als Objekt zu haben.
OIS
1
Dies beantwortet die Frage des Ops nicht direkt, war aber dennoch sehr hilfreich für mich. Die Daten, die ich speichere, gelten für die gesamte Seite und nicht für ein bestimmtes Element, sodass ein Elementattribut nicht wirklich funktioniert (es sei denn, ich setze es wie auf das body-Element, was mir gerade seit meinem Daten können groß sein). Das Speichern in einem <script type="application/json" id="MyData"></script>funktioniert perfekt. Dann kann ich mit ActiveWAFL / DblEj nachschlagen mit : document.GetData("#MyData").
Evan de la Cruz
2
Diese Antwort enthält falsche / gefährliche Informationen! Durch Ändern des Skripttyps wird die Erkennung von </ script> -Tags nicht geändert. Versuchen Sie einfach:<script type="application/json" id="MyData"> "abc</script><script>alert()</script>" </script>
Hyperknot
12

Eine andere Möglichkeit besteht darin, die JSON-Zeichenfolge mit base64 zu codieren und sie mit der atob()Funktion zu dekodieren, wenn Sie sie in Ihrem Javascript verwenden müssen.

var data = JSON.parse(atob(base64EncodedJSON));
Pavel Petrov
quelle
Danke für atob. Das war mir nie bewusst!
Ifedi Okonkwo
3
Achtung - funktioniert nicht, wenn JSON nicht lateinische Zeichen enthält.
Realexer
5

Sie können knockoutjs verwenden,

<p>First name: <strong data-bind="text: firstName" >todo</strong></p>
<p>Last name: <strong data-bind="text: lastName">todo</strong></p>

knockout.js

// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function AppViewModel() {
    this.firstName = "Jayson";
    this.lastName = "Monterroso";
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

Ausgabe

Vorname: Jayson Nachname: Monterroso

Überprüfen Sie dies: http://learn.knockoutjs.com/

jayM
quelle
2

Hier ist nichts Besonderes. Führen Sie in PHP einen Durchlauf der JSON-Zeichenfolge durch htmlspecialchars, um sicherzustellen, dass keine Sonderzeichen als HTML interpretiert werden können. Aus Javascript ist kein Entkommen notwendig; Legen Sie einfach das Attribut fest und los geht's.

Matchu
quelle
2

Für einfache JSON-Objekte würde der folgende Code funktionieren.

Kodieren:

var jsonObject = { numCells: 5, cellWidth: 1242 };
var attributeString = escape(JSON.stringify(jsonObject));

Dekodieren:

var jsonString = unescape(attributeString);
var jsonObject = JSON.parse(jsonString);
Crashalot
quelle
1

Was Sie tun können, ist, cdata um Ihre Elemente wie diese zu verwenden

<![CDATA[  <div class='log' mydata='${aL.logData}'>${aL.logMessage}</div>     ]]>  

Dabei ist mydata eine rohe JSON-Zeichenfolge. Hoffe das hilft dir und anderen.

Faiyet
quelle
Wie funktioniert (kann) diese Lösung? Was ist, wenn ich so etwas ">in mydata speichern möchte?
Martin Pecka
1
Was ist, wenn die Zeichenfolge "]]>" enthält
Dobes Vandermeer
1

Ein anderer Gedanke, der verwendet werden könnte, besteht darin, die JSON-Daten als base64-Zeichenfolge im Attribut zu speichern und sie dann zu verwenden window.atoboder window.btoain verwendbaren JSON-Daten wiederherzustellen.

<?php
$json = array("data"=>"Some json data thing");
echo "<div data-json=\"".base64_encode(json_encode($json))."\"></div>";
?>
Matthew D Auld
quelle