JSON'u bir HTML özniteliğinde saklamanın en iyi yolu?


112

Bir HTML öğesindeki bir özniteliğe bir JSON nesnesi koymam gerekiyor.

  1. HTML'nin doğrulanması gerekmez.

    Quentin tarafından cevaplandı: JSON'yi geçerli HTML5 olan bir data-*öznitelikte saklayın.

  2. JSON nesnesi herhangi bir boyutta olabilir - yani çok büyük

    Maiku Mori tarafından cevaplandı: Bir HTML niteliği için sınır potansiyel olarak 65536 karakterdir .

  3. Ya JSON özel karakterler içeriyorsa? Örneğin {foo: '<"bar/>'}

    Quentin tarafından yanıtlandı: JSON dizesini olağan kurallara göre özniteliğe koymadan önce kodlayın. PHP için işlevi kullanın . htmlentities()


EDIT - PHP ve jQuery kullanan örnek çözüm

JSON'yi HTML özelliğine yazma:

<?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'u jQuery kullanarak alma:

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

});

Bunun en iyisi olmadığından oldukça emin olduğum için muhtemelen nedenini açıklamalı ve farklı bir çözüm istemelisiniz. Veri-bir şey özniteliklerini kullanmayı deneyebilirsiniz, ancak "büyük" miktarda metin tutabileceklerinden emin değilim. Özel karakterlere gelince, metni kodlayabilirsiniz (escape () ve unescape ()).
Maiku Mori

Evet sınırı 65536 karakterdir ( stackoverflow.com/questions/2752457/… )
Maiku Mori

1
Btw, eğer öznitelik data-jsonkullanman gereken isimlendirildiyse $(this).data('json'), jQuery seni o kısımda ele aldı.
Ciantic

Sadece bir not, veri sonekini json olarak adlandırmak gerekli değildir. Herhangi bir data-custom_attribute içine geçerli json koyarsanız, jQuery ile sorunsuz çalışacaktır.
Garet Claborn

lütfen kaşlı ayraç sırasını düzeltin)}; =>});
MotsManish

Yanıtlar:


41

HTML'nin doğrulanması gerekmez.

Neden olmasın? Doğrulama, birçok hatayı yakalayan gerçekten kolay bir QA'dır. Bir HTML 5 data-*özelliği kullanın .

JSON nesnesi herhangi bir boyutta olabilir (yani çok büyük).

Boyutları ilişkilendirmek için tarayıcı sınırlarıyla ilgili herhangi bir belge görmedim.

Bunlarla karşılaşırsanız, verileri bir <script>. Bir nesne tanımlayın ve öğeleri idbu nesnedeki özellik adlarıyla eşleyin.

Ya JSON özel karakterler içeriyorsa? (örneğin {test: '<"myString />'})

Öznitelik değerlerine güvenilmeyen verileri dahil etmek için normal kuralları izleyin. Kullanım &amp;ve &quot;(eğer çift tırnak öznitelik değeri sarma eğer) ya da &#x27;(eğer sen sarma tek tırnak içinde öznitelik değeri).

Bununla birlikte, bunun JSON olmadığını unutmayın (bu, özellik adlarının dizeler olmasını ve dizelerin yalnızca çift tırnaklarla sınırlandırılmasını gerektirir).


5
Yani htmlentities($json)HTML özelliğine koymadan önce yapmam gerektiğini mi söylüyorsun ? Ve sonra jQuery'de okumak istediğimde bunu nasıl çözebilirim? Ve sonra jQuery kullanarak PHP'de olduğu gibi nasıl geri yazarım?
BadHorsie

6
Yani HTML özelliğine koymadan önce html_encode ($ json) yapmam gerektiğini mi söylüyorsunuz? - PHP kullanıyorsanız, o zaman işe yarar. Ve sonra jQuery'de okumak istediğimde bunu nasıl çözebilirim? - Öznitelikten kod çözülsün mü? Tarayıcı, HTML'yi bir DOM'a ayrıştırdığında bunu yapacaktır. Ve sonra jQuery kullanarak PHP'de olduğu gibi nasıl geri yazarım? - DOM düğümlerinin özniteliklerini ayarlıyorsunuz, ham HTML oluşturmuyorsunuz, tarayıcı bununla ilgilenecektir.
Quentin

1
Şu anda tarayıcımın kodunu şu anda Google Chrome'da çözmediği bir sorun yaşıyorum ve JSON'u ayrıştırmaya gittiğimde tüm HTML varlıkları orada ve başarısız oluyor.
Bradley Weston

Bunu bir komut dosyası etiketine koyarsanız, komut dosyası etiketlerinin özel olarak işlenmesi nedeniyle farklı bir şekilde çıkış yapmanız gerekir. örneğin içinde </script> olan bir değer komut dosyası etiketini sonlandırır.
Dobes Vandermeer

16

Nereye koyduğunuza bağlı olarak,

  • Bir de <div>istediğin gibi, JSON bir etiket, HTML açıklama, gömülü Doctype'ı başlayabileceğini HTML özel içermediğinden emin olmalısınız vb En azından kaçmak gerekir <ve &özgün karakteri yok öyle bir şekilde kaçan sırayla görünür.
  • Gelen <script>elemanları JSON bir uç etiketi içermiyorsa sağlamak gerekir </script>: ya kaçan metin sınırını <!--ya -->.
  • Olay işleyicilerinde, HTML varlıkları gibi görünen ve öznitelik sınırlarını ( "veya ') bozmayan şeyler olsa bile JSON'un anlamını koruduğundan emin olmanız gerekir .

İlk iki durum için (ve eski JSON ayrıştırıcıları için) U + 2028 ve U + 2029'u kodlamalısınız çünkü bunlar JSON'da kodlanmamış dizelerde izin verilse bile JavaScript'teki yeni satır karakterleri.

Doğruluk için, \JSON karakterlerinden alıntı yapmanız gerekir ve her zaman NUL'u kodlamak asla kötü bir fikir değildir.

HTML, içerik kodlaması olmadan sunulabilirse, UTF-7 saldırılarını+ önlemek için kodlamalısınız .

Her durumda, aşağıdaki çıkış tablosu çalışacaktır:

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

Dolayısıyla, Hello, <World>!sonunda bir satırsonu olan metnin JSON dize değeri olur "Hello, \u003cWorld\u003e!\r\n".


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

14

Bunu yapmanın başka bir yolu da json verilerini <script>etiketin içine koymaktır , ancak javascript yürütülmesini önlemek için type="text/javascript"ile değil, type="text/bootstrap"veya type="text/json"yazın.

Ardından, programınızın herhangi bir yerinde şu şekilde sorabilirsiniz:

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

Sunucu tarafında şöyle bir şey yapabilirsiniz (bu örnek php ve twig ile ):

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

1
JSON için "application / json" komut dosyası türünü kullanın. Ayrıca uzun vadede bir nesne olarak en üst seviyeye sahip olmak güzel.
OIS

1
Bu, operasyonun sorusuna doğrudan cevap vermiyor ama yine de bana çok yardımcı oldu. Depoladığım veriler, belirli bir öğeye değil, bir bütün olarak sayfaya uygulanır; bu nedenle, bir öğe özelliği gerçekten çalışmaz (bunu vücut öğesinin üzerine koymazsam, özellikle de veriler büyük olabilir). Bir <script type="application/json" id="MyData"></script>eserde mükemmel bir şekilde saklamak . Ardından, ActiveWAFL / DblEj kullanarak, beraber açın bakın: document.GetData("#MyData").
Evan de la Cruz

2
Bu cevap yanlış / tehlikeli bilgiler içeriyor! Komut dosyası türünün değiştirilmesi, </script> etiketlerinin algılanmasını değiştirmez. Deneyin:<script type="application/json" id="MyData"> "abc</script><script>alert()</script>" </script>
hyperknot

12

Başka bir seçenek de JSON dizesini base64 kodlamaktır ve bunu javascript'inizde kullanmanız gerekiyorsa, atob()işlevle kodunu çözün .

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

İçin teşekkürler atob. Bunun asla farkında değildim!
Ifedi Okonkwo

3
Dikkat - JSON latin olmayan karakterler içeriyorsa çalışmaz.
Realexer

5

Nakavtları kullanabilirsiniz,

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

Çıktı

Adı: Jayson Soyadı: Monterroso

Şunu kontrol edin: http://learn.knockoutjs.com/


2

Burada hiçbir şey fantezi değil. PHP'den, htmlspecialcharshiçbir özel karakterin HTML olarak yorumlanamayacağından emin olmak için JSON dizesini çalıştırın . Javascript'ten kaçmaya gerek yok; sadece özelliği ayarlayın ve gitmeniz iyi olur.


2

Basit JSON nesneleri için aşağıdaki kod çalışacaktır.

kodlama:

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

Kod Çözme:

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

1

Yapabileceğiniz şey, bu şekilde elemanlarınızın etrafında cdata kullanmaktır

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

mydata, ham bir json dizesidir. Umarım bu size ve başkalarına yardımcı olur.


Bu çözüm nasıl çalışır (yapabilir)? ">Verilerimde olduğu gibi bir şey saklamak istersem ne olur ?
Martin Pecka

1
Ya dizi "]]>" içeriyorsa
Dobes Vandermeer

1

Kullanılabilecek başka bir düşünce, JSON verilerini öznitelikte bir base64 dizesi olarak depolamak ve ardından onu kullanılabilir JSON verilerine geri yüklemek window.atobveya kullanmaktır window.btoa.

<?php
$json = array("data"=>"Some json data thing");
echo "<div data-json=\"".base64_encode(json_encode($json))."\"></div>";
?>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.