XML prettifier in Haskell

I don’t know how many times I’ve gone looking for one of these but my search-fu is weak and I always give up, instead resorting to manual editing in Vim (no I hardly ever need the entire file to be pretty, only one or two tags that I’m interested in). Anyway, here’s a quick hack in Haskell, relying on xml for the heavy lifting:

#! /usr/bin/env runhaskell

module Main where

import Control.Monad
import System.Environment
import Text.XML.Light.Input
import Text.XML.Light.Output

main = do
    fn <- liftM (!! 0) $ getArgs
    xml_contents <- readFile fn
    let (Just doc) = parseXMLDoc xml_contents
    writeFile ("pretty-" ++ fn) (ppTopElement doc)

Ram?nas Gutkovas

There is an utility command “xmllint” which comes with “libxml2-utils” package on Ubuntu.

xmllint --format cluttered.xml > prettified.xml

ephemient

As cool as that is, what about Vim’s “gg=G”? It sometimes gets confused by what the proper indentation should be around comments, but aside from that, it’s pretty good.

Magnus

@Gutkovas, what’s the fun in that? Kidding aside, I didn’t know xmllint did that, thanks for pointing it out.

@ephemient, yes, that’s what I’ve often done, but as you point out, it’s not always reliable.

endrew

I’m really just a noob, but what’s the point of using (!! 0) instead of head?

David

For your first line in main, I recommend:

main = do
  [fn] <- getArgs
  ...

Magnus

@endrew & David, every time I use getArgs I forget it doesn’t include argv[0] so I always start out with liftM (!! 1) and when reminded (through a run-time exception) I put in the zero. Of course I could always us (_:fn), but pattern matching in do (or let) still doesn’t come naturally for me. :-)

Andreas Krey

And, of course, you technically can’t pretty-print XML, because all the whitespace is significant. Except for within the tags.

endrew

Aha! I knew there was something to it :)

Leave a comment