Replacing DOM elements that have no attributes The institution I work for uses an application that has an awful software bug causing useless &lt;code&gt;span&lt;/code&gt; tags to appear next to "misspelled" words in iframes.

For instance, HTML that should look like this:

&lt;span class="myClass"&gt;Hello! My name is Tabitha.&lt;/span&gt;


...might look like this instead:

&lt;span class="myClass"&gt;Hello! My name is &lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Tabitha.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;


My band-aid solution, while we wait for a fix from the application developer, has been to add a script that finds all attribute-less span tags and replaces them with a new &lt;code&gt;textNode&lt;/code&gt;. This works because these extra tags are always the direct parent of the &lt;code&gt;textNode&lt;/code&gt; containing the misspelled word (or another extra span element). Any formatting or inline styling would occur outside that scope and would thus be unaffected.

But, something tells me there's got to be a better way to do it. Any thoughts?

function fixSpan(iframe) {        
    var doc = iframe.contentDocument;
    var spans = doc.getElementsByTagName('span'); //find all &lt;span&gt; elements
    for (var i = 0; i &lt; spans.length; i++) {
        var span = spans[i];            
        var tag = span.outerHTML.slice(0,6);
        if (tag === '&lt;span&gt;') { //if the span has no attributes
            //replace it with a new textNode containing its textContent
            console.log('FOUND: &lt;span&gt;' + span.textContent + '&lt;/span&gt;');
            span.parentNode.replaceChild(document.createTextNode(span.textContent), span);                
        }
    }

    if (doc.documentElement.innerHTML.includes('&lt;span&gt;')) {
        //if any attribute-less tags remain, run the method again
        console.log('Fix not complete, re-running...');
        fixSpan(iframe);
    } else {
        console.log('Fix complete.');
    }
}
Some thoughts about your code:

1) You work with the serialized form of the HTML, i.e. with innerHTML and outerHTML. In some (rare) occurrences, it may be acceptable to do so, but most of the time working with the provided API is cleaner. I don't think that the serialized representation is guaranteed to be the same across user agents (attribute ordering, legacy uppercasing of HTML...) - plus what if some inline script declares some '&lt;span&gt;' text... like yours?

2) Re-running the method is a bit dubious, you should be able to remove all spans in a single pass. In your case, the DOM collection is live, so each time you replace a span element, the current index must be shifted back. In itself, manually updating the index of a loop is a bad practice, but Javascript has limited iteration mechanisms, so you have to live with it. It's actually not that unusual in DOM manipulation.

3) Removing the spans without attributes is well and good, but even an empty span may be styled, as part of another selector (e.g. .foo &gt; span). Your fix may bring new problems.

4) Comments should not repeat the code, but bring enlightenment to the reader. Indicating "find all &lt;span&gt; elements" aside a getElementsByTagName is probably unneeded. Indicating why you shift a loop index, if you decide to do it, is necessary.

function fixSpan(doc) {
    var spans = doc.getElementsByTagName("span");
    for (var index = 0; index &lt; spans.length; index++) {
        var span = spans[index];
        if (span.attributes.length == 0) {
            span.parentNode.replaceChild(document.createTextNode(span.textContent), span);
            index--; // Tree is live; removing one span requires shifting the index.
        }
    }
}