Лучший способ хранения JSON в атрибуте HTML?

Мне нужно поместить объект JSON в атрибут элемента HTML.

  1. HTML не нужно проверять.

    Ответ: Quentin: Храните JSON в атрибуте data-* , который действителен для HTML5.

  2. Объект JSON может быть любого размера – то есть огромного

    Ответа на вопрос Maiku Mori: Предел для HTML-атрибута может составлять 65536 символов .

  3. Что делать, если JSON содержит специальные символы? например {foo: '<"bar/>'}

    Ответ: Quentin: Кодируйте строку JSON перед тем, как поместить ее в атрибут, в соответствии с обычными соглашениями. Для PHP используйте htmlentities() .


EDIT – пример решения с использованием PHP и jQuery

Запись JSON в атрибут HTML:

 <?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> 

Получение JSON с помощью 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); }); 

HTML не нужно проверять.

Почему нет? Проверка действительно легкая QA, которая ловит много ошибок. Используйте атрибут data-* HTML 5.

Объект JSON может быть любого размера (т.е. огромного).

Я не видел никакой документации по ограничениям браузера для размеров атрибутов.

Если вы запустили их, сохраните данные в <script> . Определите id объекта и объекта карты s в именах свойств этого объекта.

Что делать, если JSON содержит специальные символы? (например, {test: '<"myString />'})

Просто следуйте обычным правилам для включения ненадежных данных в значения атрибутов. Использовать &amp; и &quot; (если вы &#x27; значение атрибута в двойные кавычки) или &#x27; (если вы переносите значение атрибута в одинарные кавычки).

Обратите внимание, однако, что это не JSON (который требует, чтобы имена свойств были строками, а строки были разделены только с двойными кавычками).

В зависимости от того, где вы выразились,

  • В <div> как вы просили, вам нужно убедиться, что JSON не содержит специальных HTML-файлов, которые могут запускать тег, комментарий HTML, встроенный doctype и т. Д. Вам нужно избегать, по крайней мере, < и так, чтобы исходный символ не появляется в экранированной последовательности.
  • В элементах <script> вам необходимо убедиться, что JSON не содержит конечный тег </script> или экранирование границы текста: <!-- или --> .
  • В обработчиках событий вам необходимо убедиться, что JSON сохраняет свое значение, даже если он имеет вещи, которые похожи на объекты HTML и не нарушают границы атрибутов ( " или ' ).

Для первых двух случаев (и для старых парсеров JSON) вы должны кодировать U + 2028 и U + 2029, поскольку они являются символами новой строки в JavaScript, даже если они разрешены в строках, не кодированных в JSON.

Для правильности вам нужно сбежать с символами кавычек \ и JSON, и никогда не будет плохой идеей всегда кодировать NUL.

Если HTML может быть подан без кодировки содержимого, вы должны кодировать + чтобы предотвратить атаки UTF-7 .

В любом случае будет работать следующая таблица экранирования:

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

Итак, строковое значение JSON для текста Hello, <World>! с новой "Hello, \u003cWorld\u003e!\r\n" в конце будет "Hello, \u003cWorld\u003e!\r\n" .

Другой способ, которым вы можете это сделать, – поместить данные json внутри <script> , но не с type="text/javascript" , но с type="text/bootstrap" или type="text/json" , чтобы избежать javascript выполнение.

Затем, в каком-то месте вашей программы, вы можете запросить его таким образом:

 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; } } 

На стороне сервера вы можете сделать что-то вроде этого (этот пример с php и twig ):

 <script id="my_model" type="text/json"> {{ my_model|json_encode()|raw }} </script> 

Вы можете использовать knockoutjs,

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

Вывод

Имя: Jayson Фамилия: Monterroso

Проверьте это: http://learn.knockoutjs.com/

Другой вариант – base64 закодировать строку JSON, и если вам нужно использовать ее в своем javascript, декодируйте ее с помощью функции atob() .

 var data = JSON.parse(atob(base64EncodedJSON)); 

Ничего особенного здесь. Из PHP дайте строке JSON выполнить htmlspecialchars чтобы убедиться, что никакие специальные символы не могут быть интерпретированы как HTML. Из Javascript не требуется никакого выхода; просто установите атрибут, и вам хорошо идти.

Что вы можете сделать, так это использовать cdata вокруг вашего элемента / s

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

где mydata является сырой json-строкой. Надеюсь, это поможет вам и другим.