问题描述
我需要将 JSON 对象放入 HTML 元素的属性中。
-
HTML 不必验证。由 Quentin 回答:将 JSON 存储在
data-*
属性中,这是有效的 HTML5 。 -
JSON 对象可以是任何大小 – 即由 Maiku Mori:The limit for an HTML attribute is potentially 65536 characters 回答的巨大的数据。
-
如果 JSON 包含特殊字符怎么办?例如
{foo: '<"bar/>'}
由 Quentin 回答:根据常规惯例,将 JSON 字符串放入属性之前进行编码。 For PHP, use thehtmlentities()
功能。
编辑 – 使用 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);
});
最佳解决方案
The HTML does not have to validate.
为什么不?验证真的很容易 QA 抓住了很多错误。使用 HTML 5 data-*
属性。
The JSON object could be any size (i.e. huge).
我没有看到有关浏览器限制的属性大小的文档。
如果您遇到这种情况,请将数据存储在<script>
中。将对象和映射元素 id
定义到该对象中的属性名称。
What if the JSON contains special characters? (e.g. {test: ‘<“myString/>’})
只需遵循在属性值中包含不受信任数据的常规规则。使用&
和"
(如果您将属性值包含在双引号中) 或'
(如果您将属性值包含在单引号中) 。
但是请注意,这不是 JSON(需要属性名称是字符串和字符串仅用双引号分隔) 。
次佳解决方案
根据你所在的地方,
-
在
<div>
中,您需要确保 JSON 不包含可以启动标签,HTML 注释,嵌入式手册等的 HTML 特殊版本。您需要至少逃脱<
和&
,以使原始字符不会出现在转义的序列中。 -
在
<script>
元素中,您需要确保 JSON 不包含结束标记</script>
或转义文本边界:<!--
或-->
。 -
在事件处理程序中,您需要确保 JSON 保留其含义,即使它具有看起来像 HTML 实体的东西,也不会破坏属性边界 (
"
或'
) 。
对于前两种情况 (对于旧的 JSON 解析器),您应该对 U + 2028 和 U + 2029 进行编码,因为它们是 JavaScript 中的换行符,即使它们被允许在 JSON 中未编码的字符串中。
为了正确,您需要转义和 JSON 引号字符,并且始终编码 NUL 是永远不错的主意。
如果 HTML 可能没有内容编码,您应该编码+
以防止 UTF-7 attacks 。
在任何情况下,以下转义表将工作:
-
NUL – >
u0000
-
CR – >
n
或u000a
-
LF – >
r
或u000d
-
"
– >u0022
-
&
– >u0026
-
'
– >u0027
-
+
– >u002b
-
/
– >/
或u002f
-
<
– >u003c
-
>
– >u003e
-
– >
\
或u005c
-
U+2028 – >
u2028
-
U + 2029 – >
u2029
所以文本 Hello, <World>!
的 JSON 字符串值与最后的换行符是"Hello, u003cWorldu003e!rn"
。
第三种解决方案
另一种方法可以将 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/
第五种方案
另一个选择是对 JSON 字符串进行 base64 编码,如果需要在 JavaScript 中使用它与 atob()
函数进行编码。
var data = JSON.parse(atob(base64EncodedJSON));
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。