Jquery tree traversal - Nested Unordered list elem

2019-01-25 22:02发布

Okay, Now I have an unordered list here:

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

Basically, I want to just convert this data into a JSON entity. I want to get this done in Jquery and I think I'm having a really tough time doing it. The above list is just an example and in reality, my list would ideally have more number of children and probably be 'n' levels deep (Meaning, it will have grandchildren of grandchildren of grandchildren...or more) I've lost countless hours of sleep on this and I don't think I'm going anywhere :(

I want to extract these things: The text inside the anchor, the url of the anchor and the title of the anchor and put them onto a JSON entity

The JSON format for my list above is something like this:

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

Some useful references:

Javascript solution: Traversing unordered lists using Javascript/Jquery

^ This one probably works, but the format of the JSON output I need is as shown above and not what this script outputs :(

Other references:

How do I put unordered list items into an array

http://jsfiddle.net/yS6ZJ/1/

http://jsfiddle.net/CLLts/

http://jsfiddle.net/cWnwt/

Someone please help :(
Been breaking my head for many many sleepless nights..(P.s - It took me about 40+ mins to write this entire page along with the code)

Thank you.

3条回答
狗以群分
2楼-- · 2019-01-25 22:48

Ah, a fun little recursive exercise. I had a moment for this and here’s how I would do it. This works many levels deep recursively, but assumes that your data is not deep enough to explode the memory (recursion breaks in browsers if it is too deep). Should be fine for at least 10 levels or so.

I tested this out, seems it works, just save this in a HTML file and you should be fine.

Sorry there are not too many comments (well, technically speaking, none at all :) , this assumes you read jQuery and JS code fine. If you have questions, just ask in a comment and I’d be happy to explain.

<!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>
查看更多
ゆ 、 Hurt°
3楼-- · 2019-01-25 22:50

Seems like a recursive solution using one function for collections of list elements (children) and one for a list element would work. Note I'm assuming that you want it formatted as a string and that it's really represented as an array.

$(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, '\\\"' );
}
查看更多
神经病院院长
4楼-- · 2019-01-25 22:57

The following source code is my solution. I think it's clear enough to show the principle to covert ul to json object. Good Luck :)

$(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>

查看更多
登录 后发表回答