【问题标题】:Best way to store JSON in an HTML attribute?将 JSON 存储在 HTML 属性中的最佳方法是什么?
【发布时间】:2011-11-11 11:14:46
【问题描述】:

我需要将 JSON 对象放入 HTML 元素的属性中。

  1. HTML 不必验证。

    Quentin 回答:Store the JSON in a data-* attribute,这是有效的 HTML5。

  2. JSON 对象可以是任意大小 - 即巨大

    由 Maiku Mori 回答:The limit for an HTML attribute is potentially 65536 characters

  3. 如果 JSON 包含特殊字符怎么办?例如 {foo: '<"bar/>'}

    Quentin 回答:按照通常的约定,在将 JSON 字符串放入属性之前对其进行编码。 For PHP, use the htmlentities() 函数。


编辑 - 使用 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>

使用 jQuery 检索 JSON:

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

});

【问题讨论】:

  • 您应该解释原因并要求不同的解决方案,因为我很确定这不是最好的。您可以使用 data-something 属性,但我不确定它们是否可以容纳“大量”文本。至于特殊字符,您可以对文本进行编码(escape() 和 unescape())。
  • 是的,限制为 65536 个字符 (stackoverflow.com/questions/2752457/…)
  • 顺便说一句,如果你的属性名为data-json,你应该使用$(this).data('json'),jQuery 已经涵盖了这部分。
  • 请注意,不需要将数据后缀命名为 json。如果您将有效的 json 放在任何 data-custom_attribute 中,它将与 jQuery 一起正常工作。
  • 请修正大括号序列 )}; => });

标签: javascript php html json


【解决方案1】:

HTML 不必验证。

为什么不呢?验证是非常简单的 QA,可以发现很多错误。使用 HTML 5 data-* 属性。

JSON 对象可以是任意大小(即巨大)。

我没有看到任何关于浏览器限制属性大小的文档。

如果您确实遇到了它们,请将数据存储在 &lt;script&gt; 中。定义一个对象并将元素 ids 映射到该对象中的属性名称。

如果 JSON 包含特殊字符怎么办? (例如 {test: ''})

只需遵循在属性值中包含不受信任数据的常规规则即可。使用&amp;amp;&amp;quot;(如果将属性值用双引号括起来)或&amp;#x27;(如果将属性值用单引号括起来)。

但是请注意,这不是 JSON(它要求属性名称是字符串,并且字符串只能用双引号分隔)。

【讨论】:

  • 所以你是说我应该先做htmlentities($json),然后再把它放到HTML属性中?然后当我想在 jQuery 中读取它时如何解码它?然后我如何以与 PHP 相同的方式使用 jQuery 将其写回?
  • 所以你是说我应该在将其放入 HTML 属性之前执行 html_encode($json) ? - 如果你使用的是 PHP,那么它会起作用。 然后当我想在 jQuery 中读取它时如何解码它? — 从属性解码?浏览器在将 HTML 解析为 DOM 时会这样做。 然后我如何以与 PHP 中相同的方式使用 jQuery 将其写回? — 您正在设置 DOM 节点的属性,而不是生成原始 HTML,浏览器会处理它.
  • 目前我有一个问题,我的浏览器当前在 Google Chrome 上没有对其进行解码,当我去解析 JSON 时,所有的 HTML 实体都在那里并且失败了。
  • 如果你把它放在一个脚本标签中,由于脚本标签的特殊处理,你必须以不同的方式转义它。例如带有 的值将结束脚本标记。
【解决方案2】:

取决于你把它放在哪里,

  • &lt;div&gt; 中,如您所问,您需要确保 JSON 不包含可能启动标记、HTML 注释、嵌入文档类型等的 HTML 特殊内容。您至少需要转义 &lt; 和 @ 987654325@,这样原始字符就不会出现在转义序列中。
  • &lt;script&gt; 元素中,您需要确保JSON 不包含结束标记&lt;/script&gt; 或转义文本边界:&lt;!----&gt;
  • 在事件处理程序中,您需要确保 JSON 保留其含义,即使它具有看起来像 HTML 实体的内容并且不会破坏属性边界("')。

对于前两种情况(以及旧的 JSON 解析器),您应该对 U+2028 和 U+2029 进行编码,因为它们是 JavaScript 中的换行符,即使它们在 JSON 中未编码的字符串中是允许的。

为了正确起见,您需要转义 \ 和 JSON 引号字符,始终编码 NUL 绝不是一个坏主意。

如果 HTML 可能在没有内容编码的情况下提供,您应该编码 + 以防止 UTF-7 attacks

无论如何,下面的转义表都可以工作:

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

因此,文本 Hello, &lt;World&gt;! 末尾带有换行符的 JSON 字符串值将是 "Hello, \u003cWorld\u003e!\r\n"

【讨论】:

  • return (input.replace(/([\s"'&+\/\\\u2028\u2029\u0000])/g, (match, p1) => { return \\u${p1.codePointAt(0).toString(16).padStart(4, 0)}; }));`
【解决方案3】:

另一种方法 - 将 json 数据放入 &lt;script&gt; 标记内,但不是 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>

【讨论】:

  • 对于 JSON,使用脚本类型“application/json”。从长远来看,将顶层作为对象也很好。
  • 这并没有直接回答操作员的问题,但对我仍然很有帮助。我存储的数据适用于整个页面而不是任何特定元素,因此元素属性实际上不起作用(除非我把它放在 body 元素上,这对我来说似乎有点蹩脚,尤其是因为我的数据可能很大)。将其存储在 &lt;script type="application/json" id="MyData"&gt;&lt;/script&gt; 中效果很好。然后,使用 ActiveWAFL / DblEj,我可以通过以下方式进行查找:document.GetData("#MyData")
  • 此答案包含虚假/危险信息!更改脚本类型不会修改 标记的检测。试试看:&lt;script type="application/json" id="MyData"&gt; "abc&lt;/script&gt;&lt;script&gt;alert()&lt;/script&gt;" &lt;/script&gt;
【解决方案4】:

另一种选择是对 JSON 字符串进行 base64 编码,如果您需要在 javascript 中使用它,请使用 atob() 函数对其进行解码。

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

【讨论】:

  • 感谢atob。我从来没有意识到这一点!
  • 当心 - 如果 JSON 包含非拉丁字符,则不起作用。
【解决方案5】:

对于简单的 JSON 对象,下面的代码可以工作。

编码:

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

解码:

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

【讨论】:

    【解决方案6】:

    你可以使用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());
    

    输出

    名字:杰森 姓氏:蒙特罗索

    检查这个: http://learn.knockoutjs.com/

    【讨论】:

      【解决方案7】:

      这里没什么特别的。在 PHP 中,通过 htmlspecialchars 运行 JSON 字符串,以确保没有特殊字符可以解释为 HTML。来自 Javascript,无需转义;只需设置属性即可。

      【讨论】:

        【解决方案8】:

        另一个可以使用的想法是将 JSON 数据作为 base64 字符串存储在属性中,然后使用 window.atobwindow.btoa 将其恢复为可用的 JSON 数据。

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

        【讨论】:

        • 是的,这似乎是最好的方法。
        【解决方案9】:

        你可以做的是像这样在你的元素周围使用 cdata

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

        其中 mydata 是原始 json 字符串。希望这对您和其他人有所帮助。

        【讨论】:

        • 这个解决方案(可以)如何工作?如果我想在 mydata 中存储类似 "&gt; 的内容怎么办?
        • 如果字符串包含“]]>”
        猜你喜欢
        • 2017-01-03
        • 2011-02-27
        • 1970-01-01
        • 2010-10-22
        • 1970-01-01
        • 1970-01-01
        • 2016-07-21
        • 2013-02-15
        • 1970-01-01
        相关资源
        最近更新 更多