Replace almost all HTML tags without some of them in string in JS

Viewed 612

I need to replace almost all HTML tags from string.

The content of tags should be kept.

There are just a few tags I would like to keep:

  • p
  • li
  • ul
  • ol
  • b

e.g.:

INPUT:
"<p>TEXT</p><div>container</div><p></p><ul><li><b>list element</b>: 0.1 [mm]</li><li><strong>Another list element</strong>: 0.2</li></ul><span>span element</span>"
​
OUTPUT:
"<p>TEXT</p>container<p></p><ul><li><b>list element</b>: 0.1 [mm]</li><li>Another list element: 0.2</li></ul>span element"

I know that i can do it by replacing all tags one by one:

string.replace(/<\/span>/g, '');

Maybe there is any faster option.

How can I achieve it?

2 Answers

It's always better to avoid using a regular expression to parse Html and in your case you could use an html parser such as DOMParser

 htmls = `<p>TEXT</p><div>container</div><p></p><ul><li><b>list element</b>: 0.1 [mm]</li><li><strong>Another list element</strong>: 0.2</li></ul><span>span element</span>`;
let parser = new DOMParser();
let doc = parser.parseFromString(htmls, "text/html");
let span = doc.getElementsByTagName("span");
let sr = doc.getElementsByTagName("strong");
let elmarray = [...Array.from(span), ...Array.from(sr)];
elmarray.forEach((e) => {
 e.outerHTML = e.innerHTML;
});
  console.log(doc.body.innerHTML);

However if your html is simple you could use replace and a regular expression with caution

html =
"<p>TEXT</p><div>container</div><p></p><ul><li><b>list element</b>: 0.1 [mm]</li><li><strong>Another list element</strong>: 0.2</li></ul><span>span element</span>";
r = html.replace(/(<\/?span>|<\/?strong>)/g, "");
console.log(r);

The best/fastest way i can think of is, as suggested by Sven.hig, to create an html DOM from input string, parse it and take the outerHTML for all the tags that you want to keep and the innerHTML for the others.
Here is a code snippet that does exactly that:

    /* Input and Output strings */
    let input = "<p>TEXT</p><div>container</div><p></p><ul><li><b>list element</b>: 0.1 [mm]</li><li><strong>Another list element</strong>: 0.2</li></ul><span>span element</span>";
    let output = "";

    /* Array of the tagNames which you want to keep */
    let nonDeleatableTags = ["p", "li", "ul", "ol", "b"];

    /* We retrieve every html elements in the given input string */
    let allTagElements = Array.from(
                          new DOMParser()
                          .parseFromString(input, "text/html")
                          .getElementsByTagName("*")
                         ).filter(element => (element.tagName != "HTML" && element.tagName != "HEAD" && element.tagName != "BODY")); //The DOMParser will give us the <html>, <head> and <body> tags which we don't use
                        
    for(const element of allTagElements) {
      /* We want to avoid printing the same element twice if its a childNode */
      let alreadyInspected = false;
      for(const inspectedElement of allTagElements)
        if(element != inspectedElement && inspectedElement.contains(element))
          alreadyInspected = true;

      if(!alreadyInspected)
          output += (nonDeleatableTags.includes(element.tagName.toLowerCase())) ? element.outerHTML : element.innerHTML;      //The .toLowerCase can be omitted if you write the nonDeleatableTags elements with the upperCase
    }

    console.log(input);
    console.log(output);

If you want to keep other tags just add them to the nonDeleatableTags array and you're done !

Related