Search code examples
jqueryjsontreelisttraversal

jQuery tree traversal - Nested Unordered list elements to JSON


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

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

https://jsfiddle.net/CLLts/

https://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)


Solution

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