rubysl-rexml 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/lib/rexml/attlistdecl.rb +62 -0
  9. data/lib/rexml/attribute.rb +185 -0
  10. data/lib/rexml/cdata.rb +67 -0
  11. data/lib/rexml/child.rb +96 -0
  12. data/lib/rexml/comment.rb +80 -0
  13. data/lib/rexml/doctype.rb +271 -0
  14. data/lib/rexml/document.rb +230 -0
  15. data/lib/rexml/dtd/attlistdecl.rb +10 -0
  16. data/lib/rexml/dtd/dtd.rb +51 -0
  17. data/lib/rexml/dtd/elementdecl.rb +17 -0
  18. data/lib/rexml/dtd/entitydecl.rb +56 -0
  19. data/lib/rexml/dtd/notationdecl.rb +39 -0
  20. data/lib/rexml/element.rb +1227 -0
  21. data/lib/rexml/encoding.rb +71 -0
  22. data/lib/rexml/encodings/CP-1252.rb +103 -0
  23. data/lib/rexml/encodings/EUC-JP.rb +35 -0
  24. data/lib/rexml/encodings/ICONV.rb +22 -0
  25. data/lib/rexml/encodings/ISO-8859-1.rb +7 -0
  26. data/lib/rexml/encodings/ISO-8859-15.rb +72 -0
  27. data/lib/rexml/encodings/SHIFT-JIS.rb +37 -0
  28. data/lib/rexml/encodings/SHIFT_JIS.rb +1 -0
  29. data/lib/rexml/encodings/UNILE.rb +34 -0
  30. data/lib/rexml/encodings/US-ASCII.rb +30 -0
  31. data/lib/rexml/encodings/UTF-16.rb +35 -0
  32. data/lib/rexml/encodings/UTF-8.rb +18 -0
  33. data/lib/rexml/entity.rb +166 -0
  34. data/lib/rexml/formatters/default.rb +109 -0
  35. data/lib/rexml/formatters/pretty.rb +138 -0
  36. data/lib/rexml/formatters/transitive.rb +56 -0
  37. data/lib/rexml/functions.rb +382 -0
  38. data/lib/rexml/instruction.rb +70 -0
  39. data/lib/rexml/light/node.rb +196 -0
  40. data/lib/rexml/namespace.rb +47 -0
  41. data/lib/rexml/node.rb +75 -0
  42. data/lib/rexml/output.rb +24 -0
  43. data/lib/rexml/parent.rb +166 -0
  44. data/lib/rexml/parseexception.rb +51 -0
  45. data/lib/rexml/parsers/baseparser.rb +503 -0
  46. data/lib/rexml/parsers/lightparser.rb +60 -0
  47. data/lib/rexml/parsers/pullparser.rb +196 -0
  48. data/lib/rexml/parsers/sax2parser.rb +238 -0
  49. data/lib/rexml/parsers/streamparser.rb +46 -0
  50. data/lib/rexml/parsers/treeparser.rb +97 -0
  51. data/lib/rexml/parsers/ultralightparser.rb +56 -0
  52. data/lib/rexml/parsers/xpathparser.rb +698 -0
  53. data/lib/rexml/quickpath.rb +266 -0
  54. data/lib/rexml/rexml.rb +32 -0
  55. data/lib/rexml/sax2listener.rb +97 -0
  56. data/lib/rexml/source.rb +251 -0
  57. data/lib/rexml/streamlistener.rb +92 -0
  58. data/lib/rexml/syncenumerator.rb +33 -0
  59. data/lib/rexml/text.rb +344 -0
  60. data/lib/rexml/undefinednamespaceexception.rb +8 -0
  61. data/lib/rexml/validation/relaxng.rb +559 -0
  62. data/lib/rexml/validation/validation.rb +155 -0
  63. data/lib/rexml/validation/validationexception.rb +9 -0
  64. data/lib/rexml/xmldecl.rb +119 -0
  65. data/lib/rexml/xmltokens.rb +18 -0
  66. data/lib/rexml/xpath.rb +66 -0
  67. data/lib/rexml/xpath_parser.rb +792 -0
  68. data/lib/rubysl/rexml.rb +1 -0
  69. data/lib/rubysl/rexml/version.rb +5 -0
  70. data/rubysl-rexml.gemspec +23 -0
  71. data/spec/attribute/clone_spec.rb +10 -0
  72. data/spec/attribute/element_spec.rb +22 -0
  73. data/spec/attribute/equal_value_spec.rb +17 -0
  74. data/spec/attribute/hash_spec.rb +12 -0
  75. data/spec/attribute/initialize_spec.rb +28 -0
  76. data/spec/attribute/inspect_spec.rb +19 -0
  77. data/spec/attribute/namespace_spec.rb +23 -0
  78. data/spec/attribute/node_type_spec.rb +9 -0
  79. data/spec/attribute/prefix_spec.rb +17 -0
  80. data/spec/attribute/remove_spec.rb +19 -0
  81. data/spec/attribute/to_s_spec.rb +13 -0
  82. data/spec/attribute/to_string_spec.rb +14 -0
  83. data/spec/attribute/value_spec.rb +14 -0
  84. data/spec/attribute/write_spec.rb +22 -0
  85. data/spec/attribute/xpath_spec.rb +19 -0
  86. data/spec/attributes/add_spec.rb +6 -0
  87. data/spec/attributes/append_spec.rb +6 -0
  88. data/spec/attributes/delete_all_spec.rb +30 -0
  89. data/spec/attributes/delete_spec.rb +26 -0
  90. data/spec/attributes/each_attribute_spec.rb +24 -0
  91. data/spec/attributes/each_spec.rb +24 -0
  92. data/spec/attributes/element_reference_spec.rb +18 -0
  93. data/spec/attributes/element_set_spec.rb +25 -0
  94. data/spec/attributes/get_attribute_ns_spec.rb +13 -0
  95. data/spec/attributes/get_attribute_spec.rb +28 -0
  96. data/spec/attributes/initialize_spec.rb +18 -0
  97. data/spec/attributes/length_spec.rb +6 -0
  98. data/spec/attributes/namespaces_spec.rb +5 -0
  99. data/spec/attributes/prefixes_spec.rb +23 -0
  100. data/spec/attributes/shared/add.rb +17 -0
  101. data/spec/attributes/shared/length.rb +12 -0
  102. data/spec/attributes/size_spec.rb +6 -0
  103. data/spec/attributes/to_a_spec.rb +20 -0
  104. data/spec/cdata/clone_spec.rb +9 -0
  105. data/spec/cdata/initialize_spec.rb +24 -0
  106. data/spec/cdata/shared/to_s.rb +11 -0
  107. data/spec/cdata/to_s_spec.rb +6 -0
  108. data/spec/cdata/value_spec.rb +6 -0
  109. data/spec/document/add_element_spec.rb +30 -0
  110. data/spec/document/add_spec.rb +60 -0
  111. data/spec/document/clone_spec.rb +19 -0
  112. data/spec/document/doctype_spec.rb +14 -0
  113. data/spec/document/encoding_spec.rb +21 -0
  114. data/spec/document/expanded_name_spec.rb +15 -0
  115. data/spec/document/new_spec.rb +37 -0
  116. data/spec/document/node_type_spec.rb +7 -0
  117. data/spec/document/root_spec.rb +11 -0
  118. data/spec/document/stand_alone_spec.rb +18 -0
  119. data/spec/document/version_spec.rb +13 -0
  120. data/spec/document/write_spec.rb +38 -0
  121. data/spec/document/xml_decl_spec.rb +14 -0
  122. data/spec/element/add_attribute_spec.rb +40 -0
  123. data/spec/element/add_attributes_spec.rb +21 -0
  124. data/spec/element/add_element_spec.rb +38 -0
  125. data/spec/element/add_namespace_spec.rb +23 -0
  126. data/spec/element/add_text_spec.rb +23 -0
  127. data/spec/element/attribute_spec.rb +16 -0
  128. data/spec/element/attributes_spec.rb +18 -0
  129. data/spec/element/cdatas_spec.rb +23 -0
  130. data/spec/element/clone_spec.rb +28 -0
  131. data/spec/element/comments_spec.rb +20 -0
  132. data/spec/element/delete_attribute_spec.rb +38 -0
  133. data/spec/element/delete_element_spec.rb +50 -0
  134. data/spec/element/delete_namespace_spec.rb +24 -0
  135. data/spec/element/document_spec.rb +17 -0
  136. data/spec/element/each_element_with_attribute_spec.rb +34 -0
  137. data/spec/element/each_element_with_text_spec.rb +30 -0
  138. data/spec/element/get_text_spec.rb +17 -0
  139. data/spec/element/has_attributes_spec.rb +16 -0
  140. data/spec/element/has_elements_spec.rb +17 -0
  141. data/spec/element/has_text_spec.rb +15 -0
  142. data/spec/element/inspect_spec.rb +26 -0
  143. data/spec/element/instructions_spec.rb +20 -0
  144. data/spec/element/namespace_spec.rb +26 -0
  145. data/spec/element/namespaces_spec.rb +31 -0
  146. data/spec/element/new_spec.rb +34 -0
  147. data/spec/element/next_element_spec.rb +18 -0
  148. data/spec/element/node_type_spec.rb +7 -0
  149. data/spec/element/prefixes_spec.rb +22 -0
  150. data/spec/element/previous_element_spec.rb +19 -0
  151. data/spec/element/raw_spec.rb +23 -0
  152. data/spec/element/root_spec.rb +27 -0
  153. data/spec/element/text_spec.rb +45 -0
  154. data/spec/element/texts_spec.rb +15 -0
  155. data/spec/element/whitespace_spec.rb +22 -0
  156. data/spec/node/each_recursive_spec.rb +20 -0
  157. data/spec/node/find_first_recursive_spec.rb +24 -0
  158. data/spec/node/index_in_parent_spec.rb +14 -0
  159. data/spec/node/next_sibling_node_spec.rb +20 -0
  160. data/spec/node/parent_spec.rb +20 -0
  161. data/spec/node/previous_sibling_node_spec.rb +20 -0
  162. data/spec/shared/each_element.rb +35 -0
  163. data/spec/shared/elements_to_a.rb +35 -0
  164. data/spec/text/append_spec.rb +9 -0
  165. data/spec/text/clone_spec.rb +9 -0
  166. data/spec/text/comparison_spec.rb +24 -0
  167. data/spec/text/empty_spec.rb +11 -0
  168. data/spec/text/indent_text_spec.rb +23 -0
  169. data/spec/text/inspect_spec.rb +7 -0
  170. data/spec/text/new_spec.rb +48 -0
  171. data/spec/text/node_type_spec.rb +7 -0
  172. data/spec/text/normalize_spec.rb +7 -0
  173. data/spec/text/read_with_substitution_spec.rb +12 -0
  174. data/spec/text/to_s_spec.rb +17 -0
  175. data/spec/text/unnormalize_spec.rb +7 -0
  176. data/spec/text/value_spec.rb +36 -0
  177. data/spec/text/wrap_spec.rb +20 -0
  178. data/spec/text/write_with_substitution_spec.rb +32 -0
  179. metadata +385 -0
@@ -0,0 +1,18 @@
1
+ module REXML
2
+ module Encoding
3
+ def encode_utf8 content
4
+ content
5
+ end
6
+
7
+ def decode_utf8(str)
8
+ str
9
+ end
10
+
11
+ register(UTF_8) do |obj|
12
+ class << obj
13
+ alias decode decode_utf8
14
+ alias encode encode_utf8
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,166 @@
1
+ require 'rexml/child'
2
+ require 'rexml/source'
3
+ require 'rexml/xmltokens'
4
+
5
+ module REXML
6
+ # God, I hate DTDs. I really do. Why this idiot standard still
7
+ # plagues us is beyond me.
8
+ class Entity < Child
9
+ include XMLTokens
10
+ PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#"
11
+ SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))}
12
+ PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')}
13
+ EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
14
+ NDATADECL = "\\s+NDATA\\s+#{NAME}"
15
+ PEREFERENCE = "%#{NAME};"
16
+ ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
17
+ PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
18
+ ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
19
+ PEDECL = "<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
20
+ GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
21
+ ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
22
+
23
+ attr_reader :name, :external, :ref, :ndata, :pubid
24
+
25
+ # Create a new entity. Simple entities can be constructed by passing a
26
+ # name, value to the constructor; this creates a generic, plain entity
27
+ # reference. For anything more complicated, you have to pass a Source to
28
+ # the constructor with the entity definiton, or use the accessor methods.
29
+ # +WARNING+: There is no validation of entity state except when the entity
30
+ # is read from a stream. If you start poking around with the accessors,
31
+ # you can easily create a non-conformant Entity. The best thing to do is
32
+ # dump the stupid DTDs and use XMLSchema instead.
33
+ #
34
+ # e = Entity.new( 'amp', '&' )
35
+ def initialize stream, value=nil, parent=nil, reference=false
36
+ super(parent)
37
+ @ndata = @pubid = @value = @external = nil
38
+ if stream.kind_of? Array
39
+ @name = stream[1]
40
+ if stream[-1] == '%'
41
+ @reference = true
42
+ stream.pop
43
+ else
44
+ @reference = false
45
+ end
46
+ if stream[2] =~ /SYSTEM|PUBLIC/
47
+ @external = stream[2]
48
+ if @external == 'SYSTEM'
49
+ @ref = stream[3]
50
+ @ndata = stream[4] if stream.size == 5
51
+ else
52
+ @pubid = stream[3]
53
+ @ref = stream[4]
54
+ end
55
+ else
56
+ @value = stream[2]
57
+ end
58
+ else
59
+ @reference = reference
60
+ @external = nil
61
+ @name = stream
62
+ @value = value
63
+ end
64
+ end
65
+
66
+ # Evaluates whether the given string matchs an entity definition,
67
+ # returning true if so, and false otherwise.
68
+ def Entity::matches? string
69
+ (ENTITYDECL =~ string) == 0
70
+ end
71
+
72
+ # Evaluates to the unnormalized value of this entity; that is, replacing
73
+ # all entities -- both %ent; and &ent; entities. This differs from
74
+ # +value()+ in that +value+ only replaces %ent; entities.
75
+ def unnormalized
76
+ document.record_entity_expansion unless document.nil?
77
+ v = value()
78
+ return nil if v.nil?
79
+ @unnormalized = Text::unnormalize(v, parent)
80
+ @unnormalized
81
+ end
82
+
83
+ #once :unnormalized
84
+
85
+ # Returns the value of this entity unprocessed -- raw. This is the
86
+ # normalized value; that is, with all %ent; and &ent; entities intact
87
+ def normalized
88
+ @value
89
+ end
90
+
91
+ # Write out a fully formed, correct entity definition (assuming the Entity
92
+ # object itself is valid.)
93
+ #
94
+ # out::
95
+ # An object implementing <TT>&lt;&lt;<TT> to which the entity will be
96
+ # output
97
+ # indent::
98
+ # *DEPRECATED* and ignored
99
+ def write out, indent=-1
100
+ out << '<!ENTITY '
101
+ out << '% ' if @reference
102
+ out << @name
103
+ out << ' '
104
+ if @external
105
+ out << @external << ' '
106
+ if @pubid
107
+ q = @pubid.include?('"')?"'":'"'
108
+ out << q << @pubid << q << ' '
109
+ end
110
+ q = @ref.include?('"')?"'":'"'
111
+ out << q << @ref << q
112
+ out << ' NDATA ' << @ndata if @ndata
113
+ else
114
+ q = @value.include?('"')?"'":'"'
115
+ out << q << @value << q
116
+ end
117
+ out << '>'
118
+ end
119
+
120
+ # Returns this entity as a string. See write().
121
+ def to_s
122
+ rv = ''
123
+ write rv
124
+ rv
125
+ end
126
+
127
+ PEREFERENCE_RE = /#{PEREFERENCE}/um
128
+ # Returns the value of this entity. At the moment, only internal entities
129
+ # are processed. If the value contains internal references (IE,
130
+ # %blah;), those are replaced with their values. IE, if the doctype
131
+ # contains:
132
+ # <!ENTITY % foo "bar">
133
+ # <!ENTITY yada "nanoo %foo; nanoo>
134
+ # then:
135
+ # doctype.entity('yada').value #-> "nanoo bar nanoo"
136
+ def value
137
+ if @value
138
+ matches = @value.scan(PEREFERENCE_RE)
139
+ rv = @value.clone
140
+ if @parent
141
+ matches.each do |entity_reference|
142
+ entity_value = @parent.entity( entity_reference[0] )
143
+ rv.gsub!( /%#{entity_reference};/um, entity_value )
144
+ end
145
+ end
146
+ return rv
147
+ end
148
+ nil
149
+ end
150
+ end
151
+
152
+ # This is a set of entity constants -- the ones defined in the XML
153
+ # specification. These are +gt+, +lt+, +amp+, +quot+ and +apos+.
154
+ module EntityConst
155
+ # +>+
156
+ GT = Entity.new( 'gt', '>' )
157
+ # +<+
158
+ LT = Entity.new( 'lt', '<' )
159
+ # +&+
160
+ AMP = Entity.new( 'amp', '&' )
161
+ # +"+
162
+ QUOT = Entity.new( 'quot', '"' )
163
+ # +'+
164
+ APOS = Entity.new( 'apos', "'" )
165
+ end
166
+ end
@@ -0,0 +1,109 @@
1
+ module REXML
2
+ module Formatters
3
+ class Default
4
+ # Prints out the XML document with no formatting -- except if id_hack is
5
+ # set.
6
+ #
7
+ # ie_hack::
8
+ # If set to true, then inserts whitespace before the close of an empty
9
+ # tag, so that IE's bad XML parser doesn't choke.
10
+ def initialize( ie_hack=false )
11
+ @ie_hack = ie_hack
12
+ end
13
+
14
+ # Writes the node to some output.
15
+ #
16
+ # node::
17
+ # The node to write
18
+ # output::
19
+ # A class implementing <TT>&lt;&lt;</TT>. Pass in an Output object to
20
+ # change the output encoding.
21
+ def write( node, output )
22
+ case node
23
+
24
+ when Document
25
+ if node.xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
26
+ output = Output.new( output, node.xml_decl.encoding )
27
+ end
28
+ write_document( node, output )
29
+
30
+ when Element
31
+ write_element( node, output )
32
+
33
+ when Declaration, ElementDecl, NotationDecl, ExternalEntity, Entity,
34
+ Attribute, AttlistDecl
35
+ node.write( output,-1 )
36
+
37
+ when Instruction
38
+ write_instruction( node, output )
39
+
40
+ when DocType, XMLDecl
41
+ node.write( output )
42
+
43
+ when Comment
44
+ write_comment( node, output )
45
+
46
+ when CData
47
+ write_cdata( node, output )
48
+
49
+ when Text
50
+ write_text( node, output )
51
+
52
+ else
53
+ raise Exception.new("XML FORMATTING ERROR")
54
+
55
+ end
56
+ end
57
+
58
+ protected
59
+ def write_document( node, output )
60
+ node.children.each { |child| write( child, output ) }
61
+ end
62
+
63
+ def write_element( node, output )
64
+ output << "<#{node.expanded_name}"
65
+
66
+ node.attributes.each_attribute do |attr|
67
+ output << " "
68
+ attr.write( output )
69
+ end unless node.attributes.empty?
70
+
71
+ if node.children.empty?
72
+ output << " " if @ie_hack
73
+ output << "/"
74
+ else
75
+ output << ">"
76
+ node.children.each { |child|
77
+ write( child, output )
78
+ }
79
+ output << "</#{node.expanded_name}"
80
+ end
81
+ output << ">"
82
+ end
83
+
84
+ def write_text( node, output )
85
+ output << node.to_s()
86
+ end
87
+
88
+ def write_comment( node, output )
89
+ output << Comment::START
90
+ output << node.to_s
91
+ output << Comment::STOP
92
+ end
93
+
94
+ def write_cdata( node, output )
95
+ output << CData::START
96
+ output << node.to_s
97
+ output << CData::STOP
98
+ end
99
+
100
+ def write_instruction( node, output )
101
+ output << Instruction::START.sub(/\\/u, '')
102
+ output << node.target
103
+ output << ' '
104
+ output << node.content
105
+ output << Instruction::STOP.sub(/\\/u, '')
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,138 @@
1
+ require 'rexml/formatters/default'
2
+
3
+ module REXML
4
+ module Formatters
5
+ # Pretty-prints an XML document. This destroys whitespace in text nodes
6
+ # and will insert carriage returns and indentations.
7
+ #
8
+ # TODO: Add an option to print attributes on new lines
9
+ class Pretty < Default
10
+
11
+ # If compact is set to true, then the formatter will attempt to use as
12
+ # little space as possible
13
+ attr_accessor :compact
14
+ # The width of a page. Used for formatting text
15
+ attr_accessor :width
16
+
17
+ # Create a new pretty printer.
18
+ #
19
+ # output::
20
+ # An object implementing '<<(String)', to which the output will be written.
21
+ # indentation::
22
+ # An integer greater than 0. The indentation of each level will be
23
+ # this number of spaces. If this is < 1, the behavior of this object
24
+ # is undefined. Defaults to 2.
25
+ # ie_hack::
26
+ # If true, the printer will insert whitespace before closing empty
27
+ # tags, thereby allowing Internet Explorer's feeble XML parser to
28
+ # function. Defaults to false.
29
+ def initialize( indentation=2, ie_hack=false )
30
+ @indentation = indentation
31
+ @level = 0
32
+ @ie_hack = ie_hack
33
+ @width = 80
34
+ end
35
+
36
+ protected
37
+ def write_element(node, output)
38
+ output << ' '*@level
39
+ output << "<#{node.expanded_name}"
40
+
41
+ node.attributes.each_attribute do |attr|
42
+ output << " "
43
+ attr.write( output )
44
+ end unless node.attributes.empty?
45
+
46
+ if node.children.empty?
47
+ if @ie_hack
48
+ output << " "
49
+ end
50
+ output << "/"
51
+ else
52
+ output << ">"
53
+ # If compact and all children are text, and if the formatted output
54
+ # is less than the specified width, then try to print everything on
55
+ # one line
56
+ skip = false
57
+ if compact
58
+ if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
59
+ string = ""
60
+ old_level = @level
61
+ @level = 0
62
+ node.children.each { |child| write( child, string ) }
63
+ @level = old_level
64
+ if string.length < @width
65
+ output << string
66
+ skip = true
67
+ end
68
+ end
69
+ end
70
+ unless skip
71
+ output << "\n"
72
+ @level += @indentation
73
+ node.children.each { |child|
74
+ next if child.kind_of?(Text) and child.to_s.strip.length == 0
75
+ write( child, output )
76
+ output << "\n"
77
+ }
78
+ @level -= @indentation
79
+ output << ' '*@level
80
+ end
81
+ output << "</#{node.expanded_name}"
82
+ end
83
+ output << ">"
84
+ end
85
+
86
+ def write_text( node, output )
87
+ s = node.to_s()
88
+ s.gsub!(/\s/,' ')
89
+ s.squeeze!(" ")
90
+ s = wrap(s, 80-@level)
91
+ s = indent_text(s, @level, " ", true)
92
+ output << (' '*@level + s)
93
+ end
94
+
95
+ def write_comment( node, output)
96
+ output << ' ' * @level
97
+ super
98
+ end
99
+
100
+ def write_cdata( node, output)
101
+ output << ' ' * @level
102
+ super
103
+ end
104
+
105
+ def write_document( node, output )
106
+ # Ok, this is a bit odd. All XML documents have an XML declaration,
107
+ # but it may not write itself if the user didn't specifically add it,
108
+ # either through the API or in the input document. If it doesn't write
109
+ # itself, then we don't need a carriage return... which makes this
110
+ # logic more complex.
111
+ node.children.each { |child|
112
+ next if child == node.children[-1] and child.instance_of?(Text)
113
+ unless child == node.children[0] or child.instance_of?(Text) or
114
+ (child == node.children[1] and !node.children[0].writethis)
115
+ output << "\n"
116
+ end
117
+ write( child, output )
118
+ }
119
+ end
120
+
121
+ private
122
+ def indent_text(string, level=1, style="\t", indentfirstline=true)
123
+ return string if level < 0
124
+ string.gsub(/\n/, "\n#{style*level}")
125
+ end
126
+
127
+ def wrap(string, width)
128
+ # Recursively wrap string at width.
129
+ return string if string.length <= width
130
+ place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
131
+ return string if place.nil?
132
+ return string[0,place] + "\n" + wrap(string[place+1..-1], width)
133
+ end
134
+
135
+ end
136
+ end
137
+ end
138
+
@@ -0,0 +1,56 @@
1
+ require 'rexml/formatters/pretty'
2
+
3
+ module REXML
4
+ module Formatters
5
+ # The Transitive formatter writes an XML document that parses to an
6
+ # identical document as the source document. This means that no extra
7
+ # whitespace nodes are inserted, and whitespace within text nodes is
8
+ # preserved. Within these constraints, the document is pretty-printed,
9
+ # with whitespace inserted into the metadata to introduce formatting.
10
+ #
11
+ # Note that this is only useful if the original XML is not already
12
+ # formatted. Since this formatter does not alter whitespace nodes, the
13
+ # results of formatting already formatted XML will be odd.
14
+ class Transitive < Default
15
+ def initialize( indentation=2 )
16
+ @indentation = indentation
17
+ @level = 0
18
+ end
19
+
20
+ protected
21
+ def write_element( node, output )
22
+ output << "<#{node.expanded_name}"
23
+
24
+ node.attributes.each_attribute do |attr|
25
+ output << " "
26
+ attr.write( output )
27
+ end unless node.attributes.empty?
28
+
29
+ output << "\n"
30
+ output << ' '*@level
31
+ if node.children.empty?
32
+ output << "/"
33
+ else
34
+ output << ">"
35
+ # If compact and all children are text, and if the formatted output
36
+ # is less than the specified width, then try to print everything on
37
+ # one line
38
+ skip = false
39
+ @level += @indentation
40
+ node.children.each { |child|
41
+ write( child, output )
42
+ }
43
+ @level -= @indentation
44
+ output << "</#{node.expanded_name}"
45
+ output << "\n"
46
+ output << ' '*@level
47
+ end
48
+ output << ">"
49
+ end
50
+
51
+ def write_text( node, output )
52
+ output << node.to_s()
53
+ end
54
+ end
55
+ end
56
+ end