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

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


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

});

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

В зависимости от того, где вы его положили,

  • В <div>, как вы просили, вам нужно убедиться, что JSON не содержит специальных HTML файлов, которые могут запускать тег, комментарий HTML, встроенный doctype и т.д. Вам нужно избежать не менее < и & таким образом, чтобы исходный символ не появлялся в escape-последовательности.
  • В элементах <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".

Ответ 3

Другой способ, которым вы можете это сделать, - поместить данные 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>

Ответ 4

Вы можете использовать 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/

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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

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