0

Here is my code:

var str = `<p>paragraph<a>link</a></p>
           <div class="myclass">
               <div>something</div>
               <div style="mystyle">something</div>
               <b><a href="#">link</a></b>
               <b><a href="#" name="a name">link</a></b>
               <b style="color:red">bold</b>
               <img src="../path" alt="something" />
               <img src="../path" alt="something" class="myclass" />
           </div>`;
var div = document.createElement("div");
div.innerHTML=str;
div.querySelectorAll("*").forEach(function(el){
  for (var i = 0, atts = el.attributes, n = atts.length; i < n; i++){
    var att = atts[i].nodeName;
    if (["src","alt","href"].indexOf(att) ==-1) el.removeAttribute(att); 
  }
}); 
// console.log(div); alert shows it more clearly
alert(div.innerHTML);

It removes every attribute except src, alt, href. Now I want to remove the tag (not just the attribute) which contains any attribute except those three ones.

I've tested removeChild() instead of removeAttribute(), but it doesn't work as expected. Any idea?


An short example:

input:

<a href="#" class="sth">link</a>
<img src="#" />

expected output:

link
<img src="#" />

<a> should be removed, because of class attribute.

Martin AJ
  • 6,261
  • 8
  • 53
  • 111
  • 1
    jquery's unwrap? https://api.jquery.com/unwrap/ – Snowmonkey Jan 30 '17 at 15:33
  • @Snowmonkey Maybe. I will check it out. thank you – Martin AJ Jan 30 '17 at 15:35
  • 1
    Did you try removeChild on the div? It's `div.removeChild(el)`, not `el.removeChild()` ALso, if you update your querySelectorAll, you could select only all the elements containing one of those attributes and just remove all of them. – Shilly Jan 30 '17 at 15:37
  • @Shilly Why should I select *all the elements containing one of those attributes* ? – Martin AJ Jan 30 '17 at 15:37
  • @MartinAJ doesn't want to remove el's children, simply (from what I can see) to remove the el itself and keep the children in the tree structure. – Snowmonkey Jan 30 '17 at 15:38
  • must have all 3 or just remove if any other attributes exist? – charlietfl Jan 30 '17 at 15:38
  • @charlietfl *just remove if any other attributes exist.* – Martin AJ Jan 30 '17 at 15:38
  • To get the reverse of it obv, so you can just removeChild loop over them. – Shilly Jan 30 '17 at 15:39
  • If element has `src`, `alt`, `href`, remove tag? – guest271314 Jan 30 '17 at 15:41
  • @guest271314 all together, yes! but `src` + `alt`, no! – Martin AJ Jan 30 '17 at 15:42
  • 1
    @guest271314 by the way, a tag which has those three attributes, seems invalid to me! – Martin AJ Jan 30 '17 at 15:42
  • Could you clarify the exact rules when an element has to be removed, since it's getting confusing now. Also, removing the tag removes the innerHTML, so does that innerHTML have to be reinserted as text after the tag is removed? (As you show in your desired output.) – Shilly Jan 30 '17 at 15:44
  • 1
    If `alt` and `src` attributes but not `href` do not remove tag? Why would element have both `src` and `href` attributes at same element? – guest271314 Jan 30 '17 at 15:46
  • @guest271314 no,that's ok. Here is the idea: All tags should be removed if they have any attribute. Except the ones which have either `href` attribute or `src` attribute. noted that `alt` is also allowed if comes next to `src` attribute. that's it. cc @Shilly – Martin AJ Jan 30 '17 at 15:48
  • _"noted that `alt` is also allowed if comes next to `src` attribute."_ What should occur where both `alt` and `src` attributes are present? – guest271314 Jan 30 '17 at 15:52
  • @guest271314 all tags should be removed except these: 1. only `href` attribute. 2. only `src` attribute. 3. both `src` and `alt` attributes. 4. there isn't any attribute – Martin AJ Jan 30 '17 at 15:54

3 Answers3

2

var str = `<p>paragraph<a>link</a></p>
           <div class="myclass">
               <div>something</div>
               <div style="mystyle">something</div>
               <b><a href="#">link</a></b>
               <b><a href="#" name="a name">link</a></b>
               <b style="color:red">bold</b>
               <img src="../path" alt="something" />
               <img src="../path" alt="something" class="myclass" />
           </div>`;
var div = document.createElement("div");
div.innerHTML=str;
div.querySelectorAll("*").forEach(function(el){
  for (var i = 0, atts = el.attributes, n = atts.length; i < n; i++){
    var att = atts[i].nodeName;
    if (["src","alt","href"].indexOf(att) ==-1){
      var parent = el.parentElement;
      while(el.firstChild) parent.insertBefore(el.firstChild, el);
      parent.removeChild(el);
      break; // element is already removed, don't loop over attributes of a removed element.
    } 
  }
}); 
// console.log(div); alert shows it more clearly
alert(div.innerHTML);
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
  • You might want to add a `break` at the end of the `if` block so that the same element is not removed twice (which might lead to errors) – Hubert Grzeskowiak Jan 30 '17 at 15:50
  • 1
    @Editor you should understand what the code does before wrongly editing it. The code should move all the element inside `el` first then removes `el`. that's why the while doesn't have braces so it can have only one instruction inside it. – ibrahim mahrir Jan 30 '17 at 15:50
  • @ibrahimmahrir right. sorry about setting the braces wrongly :-S – Hubert Grzeskowiak Jan 30 '17 at 15:51
  • @HubertGrzeskowiak Plus it should be `break` not `continue` to terminate the `for` loop at once. – ibrahim mahrir Jan 30 '17 at 15:53
  • You'll have to slice the nodeList returned from querySelectorAll into an array before looping with forEach for slightly older browsers. Also note that this also removes the wrapper div with myClass, so watch out for your css and layout. But +1 otherwise. – Shilly Jan 30 '17 at 15:57
  • @Shilly the div with the style attribute is intended to be removed. Since it's not included in `["href", "src", "alt"]`. – ibrahim mahrir Jan 30 '17 at 15:59
  • Indeed. I'm mentioning it as a reminder for the OP that this operation might change the layout. – Shilly Jan 30 '17 at 16:02
  • @Shilly [Here](http://stackoverflow.com/questions/41923316/how-can-i-remove-all-tags-attributes-except-specific-ones) is the original question asked by him yesterday. In that question he wants just to remove the attributes (style included). Now instead of removing the attributes, he wants to remove the whole element. (:D I witnessed both questions that's why I'm familiar with his needs). – ibrahim mahrir Jan 30 '17 at 16:06
0

Try this method

div.removeChild(el)

Mauricio
  • 84
  • 1
  • 8
0

You can use .each(), .children(), .is(), .filter(), .replaceWith()

var str = `<p>paragraph<a>link</a></p>
           <div class="myclass">
               <div>something</div>
               <div style="mystyle">something</div>
               <b><a href="#">link</a></b>
               <b><a href="#" name="a name">link</a></b>
               <b style="color:red">bold</b>
               <img src="../path" alt="something" />
               <img src="../path" alt="something" class="myclass" />
           </div>`;
var div = document.createElement("div");
div.innerHTML = str;
$(div).children().each(function (_, el) {
    if (!$(">[src], >[href]", el).length) {      
      $(el).children().add(el).each(function(_, element) {
         $(element).replaceWith(element.textContent)
      });
    } else {
      $(el).children().each(function(_, elem) {
        if (!$(">[src], >[href]", elem).length 
            && !$(elem).is("[href], [src]")) {
          $(elem).replaceWith(elem.innerHTML);
        } else {
          if ($(">[href], >[src]", elem).length)
           $(elem).filter(function(_, element) {
             return !$(element).is("[href], [src]")
           }).replaceWith(elem.innerHTML);
        }
      });     
      if (!$(el).is("[href], [src]")) {
        $(el).replaceWith(el.innerHTML)
      }    
    }
  });
  // console.log(div); alert shows it more clearly
alert(div.innerHTML);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
guest271314
  • 1
  • 15
  • 104
  • 177