39

Is there an easy way within vi to make your XML text "pretty"?

For example:

I want this..

            <person>
  <name>Nick</name>
 <age>26</age>
         <gender>male</gender>
<occupation>doctor</occupation>
    </person>

to be this...

<person>
    <name>Nick</name>
    <age>26</age>
    <gender>male</gender>
    <occupation>doctor</occupation>
</person>
Ulrich Dangel
  • 25,079
  • 3
  • 80
  • 80
Rob Avery IV
  • 3,075
  • 3
  • 17
  • 14

1 Answers1

49

I've had the most luck with this:

:%!xmllint --format %

It's strict about your tags, though, so it will error out if your opening and closing tags don't match. It also adds an XML declaration at the top of your file, if you don't have one as well.

This page recommends the following, although I can't get it to work:

:set filetype=xml
:filetype indent on
gg=G

I tested it out, and it seems to work, somewhat. Not perfectly, but it gets the job done.

If that doesn't work well, you could use minidom in Python to format it for you.

import xml.dom.minidom

xml = xml.dom.minidom.parse(filename)
formatted_xml = xml.toprettyxml()
Nate
  • 760
  • 1
  • 8
  • 9
  • That `gg=G` command didn't really work. Instead, it just removed all the previous indentations I had. – Rob Avery IV Jan 24 '13 at 20:10
  • Yeah, I've found the same thing. It seems to work when I have a specific type of formatting already, but usually not. I'll have to test it out a bit more. – Nate Jan 24 '13 at 20:14
  • 2
    `:%!xmllint --format %` seems to work well, so I've added that to the post. – Nate Jan 24 '13 at 20:20
  • Do you if you can set the tab indent size? For example: A parent's children will be 1 tab instead of 3 spaces, etc. – Rob Avery IV Jan 25 '13 at 13:40
  • @RobAveryIV you can set the indentation by setting the environment variable `XMLLINT_INDENT`. Default is two spaces, and you can set it to anything you want: `export XMLLINT_INDENT=" "` for four spaces, for example. See also [this answer](http://stackoverflow.com/a/10386006/2521769) on StackOverflow. – Stefan van den Akker Dec 15 '15 at 11:23
  • Only downside to `xmllint`: requires that the current buffer be saved as a filename first. – kenny Nov 08 '16 at 22:03
  • 1
    @kenny I modified the answer to cope with that – törzsmókus Aug 09 '17 at 15:10
  • 2
    I'm doing ":set ft=xml | %!xmllint --format -" to make it work on the current buffer and turn on syntax highlighting – grebulon Apr 26 '18 at 09:39
  • got an error, "E499: Empty file name for '%' or '#', only works with :p:h" – CCNA Jun 24 '22 at 00:38