Search code examples
javascriptjqueryarraysjsontraversal

How to traverse through HTML and convert it to an array of objects?


I have the following HTML code:

<div class="block" data-type="click">
    <div class="container" data-type="noclick">
        <p>Some text</p>
    </div>
    <div class="container" data-type="noclick">
        <div class="container" data-type="noclick">
            <p data-type="click">More text</p>
        </div>
        <div class="container">
            <p data-type="click">More text</p>
        </div>
    </div>
    ...
        ...
</div>

There is a parent element called block which may contain any number of child elements, of which may also contain any number of child elements itself.

I am using the following code to convert HTML into JSON output:

    site = [];
    ctr = 0;

    $(".block").each(function(){
        site.push([]);
        site[ctr]["type"] = $(this).data("type");
        site[ctr]["class"] = $(this).attr("class");
        site[ctr]["style"] = $(this).attr("style");
        site[ctr]["children"] = [];
            $(this).children().each(function(){
                site[ctr]["children"].push([]);
                site[ctr]["children"]["type"] = $(this).data("type");
                site[ctr]["children"]["class"] = $(this).attr("class");
                site[ctr]["children"]["style"] = $(this).attr("style");
            });
        ctr+=1;
    });

However, for an element that contains many different levels of child elements, what is the best approach to include those in the array?

In other words, the code above only works for elements that contain one level of children - how could I get it to work for an element that contains 20 different levels of children whilst another only contains two?


Solution

  • Follows a full working example using vanilla javascipt and a recursive function:

    function convertToArray(elements) {
        const array = [];
        
        if(!elements || elements.length === 0) {
            return [];
        }    
        
        for(let i=0; i<elements.length; i++) {
            array[i] = {};
            array[i]['class'] = elements[i].getAttribute('class');
            array[i]['type'] = elements[i].getAttribute('data-type');
            array[i]['style'] = elements[i].getAttribute('style');
            array[i]['children'] = convertToArray(elements[i].children);
        }
        return array;
    }
    
    const rootElement = document.getElementsByClassName('block');
    console.log(convertToArray(rootElement));
    <div class="block" data-type="click">
        <div class="container" data-type="noclick">
            <p>Some text</p>
        </div>
        <div class="container" data-type="noclick">
            <div class="container" data-type="noclick">
                <p data-type="click">More text</p>
            </div>
            <div class="container">
                <p data-type="click">More text</p>
            </div>
        </div>
    </div>