【问题标题】:convert HTML DOM structure to JSON将 HTML DOM 结构转换为 JSON
【发布时间】:2011-12-21 00:57:24
【问题描述】:

我在这上面浪费了很多时间。递归部分很虚幻。
对于给定的深度未知的 HTML 结构,我需要转换为 JSON。
(我在我正在构建的一些 YAML i18n 翻译系统中使用它)

我的一般想法是深入直到找到INPUT,然后创建一个 具有span.innerHTML/input.value 的键/值的对象,并返回该对象 对象,因此它将是最后一个到达 <span class="title"> 的 KEY 的 VALUE。

(是的,这有点复杂,但开发起来很有趣)

JSBIN playground - 实时代码示例

我的递归函数无法正常工作,无法输出我想要的 JSON...

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>


(需要)JSON 输出

{
    footer : {
        statement : 'xxx'
    },
    landing : {
        page_title : 'yyy',
        page_sub_title : 'xxx',
        pricing : {
            title : 'aaa',
            cost : 'xxx'
        }
    }
}

【问题讨论】:

  • 是否有意缺少帮助库(例如 jQuery)?同样document.querySelectorAll的用法?我的意思是,它会让事情变得更容易......
  • 只是一个简短的旁注:你听说过label吗?你应该使用它。

标签: javascript html json


【解决方案1】:

如果你能说服自己使用 jQuery,试试this

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

【讨论】:

    【解决方案2】:

    Live Example

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

    【讨论】:

    • 非常时尚,很好地使用了[].forEach.call(thing.children, function (li) {
    【解决方案3】:

    我是新来的,我找不到如何发表评论。我想问你这是否总是结构,无论部门如何。如果答案是否定的,请不要阅读我的答案:)。

    所以首先我添加了一个函数 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;
            }
        }
    

    【讨论】:

    • 是的,无论深度如何,这始终是结构。感谢您发布答案!
    • @fortune :添加 cmets 只能通过足够的声望来完成,但您无需等待很长时间即可获得该声望。这是你的前 10 个额外的 ;)
    【解决方案4】:
    <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));
    

    你会得到:

    [{"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":[]}]}]}]

    【讨论】:

      【解决方案5】:

      试试这个:

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

      【讨论】:

      • 哦对不起哈哈哈
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-12
      • 2021-12-10
      • 1970-01-01
      • 2015-11-12
      • 2018-11-07
      • 1970-01-01
      • 2011-01-10
      相关资源
      最近更新 更多