Harsha Venkataramu
Harsha Venkataramu

Reputation: 2914

nested xml into unordered list in jquery

I am trying to convert a nested xml document to an unordered list using jquery.The xml document is

    <?xml version="1.0" encoding="utf-8"?>
    <Parent>
    <name>Director</name>
    <Children>Exe Director1</Children>
    <Children>Exe Director2</Children>
    <Parent>
        <name>Exe Director3</name>
        <Children>Sub Director 1</Children>
        <Children>Sub Director 2</Children>
        <Parent>
            <name>Sub Director 3</name>
            <Children>Cameraman 1</Children>
            <Children>Cameraman 2</Children>
        </Parent>
    </Parent>    
</Parent>

The expected output:

 <ul>
    <li>Director
        <ul>
            <li>Exe Director 1</li>
            <li>Exe Director 2</li>
            <li>Exe Director 3
                <ul>
                    <li>Sub Director 1</li>
                    <li>Sub Director 2</li>
                    <li>Sub Director 3
                        <ul>
                            <li>Cameraman 1</li>
                            <li>Cameraman 2</li>
                        </ul>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

The output which I am getting.

 <ul>
        <li>Director</li>
        <ul>
            <li>Exe Director1</li>
            <li>Exe Director2</li>
            <li>Exe Director3</li>
            <ul>
                <li>Sub Director 1</li>
                <li>Sub Director 2</li>
                <li>Sub Director 3</li>
                <ul>
                    <li>Cameraman 1</li>
                    <li>Cameraman 2</li>
                </ul>
            </ul>
        </ul>
    </ul>

As you can see,the Children are not getting created inside the parent li but outside it The latest version of the code

    <!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    var levels;
    $(document).ready(function() 
    {
        $.ajax({
            type: "GET",
            url: "test.xml",
            dataType: "xml",
            success: function (xml) { 
                var $ul = xmlParser(xml, $('#ListContainer'));
            }
        });
    });

    function xmlParser(xml,ul) {
        $(xml).contents().each(function (i, el) 
        {
            if (el.nodeName.toUpperCase() == "CHILDREN") 
            {
               $("<li>").text($(el).text()).appendTo($('ul:last')); // Append <li> Children
            } else if (el.nodeName.toUpperCase() == "NAME") 
            {
                $('<li>').text($(el).text()).appendTo(ul);
                $('<ul>').insertAfter($("li:last"));
            }
            else if (el.nodeName.toUpperCase() == "PARENT") 
            {
               if($('ul').length == 0)
                {
                    ul = ul.append('<ul>');
                }
                ul.append(xmlParser($(el),$("ul:last") )); // Recursively append the other Parent
            }
        });
        return ul;
    }
</script>
</head>
<body>
    <div id="ListContainer"></div>
</body>
</html>

I am breaking my head over this code.Can you guys help me out with what might be going wrong!

Thanks

Upvotes: 1

Views: 2152

Answers (4)

jsexpert
jsexpert

Reputation: 52

You are appending PARENT element to same "ul" element for all "PARENT" contents. use

$ul.find('li').last().append(xmlParser($(el)));

instead of

$ul.append(xmlParser($(el)));

Upvotes: 0

rt2800
rt2800

Reputation: 3045

Here is Consolidation of my comments into a coherent answer-->

  1. move $("#ListContainer").append($ul); out of recursion;
  2. create <UL> outside xmlParser() method and pass it as parentElem. e.g. var $ul = xmlParser(xml, $('<ul>')); $("#ListContainer").append($ul) (in success callback of $.ajax)
  3. Return $ul as output result of xmlParser() function

Upvotes: 1

My suggestion is to use jQuery's map function recursively, as in the following example:

<script type="text/javascript">
$(function() {
    var map = function() {
            if ($(this).is("parent")) {
                var children = $(this).children().map(map).get().join('');
                $(this).children().remove();
                var result = "<li>" + $(this).text();
                return result + "<ul>" + children + "</ul></li>";
            }

            if ($(this).is("Children")) {
                return "<li>" + $(this).text() + "</li>";
            }
        };

    $.get("test.xml", function(data) {
        var result = $(data).map(map);
        $("div").html("<ul>" + result[0] + "</ul>");
    }, "html");
}); 
</script>

This ensures that the input tree is traversed completely, and that the resulting output has the same "indentations" as the input.

Notice that map() returns an array, so the resulting string is present as the first item of the array.

Upvotes: 1

YogeshWaran
YogeshWaran

Reputation: 2281

You are appending PARENT element to same "ul" element for all "PARENT" contents. use

 $ul.find('li').last().append(xmlParser($(el)));

instead of

 $ul.append(xmlParser($(el)));

refer below link for last api:

http://api.jquery.com/last/

Upvotes: 1

Related Questions