jQuery树遍历 - 将嵌套的无序列表元素转换为JSON

3

好的,现在我这里有一个无序列表:

<ul id="mycustomid">
    <li><a href="url of Item A" title="sometitle">Item A</a>
        <ul class="children">
           <li><a href="url of Child1 of A" title="sometitle">Child1 of A</a>
               <ul class="children">
                 <li><a href="url of Grandchild of A" title="sometitle">Grandchild of A</a>
                    <ul class="children">
                       <li><a href="url of Grand Grand child of A" title="sometitle">Grand Grand child of A</a></li>
                    </ul>
                </li>
               </ul>
           </li>
        </ul>
    </li>
    <li><a href="url of Item B" title="sometitle">Item B</a></li>
    <li><a href="url of Item C" title="sometitle">Item C</a></li>
</ul>

基本上,我想把这些数据转换成JSON实体。我想用jQuery完成这个任务,但我发现这很困难。上面的列表只是一个例子,实际上,我的列表理想情况下应该有更多的子节点,并且可能是'n'层深(意思是,它将有孙子的孙子的孙子...或更多)。我已经失去了无数个小时的睡眠,但我觉得我一事无成 :(
我想提取这些内容:锚点内的文本、锚点的URL和锚点的标题,并将它们放到一个JSON实体中。
上面列表的JSON格式如下:
{
        name: "Item A",
        url: "url of Item A",
        title: "sometitle",
        children: [{
                   name: "Child1 of A",
                   url: "url of Child1 of A",
                   title: "sometitle",
                   children: [{
                                name: "Grandchild of A",
                                url: "url of Grandchild of A",
                                title: "sometitle",
                                children: [{
                                           name: "Grand Grand child of A",
                                           url: "url of Grand Grand child of A",
                                           title: "sometitle",
                                           children: []
                                           }]
                              }]
                   }]
},
           {
            name: "Item B",
            url: "url of Item B",
            title: "sometitle",
            children: []
           },
           {
            name: "Item C",
            url: "url of Item C",
            title: "sometitle",
            children: []
           }

一些有用的参考资料:

Javascript解决方案: 使用Javascript/Jquery遍历无序列表

^ 这个可能有效,但我需要的JSON输出格式如上所示,而不是该脚本输出的格式:(

其他参考资料:

将无序列表项放入数组中该怎么办

https://jsfiddle.net/yS6ZJ/1/

https://jsfiddle.net/CLLts/

https://jsfiddle.net/cWnwt/

请有人帮帮忙 :(
已经苦思冥想了很多个彻夜未眠的夜晚。。(注:编写此页面及代码大约花费了40多分钟)


1
正在处理中。顺便说一下,您得到的 JSON 结果是对象数组,因此您应该有 [ 和 ] 括号。[ {}, {}, {} ] - Samuel Meacham
谢谢Samuel,但我的应用程序似乎使用了无效的JSON格式,并且它使用了上述格式 :) 感谢您的输入 :) - dsignr
3个回答

9

啊,一个有趣的递归练习。我有时间做这个,以下是我的方法。该方法可以无限递归到很多层,但是需要注意数据不要过于深入以至于消耗内存(如果递归太深,浏览器会中断)。在至少10个级别左右应该能正常工作。

我已经测试过了,看起来它是有效的,只需将其保存在HTML文件中即可。

很抱歉没有太多注释(严格来说,根本没有 :),因为此代码假定您可以很好地阅读jQuery和JS代码。如果您有问题,请在评论中提问,我很乐意解释。

<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>Recursive list processor example</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
    <script type="text/javascript">

$(document).ready(function() {

    var out = [];

    function processOneLi(node) {       

        var aNode = node.children("a:first");
        var retVal = {
            "title": aNode.attr("title"),
            "url": aNode.attr("href"),
            "name": aNode.text()
        };

        node.find("> .children > li").each(function() {
            if (!retVal.hasOwnProperty("children")) {
                retVal.children = [];
            }
            retVal.children.push(processOneLi($(this)));
        });

        return retVal;
    }

    $("#mycustomid").children("li").each(function() {
        out.push(processOneLi($(this)));
    });


    console.log("got the following JSON from your HTML:", JSON.stringify(out));

});

    </script>
</head>
<body>
<ul id="mycustomid">
    <li><a href="http://example.com/urlOfItemA" title="sometitle">Item A</a>
        <ul class="children">
           <li><a href="http://example.com/urlOfItemAChild1" title="sometitle">Child1 of A</a>
               <ul class="children">
                 <li><a href="http://example.com/urlOfItemAGrandchild" title="sometitle">Grandchild of A</a>
                    <ul class="children">
                       <li><a href="http://example.com/urlOfItemAGrandGrandChild" title="sometitle">Grand Grand child of A</a></li>
                    </ul>
                </li>
               </ul>
           </li>
        </ul>
    </li>
    <li><a href="http://example.com/urlOfItemB" title="sometitle2">Item '"" B</a></li>
    <li><a href="http://example.com/urlOfItemC" title="sometitle3">Item C</a></li>
</ul>
</body>
</html>

1
抱歉,Jaanus,我不在桌前。非常感谢你的努力,你提供的代码完美地运行了,你是我的救星,你为我省去了很多麻烦!!非常感谢!!! :) - dsignr
2
你应该标记被接受的答案,无论你接受哪一个,成为一个好的Stackoverflow公民 :) - Jaanus
然而,它没有按照我的格式输出JSON?例如,我在属性上有引号,比如:"name":"something" "title":"something"但是我需要它像这样: name:"something" title:"something"谢谢 - dsignr
JSON标准规定对象键必须用双引号括起来。我正在使用Douglas Crockford的标准JSON输出器,这是将Javascript对象转换为JSON字符串的行业标准。因此,您所要求的是非标准无效的JSON。您为什么需要它呢? - Jaanus
1
  1. 别担心,我们都曾经是新手 :)
  2. 我明白你的意思。像 JSON 这样的标准的重点在于应用程序以标准方式输入和输出它。正确的做法是修复您的应用程序,使其接受标准有效的 JSON。如果不可能,您可以尝试让 tvanfonsson 的代码工作。您可以看到它如何将自定义 JSON 输出为字符串,并且您可以对其进行修改以生成所需内容。但是真正的解决方法是修复这个其他应用程序。还有其他方法,但它们真的是倒退的不良做法。
- Jaanus
显示剩余2条评论

2

似乎使用递归解决方案,其中一个函数用于集合列表元素(子项),另一个函数用于列表元素,会起作用。请注意,我假设您希望将其格式化为字符串,并且它实际上表示为数组。

$(function() {
    var json = formatListElements( $('#mycustomid > li') );
});

function formatListElements( elems )
{
    var contents = [] 
    $.each( elems, function( index, elem ) {
        contents[index] = formatListElement( elem );
    }
    return '[' + contents.join(', ') + ']';
}

function formatListElement( elem )
{
   var anchor = $(elem).children('a:first');
   return '{ "name": "' + quote( anchor.text() )
                + '", "url": "' + quote( anchor.attr('href') )
                + '", "title": "' + quote( anchor.attr('title') )
                + '", "children": ' + formatListElements( $(elem).find('> ul > li')
        + '}';
}

function quote( str )
{
    return str.replace( /"/g, '\\\"' );
}

这个输出无效的JSON,因为:1)您没有引用属性值;2)您没有转义字符串中的'或"字符,而您应该用引号引用属性值。除此之外还不错。 - Jaanus
@Jaanus -- 是的,这只是一个快速的回答,完全未经测试。我已经添加了属性周围的引号和字符串中引用引号的引号。 - tvanfosson
你现在这样做,可能会引用太多的引号。不确定单引号是否必须在JSON“blah ' blah”字符串内加引号? :) - Jaanus
@Jaanus -- 可能是对的,只需要引用双引号。我认为这不会有影响。 - tvanfosson
@Jaanus - 因为这不是必要的,我会将其删除,但引用引用不会有任何影响。由于只有一个反斜杠,它仍将被解释为引号字符,并且引用单引号的结果是单引号。 - tvanfosson
显示剩余2条评论

2
以下是我的解决方案源代码。我认为它足够清晰,可以展示将
    转换为JSON对象的原理。祝好运 :)

    $(function() {
    
      function buildJSON($li) {
        var subObj = { "name": $li.contents().eq(0).text().trim() };
        $li.children('ul').children().each(function() {
          if (!subObj.children) { subObj.children = []; }
          subObj.children.push(buildJSON($(this)));
        });
        return subObj;
      }
        
      var obj = buildJSON($("#ul-data").children());
      $('body').append('<pre>').find('pre').append(JSON.stringify(obj, null, 2));
    
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <ul id="ul-data">
      <li><a href="#">AAA</a>
        <ul>
          <li><a href="#">DDD</a>
            <ul>
              <li><a href="#">EEE</a>
                <ul>
                  <li><a href="#">FFF</a></li>
                </ul>
              </li>
            </ul>
          </li>
          <li><a href="#">BBB</a></li>
          <li><a href="#">CCC</a></li>
        </ul>
      </li>
    </ul>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接