/tools/Ruby/lib/ruby/1.8/rexml/formatters/pretty.rb

http://github.com/agross/netopenspace · Ruby · 138 lines · 96 code · 14 blank · 28 comment · 14 complexity · 4a0141c793c512c829b519b132506664 MD5 · raw file

  1. require 'rexml/formatters/default'
  2. module REXML
  3. module Formatters
  4. # Pretty-prints an XML document. This destroys whitespace in text nodes
  5. # and will insert carriage returns and indentations.
  6. #
  7. # TODO: Add an option to print attributes on new lines
  8. class Pretty < Default
  9. # If compact is set to true, then the formatter will attempt to use as
  10. # little space as possible
  11. attr_accessor :compact
  12. # The width of a page. Used for formatting text
  13. attr_accessor :width
  14. # Create a new pretty printer.
  15. #
  16. # output::
  17. # An object implementing '<<(String)', to which the output will be written.
  18. # indentation::
  19. # An integer greater than 0. The indentation of each level will be
  20. # this number of spaces. If this is < 1, the behavior of this object
  21. # is undefined. Defaults to 2.
  22. # ie_hack::
  23. # If true, the printer will insert whitespace before closing empty
  24. # tags, thereby allowing Internet Explorer's feeble XML parser to
  25. # function. Defaults to false.
  26. def initialize( indentation=2, ie_hack=false )
  27. @indentation = indentation
  28. @level = 0
  29. @ie_hack = ie_hack
  30. @width = 80
  31. end
  32. protected
  33. def write_element(node, output)
  34. output << ' '*@level
  35. output << "<#{node.expanded_name}"
  36. node.attributes.each_attribute do |attr|
  37. output << " "
  38. attr.write( output )
  39. end unless node.attributes.empty?
  40. if node.children.empty?
  41. if @ie_hack
  42. output << " "
  43. end
  44. output << "/"
  45. else
  46. output << ">"
  47. # If compact and all children are text, and if the formatted output
  48. # is less than the specified width, then try to print everything on
  49. # one line
  50. skip = false
  51. if compact
  52. if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
  53. string = ""
  54. old_level = @level
  55. @level = 0
  56. node.children.each { |child| write( child, string ) }
  57. @level = old_level
  58. if string.length < @width
  59. output << string
  60. skip = true
  61. end
  62. end
  63. end
  64. unless skip
  65. output << "\n"
  66. @level += @indentation
  67. node.children.each { |child|
  68. next if child.kind_of?(Text) and child.to_s.strip.length == 0
  69. write( child, output )
  70. output << "\n"
  71. }
  72. @level -= @indentation
  73. output << ' '*@level
  74. end
  75. output << "</#{node.expanded_name}"
  76. end
  77. output << ">"
  78. end
  79. def write_text( node, output )
  80. s = node.to_s()
  81. s.gsub!(/\s/,' ')
  82. s.squeeze!(" ")
  83. s = wrap(s, 80-@level)
  84. s = indent_text(s, @level, " ", true)
  85. output << (' '*@level + s)
  86. end
  87. def write_comment( node, output)
  88. output << ' ' * @level
  89. super
  90. end
  91. def write_cdata( node, output)
  92. output << ' ' * @level
  93. super
  94. end
  95. def write_document( node, output )
  96. # Ok, this is a bit odd. All XML documents have an XML declaration,
  97. # but it may not write itself if the user didn't specifically add it,
  98. # either through the API or in the input document. If it doesn't write
  99. # itself, then we don't need a carriage return... which makes this
  100. # logic more complex.
  101. node.children.each { |child|
  102. next if child == node.children[-1] and child.instance_of?(Text)
  103. unless child == node.children[0] or child.instance_of?(Text) or
  104. (child == node.children[1] and !node.children[0].writethis)
  105. output << "\n"
  106. end
  107. write( child, output )
  108. }
  109. end
  110. private
  111. def indent_text(string, level=1, style="\t", indentfirstline=true)
  112. return string if level < 0
  113. string.gsub(/\n/, "\n#{style*level}")
  114. end
  115. def wrap(string, width)
  116. # Recursively wrap string at width.
  117. return string if string.length <= width
  118. place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
  119. return string if place.nil?
  120. return string[0,place] + "\n" + wrap(string[place+1..-1], width)
  121. end
  122. end
  123. end
  124. end