将JSON存储在HTML属性中的最佳方法?


112

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

  1. HTML不必验证。

    昆汀回答:将JSON存储在data-*有效HTML5 attribute中

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

    森·麦库(Maiku Mori)回答:HTML属性的限制可能为65536个字符

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

    昆汀回答:按照常规惯例,将JSON字符串放入属性之前进行编码。对于PHP,请使用函数 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/...
Maiku森

1
顺便说一句,如果您的属性已命名data-json,则应使用$(this).data('json'),jQuery已覆盖了该部分。
Ciantic

仅需注意,不需要将数据后缀命名为json。如果您将有效的json放在任何data-custom_attribute中,它将与jQuery一起正常工作。
Garet Claborn 2014年

请修正括号顺序)}; =>});
MotsManish

Answers:


41

HTML不必验证。

为什么不?验证真的很容易进行质量检查,它会捕获很多错误。使用HTML 5 data-*属性。

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

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

如果确实遇到了问题,则将数据存储在中<script>。定义一个对象,然后将ids 映射到该对象中的属性名称。

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

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

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


5
因此,您是说我应该htmlentities($json)在将其放入HTML属性之前执行该操作?然后,当我想在jQuery中读取它时,该如何解码呢?然后,如何以与PHP相同的方式使用jQuery将其写回?
BadHorsie 2011年

6
所以您是说我应该在将其放入HTML属性之前执行html_encode($ json)吗?—如果您使用的是PHP,则可以使用。然后,当我想在jQuery中读取它时,该如何解码呢?—从属性解码?浏览器在将HTML解析为DOM时将执行此操作。然后,如何以与PHP相同的方式使用jQuery将其写回?—您正在设置DOM节点的属性,而不是生成原始HTML,浏览器会处理它。
昆汀

1
目前,我遇到了一个问题,即我的浏览器当前无法在Google Chrome上对其进行解码,而当我解析JSON时,所有HTML实体都在那里并且失败了。
布拉德利·韦斯顿

如果将其放在脚本标签中,则由于对脚本标签的特殊处理,必须对其进行不同的转义。例如,其中带有</ script>的值将结束script标签。
Dobes Vandermeer

16

根据你放的位置

  • <div>您所要求的中,您需要确保JSON不包含可以开始标签,HTML注释,嵌入式doctype等的HTML特殊字符。您需要至少转义<,并且&原始字符不会出现在转义序列中。
  • <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

因此,结尾Hello, <World>!带有换行符的文本的JSON字符串值为"Hello, \u003cWorld\u003e!\r\n"


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

14

您可以执行的另一种方法-将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>

1
对于JSON,请使用脚本类型“ application / json”。从长远来看,最好将顶级作为对象。
OIS,2015年

1
这并不能直接回答操作者的问题,但对我仍然很有帮助。我存储的数据整体上适用于页面,而不适用于任何特定元素,因此element属性并不能真正起作用(除非我将其放在body元素上,这对我来说似乎有点la脚,尤其是因为数据可能很大)。<script type="application/json" id="MyData"></script>完美地存储它。然后,使用ActiveWAFL / DblEj,可以使用以下命令进行查找document.GetData("#MyData")
伊万·德拉克鲁斯

2
该答案包含虚假/危险信息!更改脚本类型不会修改</ script>标记的检测。试试看:<script type="application/json" id="MyData"> "abc</script><script>alert()</script>" </script>
hyperknot

12

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

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

谢谢你atob。我从来没有意识到这一点!
Ifedi Okonkwo

3
当心-如果JSON包含非拉丁字符,则不起作用。
Realexer '16

5

你可以使用knockoutjs,

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

基因敲除

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


2

这里没什么好看的。从PHP开始,请提供JSON字符串htmlspecialchars以确保没有特殊字符可以解释为HTML。使用Javascript,无需转义;只需设置属性,您就可以开始了。


2

对于简单的JSON对象,下面的代码将起作用。

编码:

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

解码:

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

1

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

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

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


该解决方案如何运作?如果我想">在mydata中存储类似内容怎么办?
Martin Pecka 2014年

1
如果字符串包含“]]>”怎么办?
Dobes Vandermeer

1

可以使用的另一种思路是将JSON数据作为base64字符串存储在属性中,然后使用window.atobwindow.btoa将其还原为可用的JSON数据。

<?php
$json = array("data"=>"Some json data thing");
echo "<div data-json=\"".base64_encode(json_encode($json))."\"></div>";
?>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.