javascript 将 HTML DOM 结构转换为 JSON
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7993066/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
convert HTML DOM structure to JSON
提问by vsync
I have wasted so much time on this..the recursion part is quite illusive.
for a given HTML structure, of unknown depth, I need to convert to JSON.
(I use this from some YAML i18n translation system I am building)
我在这上面浪费了很多时间......递归部分非常虚幻。
对于未知深度的给定 HTML 结构,我需要转换为 JSON。
(我从我正在构建的一些 YAML i18n 翻译系统中使用它)
my general idea is to go deep until it finds the INPUT
, then create an
object with the key/value of the span.innerHTML/input.value
, and return that
object, so it will be the VALUE of a KEY that is the last <span class="title">
reached.
我的一般想法是深入直到找到INPUT
,然后使用 的键/值创建一个对象span.innerHTML/input.value
,并返回该对象,因此它将是最后<span class="title">
到达的 KEY 的值。
(Yes, it's a bit complicated but very interesting to develop)
(是的,它有点复杂但开发起来很有趣)
JSBIN playground- live code example
JSBIN 游乐场- 实时代码示例
I can't get my recursive function to work properly, to output the JSON I want...
我无法让我的递归函数正常工作,无法输出我想要的 JSON...
HTML structure
HTML 结构
<ul>
<li>
<span class="title">footer</span>
<ul>
<li>
<span>statement</span>
<input type="text" value="xxx">
</li>
</ul>
</li>
<li>
<span class="title">landing</span>
<ul>
<li>
<span>page_title</span>
<input type="text" value="yyy">
</li>
<li>
<span>page_sub_title</span>
<input type="text" value="xxx">
</li>
<li>
<span class="title">pricing</span>
<ul class="level11">
<li>
<span>title</span>
<input type="text" value="aaa">
</li>
<li>
<span>cost</span>
<input type="text" value="xxx">
</li>
</ul>
</li>
</ul>
</li>
</ul>
(Wanted) JSON output
(想要的)JSON 输出
{
footer : {
statement : 'xxx'
},
landing : {
page_title : 'yyy',
page_sub_title : 'xxx',
pricing : {
title : 'aaa',
cost : 'xxx'
}
}
}
采纳答案by Yoshi
If you can convince yourself to using jQuery, try this:
如果您可以说服自己使用 jQuery,请尝试以下操作:
function helper(root) {
var result = {};
$('> ul > li > span', root).each(function () {
result[$(this).text()] = $(this).hasClass('title') ? helper($(this).parent()) : $(this).next('input').val();
});
return result;
}
console.log(helper('body'));
回答by fortune
I'm new here and i couldn't find how to post a comment. I wanted to ask you if this is always the structure, no matter the dept. If the answer is no, then don't read my answer :).
我是新来的,我找不到如何发表评论。我想问你这是否总是结构,不管部门。如果答案是否定的,那么请不要阅读我的答案:)。
So first of all i added a function getPrevious, because directly trying to get the previous sibling returns you a text node. Next i changed the recursion a little bit, because it's not a simple recursion, the json format (the parent-child relations) is different then the html format. I tried it for 2 more levels and it's ok. I hope it's helpful and sorry if it's not.
所以首先我添加了一个函数 getPrevious,因为直接尝试获取前一个兄弟节点会返回一个文本节点。接下来我稍微改变了递归,因为它不是简单的递归,json格式(父子关系)与html格式不同。我又试了 2 个级别,没问题。我希望它有帮助,如果没有,我很抱歉。
function getPrevious(element)
{
var prev_el = element.previousSibling;
while (prev_el.nodeType == 3)
{
prev_el = prev_el.previousSibling;
}
return prev_el;
}
function recursive(element){
//var classname = element.className.split(' ');
// element.nodeName == 'UL'
var Result = {"title": '', "json": {}};
var json = {};
var cur_json_key = '';
if( element.nodeType == 3 )
return;
else{
//console.log( element.nodeType, element );
var nodeName = element.nodeName.toLowerCase();
var nodeClass = element.className.toLowerCase();
// if this is the SPAN with class 'TITLE', then create an object with the innerHTML as KEY
// and later the value should be another object, returned from the recursion...
if( nodeName == 'span' && nodeClass == 'title' ){
json[element.innerHTML] = {};
Result.title = element.innerHTML;
Result.json = json;
}
else
if( nodeName == 'input' ){
// if this is an INPUT field, then the SPAN sibling before it is the KEY.
var key = getPrevious(element).innerHTML;
var val = element.value;
Result.json[key] = val;
}
else
{
var is_title_found = 0;
var title_found = '';
var res = {}
// go deeper
for( var child=0; child < element.childNodes.length; child++ ){
//json = $.extend( {}, recursive( element.childNodes[child] ));
res = recursive( element.childNodes[child]);
if (res)
{
if (res.title != '')
{
is_title_found = 1;
title_found = res.title;
}
else
{
$.extend(true, json, res.json);
}
console.log(JSON.stringify(json));
}
}
if (title_found)
{
Result.json[title_found] = json
}
else
{
Result.json = json;
}
}
return Result;
}
}
回答by user3051730
<section id="in">
<ul>
<li><div>lorem</div></li>
<li>
<div>lorem</div>
<ul>
<li><div>lorem</div></li>
<li>
<div>lorem</div>
</li>
<li>
<div>lorem</div>
<ul>
<li><div>lorem</div></li>
<li>
<div>lorem</div>
</li>
<li><div>lorem</div></li>
<li><div>lorem</div></li>
</ul>
</li>
<li><div>lorem</div></li>
</ul>
</li>
<li><div>lorem</div></li>
<li><div>lorem</div></li>
</ul>
</section>
<textarea id="outjson"></textarea>
var a = [];
getJSON($('#in'), a);
function getJSON(el, arr)
{
el.children().each(function()
{
arr.push({});
arr[arr.length-1][this.tagName] = [];
if ($(this).children().length > 0)
{
getJSON($(this), arr[arr.length-1][this.tagName]);
}
});
}
$('#outjson').text(JSON.stringify(a));
You will get:
你会得到:
[{"UL":[{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]},{"UL":[{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]},{"UL":[{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]}]}]}]},{"LI":[{"DIV":[]}]}]}]},{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]}]}]}]
[{"UL":[{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]},{"UL":[{"LI": [{"DIV":[]}]},{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]},{"UL":[ {"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]}]},{"LI":[{"DIV":[]}]} ,{"LI":[{"DIV":[]}]}]}]},{"LI":[{"DIV":[]}]}]}]},{"LI":[{ "DIV":[]}]},{"LI":[{"DIV":[]}]}]}]
回答by Marcelo Matos
Try this:
试试这个:
function helper(root) {
var result = {};
root.querySelectorAll(':scope > ul > li > span').forEach(function (obj) {
result[obj.innerText] = obj.classList.contains('title') ? helper(obj.parentNode) : obj.parentNode.querySelector('input').value;
});
return result;
}
console.log(helper(document.querySelector('body')));
回答by Raynos
var ul = document.body.firstElementChild;
// cheat to only extract the value (key is undefined)
var data = extractKeyValue({}, ul)[1];
function extractKeyValue(span, thing) {
// return key & input value
if (thing.tagName === "INPUT") {
return [span.textContent, thing.value];
} else {
// recurse over every li and return the key/value of the span + thing
var obj = {};
[].forEach.call(thing.children, function (li) {
var span = li.firstElementChild;
var thing = span.nextElementSibling;
// tuple is [key, value]
var tuple = extractKeyValue(span, thing);
obj[tuple[0]] = tuple[1];
});
return [span.textContent, obj];
}
}