Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Pretty Print XML using Ruby (See related posts)

This code makes the XML output look pretty. I tried using the documentation from the REXML website to apply the method example doc.write($stdout,0), but I gave up, and instead wrote my own XML pretty-print method.

require 'rexml/document'
include REXML

  def pretty_print(parent_node, itab)
    buffer = ''

    parent_node.elements.each do |node|

      buffer += ' ' * itab + "<#{node.name}#{get_att_list(node)}"
  
      if node.to_a.length > 0
        buffer += ">"
        if node.text.nil?
          buffer += "\n"
          buffer += pretty_print(node,itab+2) 
          buffer += ' ' * itab + "</#{node.name}>\n"
        else
          node_text = node.text.strip
          if node_text != ''
            buffer += node_text 
            buffer += "</#{node.name}>\n"        
          else
            buffer += "\n" + pretty_print(node,itab+2) 
            buffer += ' ' * itab + "</#{node.name}>\n"        
          end
        end
      else
        buffer += "/>\n"
      end
      
    end
    buffer
  end

  def get_att_list(node)
    att_list = ''
    node.attributes.each { |attribute, val| att_list += " #{attribute}='#{val}'" }
    att_list
  end
  
  def pretty_xml(doc)
    buffer = ''
    xml_declaration = doc.to_s.match('<\?.*\?>').to_s
    buffer += "#{xml_declaration}\n" if not xml_declaration.nil?
    xml_doctype = doc.to_s.match('<\!.*\">').to_s
    buffer += "#{xml_doctype}\n" if not xml_doctype.nil?
    buffer += "<#{doc.root.name}#{get_att_list(doc.root)}"
    if doc.root.to_a.length > 0
      buffer +=">\n#{pretty_print(doc.root,2)}</#{doc.root.name}>"
    else
      buffer += "/>\n"
    end
  end

xml_data = "<hi id='124'><yo><a id='1'/><b/><c/></yo><sushi><love>Ruby</love></sushi></hi>"
doc = Document.new(xml_data)
pretty_xml(doc)


output
<hi id='124'>
  <yo>
    <a id='1'/>
    <b/>
    <c/>
  </yo>
  <sushi>
    <love>Ruby</love>
  </sushi>
</hi>


*Update 7-Jan-08 1:51AM *
Although I haven't tried running the following XSL code, this might actually have been a better solution to my problem. source: http://www.printk.net/~bds/indent.html

*Pretty Print XML using XSLT*
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="ISO-8859-1"/>
  <xsl:param name="indent-increment" select="'   '"/>
  
  <xsl:template name="newline">
    <xsl:text disable-output-escaping="yes">
</xsl:text>
  </xsl:template>
  
  <xsl:template match="comment() | processing-instruction()">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
    <xsl:copy />
  </xsl:template>
  
  <xsl:template match="text()">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
    <xsl:value-of select="normalize-space(.)"/>
  </xsl:template>
    
  <xsl:template match="text()[normalize-space(.)='']"/>
  
  <xsl:template match="*">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
      <xsl:choose>
       <xsl:when test="count(child::*) > 0">
        <xsl:copy>
         <xsl:copy-of select="@*"/>
         <xsl:apply-templates select="*|text()">
           <xsl:with-param name="indent" select="concat ($indent, $indent-increment)"/>
         </xsl:apply-templates>
         <xsl:call-template name="newline"/>
         <xsl:value-of select="$indent"/>
        </xsl:copy>
       </xsl:when>       
       <xsl:otherwise>
        <xsl:copy-of select="."/>
       </xsl:otherwise>
     </xsl:choose>
  </xsl:template>    
</xsl:stylesheet>

You need to create an account or log in to post comments to this site.


Click here to browse all 4861 code snippets

Related Posts