Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleting all tags of a certain type in emacs

Tags:

regex

emacs

xml

I've got an XML file. Just reading that, I can tell you're excited.

Now there's a few tags in it that I want to completely remove:

<qwerty option=1>
<nmo>sdfsdf</nmo>
<blue>sdfsdf</blue>
</qwerty>

This is a big file. How would I remove all of the tags nmo and blue, including their contents? In Emacs, or anything else my mac can use.

like image 790
cannyboy Avatar asked Dec 26 '22 08:12

cannyboy


2 Answers

Emacs has commands for navigating symbolic expressions, or "sexps". In xml-mode, the sexp navigation commands work on tags. You can navigate to the opening <, press C-M-f (forward-sexp) to navigate to the end of the tag, or press C-M-k (kill-sexp) to kill it. The variable nxml-sexp-element-flag controls whether you go the end of the opening tag (the default) or the end of the closing tag. I prefer the latter.

To remove those tags, first set nxml-sexp-element-flag with M-x customize-variable nxml-sexp-element-flag. Next, search for the tag you'd like to kill, move the point to the opening < and press C-M-k. Wrap this all up in a macro, and repeat over the entire file until the search fails.

like image 152
ataylor Avatar answered Dec 29 '22 12:12

ataylor


I assume your xml file is well formed. And I assume also that contrary to your example your "real-life" data is a little bit more complicated than one tag per line (except for the root one). Otherwise do we agree it would be as simple as removing lines containing a given tag?

Here is a proposition for a function that could do the trick:

(defun my-remove-tag (tag)
  (save-excursion
     (let ((case-fold-search nil))
       (while (search-forward-regexp (concat "<" tag "[^\\>]*>"))
     (delete-region
      (match-beginning 0)
      (search-forward (concat "</" tag ">")))))))

Calling this function you may look for nmo, blue or qwerty tags, as so:

(my-remove-tag "nmo")
(my-remove-tag "qwerty")

The rationale is looking for a opening tag then look for the closing one, and delete everything in the middle. Attributes for a tag could go in the middle of the way, and this function deal with opening tag containing attributes.

The case sensitiveness is disabled and restored once the function is done. Also the Emacs Point is restored with the usual macro : save-excusion.

Update

I removed the outer let. No need to restore the case-fold-search value by hand, the let binding simply shadows the global value, it is restored by by means of "unshadowing".

like image 34
yves Baumes Avatar answered Dec 29 '22 11:12

yves Baumes