Vim as XML Editor: ed

And now for something completely different, just for the fun of it :)

Let's explore the ways of Vim's grand-grandfather, the standard Unix editor ed.

Why ed?

Working with ed is like walking in the dark. Although you do have a flashlight, going by train or car would be much more convenient.

But for certain tasks this ancient editor still is useful, for example when you want to show the editing steps to someone (every command is visible on the screen), or apply them automatically.

Basics

We'll use GNU ed, which might be on your system already if you're on Linux.
$ ed --version
GNU ed version 0.2
Let's try to create a tiny XML file:
$ ed -p '§ '
§ <fruits>
?
§ h
Unknown command
§ q
$
The ? shows that there was an error, and command h caused ed to print the error message. q stands for quit.
Just like Vim, ed has modes. When started it's in command mode. Input commands such as a (append) or i (insert) make ed switch to input mode. So let's try it again:
$ ed -p '§ '
§ a
<fruits>
  <fruit name="Mango"/>
  <fruit name="Rsapberry"/>
</fruits>
.
§ w fruits.xml
71
§ q
$
The dot causes ed to switch back to command mode (it only has two). -p '§ ' sets the prompt which indicates command mode. w and q are familiar from Vim.

Let's Go

I misspelled the name of the second fruit. I could have deleted the rest of the line (with [backspace]) then complete it correctly (the arrow keys don't work, at least here), but I already had entered that line (pressed [enter]). There are various ways to correct it. We could change the whole line with c
$ ed -p '§ ' fruits.xml
71
§ 3c
  <fruit name="Raspberry"/>
.
§ wq
71
$ tee < fruits.xml
<fruits>
  <fruit name="Mango"/>
  <fruit name="Raspberry"/>
</fruits>
$
or we could substitute the erratic string:
$ ed -p '§ ' fruits.xml
71
§ 3s/Rsap/Rasp/p
  <fruit name="Raspberry"/>
After the substitution command the changed line becomes the current line. The p after the substitution prints the new version of the line, and %p would have printed whole document.
Now let's add some attributes to each fruit element. We can walk through them with the G/regex/ command:
§ G/<fruit /
  <fruit name="Mango"/>
s/fruit /&latin-name="Mangifera Indica" /p
  <fruit latin-name="Mangifera Indica" name="Mango"/>
  <fruit name="Raspberry"/>
s/fruit /&latin-name="Rubus Idaeus" /p
  <fruit latin-name="Rubus Idaeus" name="Raspberry"/>
Let's double the indent:
§ g/^ /s/ \+/&&/
§ %p
<fruits>
    <fruit latin-name="Mangifera Indica" name="Mango"/>
    <fruit latin-name="Rubus Idaeus" name="Raspberry"/>
</fruits>

Pretty printing

... can be done like shown in the following example, and makes it easier to enter many elements:
$ ed -p '§ '
§ a
<a><b ><c /> </b></a>
.
§ w pp.xml
22
§ e !xmllint --format %
xmllint --format pp.xml
53
§ %n
1       <?xml version="1.0"?>
2       <a>
3         <b>
4           <c/>
5         </b>
6       </a>
§ 4a
<d><e><f/></e></d>
.
§ w
72
§ e !xmllint --format %
xmllint --format pp.xml
104
§ %p
<?xml version="1.0"?>
<a>
  <b>
    <c/>
    <d>
      <e>
        <f/>
      </e>
    </d>
  </b>
</a>
§ wq
104
$

More

Ed offers a lot more, check man ed.