Help me please! There is a source line html from which it is necessary to create Element sequentially. That is, there is a way to create everything at once, simply by parsing the string through innerHTML or DOMParser, but then to iterate over all the elements, you need getElementsByTagName("*"), which is very slow. Is there a way to build html sequentially so that it takes each element in a loop?
Let’s say we have an html string:
<div>abc<span class="abc">123</span>567</div>
And, from it to make some code like this:
let parentDiv = document.createElement("div");
for(let i=0;i<3;i++){
switch(i){
case 0:
let txt1 = document.createTextNode("abc")
parentDiv.appendChild(txt1);
break
case 1:
let el1 = document.createElement("div");
el1.setAttribute("class","abc");
for(let j=0;j<1;j++){
switch(j){
case 0:
let txt1 = document.createTextNode("123")
el1.appendChild(txt1);
break;
}
}
parentDiv.appendChild(el1);
break
case 2:
let txt2 = document.createTextNode("567")
parentDiv.appendChild(txt2);
break
}
}
Only to generate such code for any valid html string.
I will be very grateful for the answer!
I think that a template will be needed here to create such code, as well as a regular expression regexp for tags. It’s just hard to figure out how to do it.
2
Answers
The problem
Note: I am not sure if I understand your question correctly. If I misunderstood, please correct me, and I will edit the answer.
If in understand your question correctly, you want to create a JavaScript function which takes a string with an HTML code (e.g.
'<div>abc</div>'
) as an argument and creates the corresponding DOM elements. The string can contain any HTML code (e.g. divs, spans, tables, etc.). Moreover, you do not want the elements to be created at once but sequentially in a loop.Furthermore, you do not want to use the
innerHTML
property to create all of the elements at once and then iterate over all the elements usinggetElementsByTagName("*")
method because you feel that it is too slow.Answer
I think that the JavaScript function you want to create could be created but it would be a VERY complex function. You would first need to identify the individual elements (possibly using regular expressions to find opening and closing tags) including their respective classes and other attributes (such as id, name, href, etc.). Then you would need to create the individual DOM elements in a loop.
I think that much simpler, safer (less prone to errors), and more clear way would be to use the
innerHTML
property and thegetElementsByTagName("*")
method. I do not know why you think that the method is very slow. According to this test,getElementsByTagName("*")
is not slow at all as you can run millions of these operations in a single second. I think that your custom complex JavaScript function would probably be much slower because it would have to complete all of the steps described in the previous paragraph.If you decide to use the
innerHTML
property and thegetElementsByTagName("*")
method, the code could look like this:However, if you really want to create your custom function, you can try to read through the source code of JourneyApps’s domparser and use it to create your own custom function.
Additional notes
I do not understand, why you would use the loops and
switch
statements in your example JavaScript code. Your JavaScript code could be rewritten simply as:After parsing the string to HTML, you can use the TreeWalker API to sequentially walk (in preorder traversal) the DOM subtree of a node via
nextNode()
. As you visit each node, you can check thenodeType
and other properties to determine what code to generate (i.e. if it’s an element node, usegetAttributeNames()
to extract each attribute and generate the code for setting each attribute, andtagName
to get the tags, etc.).The only caveat is that the API doesn’t expose an obvious method for determining whether the next Node is a child, sibling or somewhere up the parent chain. So you will likely need a way of tracking the current node’s depth, but I believe if you implement this code generation somewhat recursively, you should get that behavior for free.
Here is what the very high-level pseudocode might look like: