Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to console.log entire HTML DOM tree in order with attribute names

So I am trying create a function, that will console.log the entire DOM tree of the HTML page. It is supposed to output the tag name of each HTML element in the order they appear - children before siblings + attribute name.

I have this working piece of code:

"use strict";

document.addEventListener("DOMContentLoaded", traverse);

function traverse() {
    let elm = document.documentElement;
    displayInfo(elm);
};

function displayInfo(elm){
    //console.log(elm) 
    /* if (elm.childElementCount>0) {
        let children = Array.from(elm.children);
        console.log(children);
        children.forEach( displayInfo );
    }; */
    if (elm.hasAttributes) {
        //console.log(elm.attributes[0]);
    }; 
    var c = elm.childNodes;
    let i;
    for (i = 0; i < c.length; i++) {
        console.log(c[i].nodeName);
        if (c[i].childElementCount>0) {
            //console.log(c[i].childElementCount);
            if (c[i].hasAttributes) {
                //console.log(c[i].attributes[0]);
            };
            let cc = c[i].children;
            let ii;
            for (ii=0; ii < cc.length; ii++) {
                console.log(cc[ii].nodeName);
                if (cc[ii].hasAttributes) {
                    //console.log(cc[ii].attributes[0]);
                };
                if (cc[ii].childElementCount>0) {
                    //console.log(cc[ii].childElementCount);
                    let ccc = cc[ii].children;
                    let iii;
                    for (iii=0; iii < ccc.length; iii++) {
                        console.log(ccc[iii].nodeName);
                        if (ccc[iii].hasAttributes) {
                            //console.log(ccc[iii].attributes[0]);
                        };
                        if (ccc[iii].childElementCount>0) {
                            //console.log(ccc[iii].childElementCount);
                            let cccc = ccc[iii].children;
                            let iiii;
                            for (iiii=0; iiii < cccc.length; iiii++) {
                                console.log(cccc[iiii].nodeName);
                                if (cccc[iiii].hasAttributes) {
                                    //console.log(cccc[iiii].attributes[0]);
                                };
                                if (cccc[iiii].childElementCount>0) {
                                    console.log(cccc[iiii].childElementCount)
                                }
                            }
                        }
                    }
                }
            }
        }
    }
 };

The problem is, I am horribly repeating myself, plus I am manually setting how "deep" it will traverse. Is there a way to declare only one function that traverse?

PS: I know it's horrible to look at, I was just making sure the function would "work" all the way.

like image 697
the_odor Avatar asked Sep 06 '25 03:09

the_odor


2 Answers

There is an API just for this which is way more powerful than anything you could try to build yourself: TreeWalker.

var walker = document.createTreeWalker(
  document.documentElement,
  NodeFilter.SHOW_ELEMENT // only elements
);
while (walker.nextNode()) {
  let current = walker.currentNode;
  console.log(
    current.tagName,
    [...current.attributes].map(({value,name}) => `${name}=${value}`).join()
  );
}
<article>
  <div id="container">container content
    <span>one span</span>
    <span class="nest1">nest1 span<span class="nest2">nest2 span</span></span>
  </div>
</article>
like image 143
Kaiido Avatar answered Sep 09 '25 01:09

Kaiido


Just wanted to add this simple log of all nodes in a document object element names id and classes included placed in a neat array.

console.log(document.getElementsByTagName('*'));

like image 45
Bama Avatar answered Sep 09 '25 01:09

Bama