Search code examples
xmlxml-formatting

Is there a way to pretty print XML with vertical alignment?


I have a config file which has some XML like:

<Presidents>
  <President first="George" last="Washington" number="1" year="1789" />
  <President first="John" last="Adams" number="2" year="1797" />
</Presidents>

I would like to have a pretty printer vertically align my attributes so the file looks like:

<Presidents>
  <President first="George" last="Washington" number="1" year="1789" />
  <President first="John"   last="Adams"      number="2" year="1797" />
</Presidents>

This formatting style depends on having a list of elements with the same attributes, so it probably couldn't be applied generically to any xml document, however, it is a common style for config files. I've read the man pages for xmllint and xmlstarlet and I can't find any reference to a feature like this.


Solution

  • I created the following script to align the columns. I first pass my xml thought xmllint, and then through the following:

    #!/usr/bin/env ruby
    #
    # vertically aligns columns
    
    def print_buf(b)
      max_lengths={}
      max_lengths.default=0
    
      b.each do |line|
        for i in (0..line.size() - 1)
          d = line[i]
          s = d.size()
          if s > max_lengths[i] then
            max_lengths[i] = s
          end
        end
      end
    
      b.each do |line|
        for i in (0..line.size() - 1)
          print line[i], ' ' * (max_lengths[i] - line[i].size())
        end
      end
    
    end
    
    cols=0
    buf=[]
    
    ARGF.each do |line|
      columns=line.split(/( |\r\n|\n|\r)(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/m)
      if columns.size != cols then
        print_buf(buf) if !buf.empty?
        buf=[]
      end
      buf << columns
      cols = columns.size
    end
    
    print_buf(buf)