rubysl-rexml 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,80 @@
1
+ require "rexml/child"
2
+
3
+ module REXML
4
+ ##
5
+ # Represents an XML comment; that is, text between \<!-- ... -->
6
+ class Comment < Child
7
+ include Comparable
8
+ START = "<!--"
9
+ STOP = "-->"
10
+
11
+ # The content text
12
+
13
+ attr_accessor :string
14
+
15
+ ##
16
+ # Constructor. The first argument can be one of three types:
17
+ # @param first If String, the contents of this comment are set to the
18
+ # argument. If Comment, the argument is duplicated. If
19
+ # Source, the argument is scanned for a comment.
20
+ # @param second If the first argument is a Source, this argument
21
+ # should be nil, not supplied, or a Parent to be set as the parent
22
+ # of this object
23
+ def initialize( first, second = nil )
24
+ #puts "IN COMMENT CONSTRUCTOR; SECOND IS #{second.type}"
25
+ super(second)
26
+ if first.kind_of? String
27
+ @string = first
28
+ elsif first.kind_of? Comment
29
+ @string = first.string
30
+ end
31
+ end
32
+
33
+ def clone
34
+ Comment.new self
35
+ end
36
+
37
+ # == DEPRECATED
38
+ # See REXML::Formatters
39
+ #
40
+ # output::
41
+ # Where to write the string
42
+ # indent::
43
+ # An integer. If -1, no indenting will be used; otherwise, the
44
+ # indentation will be this number of spaces, and children will be
45
+ # indented an additional amount.
46
+ # transitive::
47
+ # Ignored by this class. The contents of comments are never modified.
48
+ # ie_hack::
49
+ # Needed for conformity to the child API, but not used by this class.
50
+ def write( output, indent=-1, transitive=false, ie_hack=false )
51
+ Kernel.warn("Comment.write is deprecated. See REXML::Formatters")
52
+ indent( output, indent )
53
+ output << START
54
+ output << @string
55
+ output << STOP
56
+ end
57
+
58
+ alias :to_s :string
59
+
60
+ ##
61
+ # Compares this Comment to another; the contents of the comment are used
62
+ # in the comparison.
63
+ def <=>(other)
64
+ other.to_s <=> @string
65
+ end
66
+
67
+ ##
68
+ # Compares this Comment to another; the contents of the comment are used
69
+ # in the comparison.
70
+ def ==( other )
71
+ other.kind_of? Comment and
72
+ (other <=> self) == 0
73
+ end
74
+
75
+ def node_type
76
+ :comment
77
+ end
78
+ end
79
+ end
80
+ #vim:ts=2 sw=2 noexpandtab:
@@ -0,0 +1,271 @@
1
+ require "rexml/parent"
2
+ require "rexml/parseexception"
3
+ require "rexml/namespace"
4
+ require 'rexml/entity'
5
+ require 'rexml/attlistdecl'
6
+ require 'rexml/xmltokens'
7
+
8
+ module REXML
9
+ # Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
10
+ # ... >. DOCTYPES can be used to declare the DTD of a document, as well as
11
+ # being used to declare entities used in the document.
12
+ class DocType < Parent
13
+ include XMLTokens
14
+ START = "<!DOCTYPE"
15
+ STOP = ">"
16
+ SYSTEM = "SYSTEM"
17
+ PUBLIC = "PUBLIC"
18
+ DEFAULT_ENTITIES = {
19
+ 'gt'=>EntityConst::GT,
20
+ 'lt'=>EntityConst::LT,
21
+ 'quot'=>EntityConst::QUOT,
22
+ "apos"=>EntityConst::APOS
23
+ }
24
+
25
+ # name is the name of the doctype
26
+ # external_id is the referenced DTD, if given
27
+ attr_reader :name, :external_id, :entities, :namespaces
28
+
29
+ # Constructor
30
+ #
31
+ # dt = DocType.new( 'foo', '-//I/Hate/External/IDs' )
32
+ # # <!DOCTYPE foo '-//I/Hate/External/IDs'>
33
+ # dt = DocType.new( doctype_to_clone )
34
+ # # Incomplete. Shallow clone of doctype
35
+ #
36
+ # +Note+ that the constructor:
37
+ #
38
+ # Doctype.new( Source.new( "<!DOCTYPE foo 'bar'>" ) )
39
+ #
40
+ # is _deprecated_. Do not use it. It will probably disappear.
41
+ def initialize( first, parent=nil )
42
+ @entities = DEFAULT_ENTITIES
43
+ @long_name = @uri = nil
44
+ if first.kind_of? String
45
+ super()
46
+ @name = first
47
+ @external_id = parent
48
+ elsif first.kind_of? DocType
49
+ super( parent )
50
+ @name = first.name
51
+ @external_id = first.external_id
52
+ elsif first.kind_of? Array
53
+ super( parent )
54
+ @name = first[0]
55
+ @external_id = first[1]
56
+ @long_name = first[2]
57
+ @uri = first[3]
58
+ elsif first.kind_of? Source
59
+ super( parent )
60
+ parser = Parsers::BaseParser.new( first )
61
+ event = parser.pull
62
+ if event[0] == :start_doctype
63
+ @name, @external_id, @long_name, @uri, = event[1..-1]
64
+ end
65
+ else
66
+ super()
67
+ end
68
+ end
69
+
70
+ def node_type
71
+ :doctype
72
+ end
73
+
74
+ def attributes_of element
75
+ rv = []
76
+ each do |child|
77
+ child.each do |key,val|
78
+ rv << Attribute.new(key,val)
79
+ end if child.kind_of? AttlistDecl and child.element_name == element
80
+ end
81
+ rv
82
+ end
83
+
84
+ def attribute_of element, attribute
85
+ att_decl = find do |child|
86
+ child.kind_of? AttlistDecl and
87
+ child.element_name == element and
88
+ child.include? attribute
89
+ end
90
+ return nil unless att_decl
91
+ att_decl[attribute]
92
+ end
93
+
94
+ def clone
95
+ DocType.new self
96
+ end
97
+
98
+ # output::
99
+ # Where to write the string
100
+ # indent::
101
+ # An integer. If -1, no indentation will be used; otherwise, the
102
+ # indentation will be this number of spaces, and children will be
103
+ # indented an additional amount.
104
+ # transitive::
105
+ # Ignored
106
+ # ie_hack::
107
+ # Ignored
108
+ def write( output, indent=0, transitive=false, ie_hack=false )
109
+ f = REXML::Formatters::Default.new
110
+ indent( output, indent )
111
+ output << START
112
+ output << ' '
113
+ output << @name
114
+ output << " #@external_id" if @external_id
115
+ output << " #{@long_name.inspect}" if @long_name
116
+ output << " #{@uri.inspect}" if @uri
117
+ unless @children.empty?
118
+ next_indent = indent + 1
119
+ output << ' ['
120
+ child = nil # speed
121
+ @children.each { |child|
122
+ output << "\n"
123
+ f.write( child, output )
124
+ }
125
+ output << "\n]"
126
+ end
127
+ output << STOP
128
+ end
129
+
130
+ def context
131
+ @parent.context
132
+ end
133
+
134
+ def entity( name )
135
+ @entities[name].unnormalized if @entities[name]
136
+ end
137
+
138
+ def add child
139
+ super(child)
140
+ @entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES
141
+ @entities[ child.name ] = child if child.kind_of? Entity
142
+ end
143
+
144
+ # This method retrieves the public identifier identifying the document's
145
+ # DTD.
146
+ #
147
+ # Method contributed by Henrik Martensson
148
+ def public
149
+ case @external_id
150
+ when "SYSTEM"
151
+ nil
152
+ when "PUBLIC"
153
+ strip_quotes(@long_name)
154
+ end
155
+ end
156
+
157
+ # This method retrieves the system identifier identifying the document's DTD
158
+ #
159
+ # Method contributed by Henrik Martensson
160
+ def system
161
+ case @external_id
162
+ when "SYSTEM"
163
+ strip_quotes(@long_name)
164
+ when "PUBLIC"
165
+ @uri.kind_of?(String) ? strip_quotes(@uri) : nil
166
+ end
167
+ end
168
+
169
+ # This method returns a list of notations that have been declared in the
170
+ # _internal_ DTD subset. Notations in the external DTD subset are not
171
+ # listed.
172
+ #
173
+ # Method contributed by Henrik Martensson
174
+ def notations
175
+ children().select {|node| node.kind_of?(REXML::NotationDecl)}
176
+ end
177
+
178
+ # Retrieves a named notation. Only notations declared in the internal
179
+ # DTD subset can be retrieved.
180
+ #
181
+ # Method contributed by Henrik Martensson
182
+ def notation(name)
183
+ notations.find { |notation_decl|
184
+ notation_decl.name == name
185
+ }
186
+ end
187
+
188
+ private
189
+
190
+ # Method contributed by Henrik Martensson
191
+ def strip_quotes(quoted_string)
192
+ quoted_string =~ /^[\'\"].*[\´\"]$/ ?
193
+ quoted_string[1, quoted_string.length-2] :
194
+ quoted_string
195
+ end
196
+ end
197
+
198
+ # We don't really handle any of these since we're not a validating
199
+ # parser, so we can be pretty dumb about them. All we need to be able
200
+ # to do is spew them back out on a write()
201
+
202
+ # This is an abstract class. You never use this directly; it serves as a
203
+ # parent class for the specific declarations.
204
+ class Declaration < Child
205
+ def initialize src
206
+ super()
207
+ @string = src
208
+ end
209
+
210
+ def to_s
211
+ @string+'>'
212
+ end
213
+
214
+ # == DEPRECATED
215
+ # See REXML::Formatters
216
+ #
217
+ def write( output, indent )
218
+ output << to_s
219
+ end
220
+ end
221
+
222
+ public
223
+ class ElementDecl < Declaration
224
+ def initialize( src )
225
+ super
226
+ end
227
+ end
228
+
229
+ class ExternalEntity < Child
230
+ def initialize( src )
231
+ super()
232
+ @entity = src
233
+ end
234
+ def to_s
235
+ @entity
236
+ end
237
+ def write( output, indent )
238
+ output << @entity
239
+ end
240
+ end
241
+
242
+ class NotationDecl < Child
243
+ attr_accessor :public, :system
244
+ def initialize name, middle, pub, sys
245
+ super(nil)
246
+ @name = name
247
+ @middle = middle
248
+ @public = pub
249
+ @system = sys
250
+ end
251
+
252
+ def to_s
253
+ "<!NOTATION #@name #@middle#{
254
+ @public ? ' ' + public.inspect : ''
255
+ }#{
256
+ @system ? ' ' +@system.inspect : ''
257
+ }>"
258
+ end
259
+
260
+ def write( output, indent=-1 )
261
+ output << to_s
262
+ end
263
+
264
+ # This method retrieves the name of the notation.
265
+ #
266
+ # Method contributed by Henrik Martensson
267
+ def name
268
+ @name
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,230 @@
1
+ require "rexml/element"
2
+ require "rexml/xmldecl"
3
+ require "rexml/source"
4
+ require "rexml/comment"
5
+ require "rexml/doctype"
6
+ require "rexml/instruction"
7
+ require "rexml/rexml"
8
+ require "rexml/parseexception"
9
+ require "rexml/output"
10
+ require "rexml/parsers/baseparser"
11
+ require "rexml/parsers/streamparser"
12
+ require "rexml/parsers/treeparser"
13
+
14
+ module REXML
15
+ # Represents a full XML document, including PIs, a doctype, etc. A
16
+ # Document has a single child that can be accessed by root().
17
+ # Note that if you want to have an XML declaration written for a document
18
+ # you create, you must add one; REXML documents do not write a default
19
+ # declaration for you. See |DECLARATION| and |write|.
20
+ class Document < Element
21
+ # A convenient default XML declaration. If you want an XML declaration,
22
+ # the easiest way to add one is mydoc << Document::DECLARATION
23
+ # +DEPRECATED+
24
+ # Use: mydoc << XMLDecl.default
25
+ DECLARATION = XMLDecl.default
26
+
27
+ # Constructor
28
+ # @param source if supplied, must be a Document, String, or IO.
29
+ # Documents have their context and Element attributes cloned.
30
+ # Strings are expected to be valid XML documents. IOs are expected
31
+ # to be sources of valid XML documents.
32
+ # @param context if supplied, contains the context of the document;
33
+ # this should be a Hash.
34
+ def initialize( source = nil, context = {} )
35
+ @entity_expansion_count = 0
36
+ super()
37
+ @context = context
38
+ return if source.nil?
39
+ if source.kind_of? Document
40
+ @context = source.context
41
+ super source
42
+ else
43
+ build( source )
44
+ end
45
+ end
46
+
47
+ def node_type
48
+ :document
49
+ end
50
+
51
+ # Should be obvious
52
+ def clone
53
+ Document.new self
54
+ end
55
+
56
+ # According to the XML spec, a root node has no expanded name
57
+ def expanded_name
58
+ ''
59
+ #d = doc_type
60
+ #d ? d.name : "UNDEFINED"
61
+ end
62
+
63
+ alias :name :expanded_name
64
+
65
+ # We override this, because XMLDecls and DocTypes must go at the start
66
+ # of the document
67
+ def add( child )
68
+ if child.kind_of? XMLDecl
69
+ @children.unshift child
70
+ child.parent = self
71
+ elsif child.kind_of? DocType
72
+ # Find first Element or DocType node and insert the decl right
73
+ # before it. If there is no such node, just insert the child at the
74
+ # end. If there is a child and it is an DocType, then replace it.
75
+ insert_before_index = 0
76
+ @children.find { |x|
77
+ insert_before_index += 1
78
+ x.kind_of?(Element) || x.kind_of?(DocType)
79
+ }
80
+ if @children[ insert_before_index ] # Not null = not end of list
81
+ if @children[ insert_before_index ].kind_of DocType
82
+ @children[ insert_before_index ] = child
83
+ else
84
+ @children[ index_before_index-1, 0 ] = child
85
+ end
86
+ else # Insert at end of list
87
+ @children[insert_before_index] = child
88
+ end
89
+ child.parent = self
90
+ else
91
+ rv = super
92
+ raise "attempted adding second root element to document" if @elements.size > 1
93
+ rv
94
+ end
95
+ end
96
+ alias :<< :add
97
+
98
+ def add_element(arg=nil, arg2=nil)
99
+ rv = super
100
+ raise "attempted adding second root element to document" if @elements.size > 1
101
+ rv
102
+ end
103
+
104
+ # @return the root Element of the document, or nil if this document
105
+ # has no children.
106
+ def root
107
+ elements[1]
108
+ #self
109
+ #@children.find { |item| item.kind_of? Element }
110
+ end
111
+
112
+ # @return the DocType child of the document, if one exists,
113
+ # and nil otherwise.
114
+ def doctype
115
+ @children.find { |item| item.kind_of? DocType }
116
+ end
117
+
118
+ # @return the XMLDecl of this document; if no XMLDecl has been
119
+ # set, the default declaration is returned.
120
+ def xml_decl
121
+ rv = @children[0]
122
+ return rv if rv.kind_of? XMLDecl
123
+ rv = @children.unshift(XMLDecl.default)[0]
124
+ end
125
+
126
+ # @return the XMLDecl version of this document as a String.
127
+ # If no XMLDecl has been set, returns the default version.
128
+ def version
129
+ xml_decl().version
130
+ end
131
+
132
+ # @return the XMLDecl encoding of this document as a String.
133
+ # If no XMLDecl has been set, returns the default encoding.
134
+ def encoding
135
+ xml_decl().encoding
136
+ end
137
+
138
+ # @return the XMLDecl standalone value of this document as a String.
139
+ # If no XMLDecl has been set, returns the default setting.
140
+ def stand_alone?
141
+ xml_decl().stand_alone?
142
+ end
143
+
144
+ # Write the XML tree out, optionally with indent. This writes out the
145
+ # entire XML document, including XML declarations, doctype declarations,
146
+ # and processing instructions (if any are given).
147
+ #
148
+ # A controversial point is whether Document should always write the XML
149
+ # declaration (<?xml version='1.0'?>) whether or not one is given by the
150
+ # user (or source document). REXML does not write one if one was not
151
+ # specified, because it adds unnecessary bandwidth to applications such
152
+ # as XML-RPC.
153
+ #
154
+ # See also the classes in the rexml/formatters package for the proper way
155
+ # to change the default formatting of XML output
156
+ #
157
+ # _Examples_
158
+ # Document.new("<a><b/></a>").serialize
159
+ #
160
+ # output_string = ""
161
+ # tr = Transitive.new( output_string )
162
+ # Document.new("<a><b/></a>").serialize( tr )
163
+ #
164
+ # output::
165
+ # output an object which supports '<< string'; this is where the
166
+ # document will be written.
167
+ # indent::
168
+ # An integer. If -1, no indenting will be used; otherwise, the
169
+ # indentation will be twice this number of spaces, and children will be
170
+ # indented an additional amount. For a value of 3, every item will be
171
+ # indented 3 more levels, or 6 more spaces (2 * 3). Defaults to -1
172
+ # trans::
173
+ # If transitive is true and indent is >= 0, then the output will be
174
+ # pretty-printed in such a way that the added whitespace does not affect
175
+ # the absolute *value* of the document -- that is, it leaves the value
176
+ # and number of Text nodes in the document unchanged.
177
+ # ie_hack::
178
+ # Internet Explorer is the worst piece of crap to have ever been
179
+ # written, with the possible exception of Windows itself. Since IE is
180
+ # unable to parse proper XML, we have to provide a hack to generate XML
181
+ # that IE's limited abilities can handle. This hack inserts a space
182
+ # before the /> on empty tags. Defaults to false
183
+ def write( output=$stdout, indent=-1, trans=false, ie_hack=false )
184
+ if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
185
+ output = Output.new( output, xml_decl.encoding )
186
+ end
187
+ formatter = if indent > -1
188
+ if trans
189
+ REXML::Formatters::Transitive.new( indent, ie_hack )
190
+ else
191
+ REXML::Formatters::Pretty.new( indent, ie_hack )
192
+ end
193
+ else
194
+ REXML::Formatters::Default.new( ie_hack )
195
+ end
196
+ formatter.write( self, output )
197
+ end
198
+
199
+
200
+ def Document::parse_stream( source, listener )
201
+ Parsers::StreamParser.new( source, listener ).parse
202
+ end
203
+
204
+ @@entity_expansion_limit = 10_000
205
+
206
+ # Set the entity expansion limit. By default the limit is set to 10000.
207
+ def Document::entity_expansion_limit=( val )
208
+ @@entity_expansion_limit = val
209
+ end
210
+
211
+ # Get the entity expansion limit. By default the limit is set to 10000.
212
+ def Document::entity_expansion_limit
213
+ return @@entity_expansion_limit
214
+ end
215
+
216
+ attr_reader :entity_expansion_count
217
+
218
+ def record_entity_expansion
219
+ @entity_expansion_count += 1
220
+ if @entity_expansion_count > @@entity_expansion_limit
221
+ raise "number of entity expansions exceeded, processing aborted."
222
+ end
223
+ end
224
+
225
+ private
226
+ def build( source )
227
+ Parsers::TreeParser.new( source, self ).parse
228
+ end
229
+ end
230
+ end