rexml 3.1.7.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rexml might be problematic. Click here for more details.

Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +60 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/lib/rexml/attlistdecl.rb +63 -0
  11. data/lib/rexml/attribute.rb +192 -0
  12. data/lib/rexml/cdata.rb +68 -0
  13. data/lib/rexml/child.rb +97 -0
  14. data/lib/rexml/comment.rb +80 -0
  15. data/lib/rexml/doctype.rb +270 -0
  16. data/lib/rexml/document.rb +291 -0
  17. data/lib/rexml/dtd/attlistdecl.rb +11 -0
  18. data/lib/rexml/dtd/dtd.rb +47 -0
  19. data/lib/rexml/dtd/elementdecl.rb +18 -0
  20. data/lib/rexml/dtd/entitydecl.rb +57 -0
  21. data/lib/rexml/dtd/notationdecl.rb +40 -0
  22. data/lib/rexml/element.rb +1267 -0
  23. data/lib/rexml/encoding.rb +51 -0
  24. data/lib/rexml/entity.rb +171 -0
  25. data/lib/rexml/formatters/default.rb +112 -0
  26. data/lib/rexml/formatters/pretty.rb +142 -0
  27. data/lib/rexml/formatters/transitive.rb +58 -0
  28. data/lib/rexml/functions.rb +447 -0
  29. data/lib/rexml/instruction.rb +71 -0
  30. data/lib/rexml/light/node.rb +196 -0
  31. data/lib/rexml/namespace.rb +48 -0
  32. data/lib/rexml/node.rb +76 -0
  33. data/lib/rexml/output.rb +30 -0
  34. data/lib/rexml/parent.rb +166 -0
  35. data/lib/rexml/parseexception.rb +52 -0
  36. data/lib/rexml/parsers/baseparser.rb +586 -0
  37. data/lib/rexml/parsers/lightparser.rb +59 -0
  38. data/lib/rexml/parsers/pullparser.rb +197 -0
  39. data/lib/rexml/parsers/sax2parser.rb +273 -0
  40. data/lib/rexml/parsers/streamparser.rb +61 -0
  41. data/lib/rexml/parsers/treeparser.rb +101 -0
  42. data/lib/rexml/parsers/ultralightparser.rb +57 -0
  43. data/lib/rexml/parsers/xpathparser.rb +675 -0
  44. data/lib/rexml/quickpath.rb +266 -0
  45. data/lib/rexml/rexml.rb +32 -0
  46. data/lib/rexml/sax2listener.rb +98 -0
  47. data/lib/rexml/security.rb +28 -0
  48. data/lib/rexml/source.rb +298 -0
  49. data/lib/rexml/streamlistener.rb +93 -0
  50. data/lib/rexml/syncenumerator.rb +33 -0
  51. data/lib/rexml/text.rb +424 -0
  52. data/lib/rexml/undefinednamespaceexception.rb +9 -0
  53. data/lib/rexml/validation/relaxng.rb +539 -0
  54. data/lib/rexml/validation/validation.rb +144 -0
  55. data/lib/rexml/validation/validationexception.rb +10 -0
  56. data/lib/rexml/xmldecl.rb +116 -0
  57. data/lib/rexml/xmltokens.rb +85 -0
  58. data/lib/rexml/xpath.rb +81 -0
  59. data/lib/rexml/xpath_parser.rb +934 -0
  60. data/rexml.gemspec +42 -0
  61. metadata +131 -0
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: false
2
+ require_relative 'pretty'
3
+
4
+ module REXML
5
+ module Formatters
6
+ # The Transitive formatter writes an XML document that parses to an
7
+ # identical document as the source document. This means that no extra
8
+ # whitespace nodes are inserted, and whitespace within text nodes is
9
+ # preserved. Within these constraints, the document is pretty-printed,
10
+ # with whitespace inserted into the metadata to introduce formatting.
11
+ #
12
+ # Note that this is only useful if the original XML is not already
13
+ # formatted. Since this formatter does not alter whitespace nodes, the
14
+ # results of formatting already formatted XML will be odd.
15
+ class Transitive < Default
16
+ def initialize( indentation=2, ie_hack=false )
17
+ @indentation = indentation
18
+ @level = 0
19
+ @ie_hack = ie_hack
20
+ end
21
+
22
+ protected
23
+ def write_element( node, output )
24
+ output << "<#{node.expanded_name}"
25
+
26
+ node.attributes.each_attribute do |attr|
27
+ output << " "
28
+ attr.write( output )
29
+ end unless node.attributes.empty?
30
+
31
+ output << "\n"
32
+ output << ' '*@level
33
+ if node.children.empty?
34
+ output << " " if @ie_hack
35
+ output << "/"
36
+ else
37
+ output << ">"
38
+ # If compact and all children are text, and if the formatted output
39
+ # is less than the specified width, then try to print everything on
40
+ # one line
41
+ @level += @indentation
42
+ node.children.each { |child|
43
+ write( child, output )
44
+ }
45
+ @level -= @indentation
46
+ output << "</#{node.expanded_name}"
47
+ output << "\n"
48
+ output << ' '*@level
49
+ end
50
+ output << ">"
51
+ end
52
+
53
+ def write_text( node, output )
54
+ output << node.to_s()
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,447 @@
1
+ # frozen_string_literal: false
2
+ module REXML
3
+ # If you add a method, keep in mind two things:
4
+ # (1) the first argument will always be a list of nodes from which to
5
+ # filter. In the case of context methods (such as position), the function
6
+ # should return an array with a value for each child in the array.
7
+ # (2) all method calls from XML will have "-" replaced with "_".
8
+ # Therefore, in XML, "local-name()" is identical (and actually becomes)
9
+ # "local_name()"
10
+ module Functions
11
+ @@available_functions = {}
12
+ @@context = nil
13
+ @@namespace_context = {}
14
+ @@variables = {}
15
+
16
+ INTERNAL_METHODS = [
17
+ :namespace_context,
18
+ :namespace_context=,
19
+ :variables,
20
+ :variables=,
21
+ :context=,
22
+ :get_namespace,
23
+ :send,
24
+ ]
25
+ class << self
26
+ def singleton_method_added(name)
27
+ unless INTERNAL_METHODS.include?(name)
28
+ @@available_functions[name] = true
29
+ end
30
+ end
31
+ end
32
+
33
+ def Functions::namespace_context=(x) ; @@namespace_context=x ; end
34
+ def Functions::variables=(x) ; @@variables=x ; end
35
+ def Functions::namespace_context ; @@namespace_context ; end
36
+ def Functions::variables ; @@variables ; end
37
+
38
+ def Functions::context=(value); @@context = value; end
39
+
40
+ def Functions::text( )
41
+ if @@context[:node].node_type == :element
42
+ return @@context[:node].find_all{|n| n.node_type == :text}.collect{|n| n.value}
43
+ elsif @@context[:node].node_type == :text
44
+ return @@context[:node].value
45
+ else
46
+ return false
47
+ end
48
+ end
49
+
50
+ # Returns the last node of the given list of nodes.
51
+ def Functions::last( )
52
+ @@context[:size]
53
+ end
54
+
55
+ def Functions::position( )
56
+ @@context[:index]
57
+ end
58
+
59
+ # Returns the size of the given list of nodes.
60
+ def Functions::count( node_set )
61
+ node_set.size
62
+ end
63
+
64
+ # Since REXML is non-validating, this method is not implemented as it
65
+ # requires a DTD
66
+ def Functions::id( object )
67
+ end
68
+
69
+ # UNTESTED
70
+ def Functions::local_name( node_set=nil )
71
+ get_namespace( node_set ) do |node|
72
+ return node.local_name
73
+ end
74
+ end
75
+
76
+ def Functions::namespace_uri( node_set=nil )
77
+ get_namespace( node_set ) {|node| node.namespace}
78
+ end
79
+
80
+ def Functions::name( node_set=nil )
81
+ get_namespace( node_set ) do |node|
82
+ node.expanded_name
83
+ end
84
+ end
85
+
86
+ # Helper method.
87
+ def Functions::get_namespace( node_set = nil )
88
+ if node_set == nil
89
+ yield @@context[:node] if @@context[:node].respond_to?(:namespace)
90
+ else
91
+ if node_set.respond_to? :each
92
+ result = []
93
+ node_set.each do |node|
94
+ result << yield(node) if node.respond_to?(:namespace)
95
+ end
96
+ result
97
+ elsif node_set.respond_to? :namespace
98
+ yield node_set
99
+ end
100
+ end
101
+ end
102
+
103
+ # A node-set is converted to a string by returning the string-value of the
104
+ # node in the node-set that is first in document order. If the node-set is
105
+ # empty, an empty string is returned.
106
+ #
107
+ # A number is converted to a string as follows
108
+ #
109
+ # NaN is converted to the string NaN
110
+ #
111
+ # positive zero is converted to the string 0
112
+ #
113
+ # negative zero is converted to the string 0
114
+ #
115
+ # positive infinity is converted to the string Infinity
116
+ #
117
+ # negative infinity is converted to the string -Infinity
118
+ #
119
+ # if the number is an integer, the number is represented in decimal form
120
+ # as a Number with no decimal point and no leading zeros, preceded by a
121
+ # minus sign (-) if the number is negative
122
+ #
123
+ # otherwise, the number is represented in decimal form as a Number
124
+ # including a decimal point with at least one digit before the decimal
125
+ # point and at least one digit after the decimal point, preceded by a
126
+ # minus sign (-) if the number is negative; there must be no leading zeros
127
+ # before the decimal point apart possibly from the one required digit
128
+ # immediately before the decimal point; beyond the one required digit
129
+ # after the decimal point there must be as many, but only as many, more
130
+ # digits as are needed to uniquely distinguish the number from all other
131
+ # IEEE 754 numeric values.
132
+ #
133
+ # The boolean false value is converted to the string false. The boolean
134
+ # true value is converted to the string true.
135
+ #
136
+ # An object of a type other than the four basic types is converted to a
137
+ # string in a way that is dependent on that type.
138
+ def Functions::string( object=nil )
139
+ object = @@context[:node] if object.nil?
140
+ if object.respond_to?(:node_type)
141
+ case object.node_type
142
+ when :attribute
143
+ object.value
144
+ when :element
145
+ string_value(object)
146
+ when :document
147
+ string_value(object.root)
148
+ when :processing_instruction
149
+ object.content
150
+ else
151
+ object.to_s
152
+ end
153
+ else
154
+ case object
155
+ when Array
156
+ string(object[0])
157
+ when Float
158
+ if object.nan?
159
+ "NaN"
160
+ else
161
+ integer = object.to_i
162
+ if object == integer
163
+ "%d" % integer
164
+ else
165
+ object.to_s
166
+ end
167
+ end
168
+ when nil
169
+ ""
170
+ else
171
+ object.to_s
172
+ end
173
+ end
174
+ end
175
+
176
+ # A node-set is converted to a string by
177
+ # returning the concatenation of the string-value
178
+ # of each of the children of the node in the
179
+ # node-set that is first in document order.
180
+ # If the node-set is empty, an empty string is returned.
181
+ def Functions::string_value( o )
182
+ rv = ""
183
+ o.children.each { |e|
184
+ if e.node_type == :text
185
+ rv << e.to_s
186
+ elsif e.node_type == :element
187
+ rv << string_value( e )
188
+ end
189
+ }
190
+ rv
191
+ end
192
+
193
+ def Functions::concat( *objects )
194
+ concatenated = ""
195
+ objects.each do |object|
196
+ concatenated << string(object)
197
+ end
198
+ concatenated
199
+ end
200
+
201
+ # Fixed by Mike Stok
202
+ def Functions::starts_with( string, test )
203
+ string(string).index(string(test)) == 0
204
+ end
205
+
206
+ # Fixed by Mike Stok
207
+ def Functions::contains( string, test )
208
+ string(string).include?(string(test))
209
+ end
210
+
211
+ # Kouhei fixed this
212
+ def Functions::substring_before( string, test )
213
+ ruby_string = string(string)
214
+ ruby_index = ruby_string.index(string(test))
215
+ if ruby_index.nil?
216
+ ""
217
+ else
218
+ ruby_string[ 0...ruby_index ]
219
+ end
220
+ end
221
+
222
+ # Kouhei fixed this too
223
+ def Functions::substring_after( string, test )
224
+ ruby_string = string(string)
225
+ return $1 if ruby_string =~ /#{test}(.*)/
226
+ ""
227
+ end
228
+
229
+ # Take equal portions of Mike Stok and Sean Russell; mix
230
+ # vigorously, and pour into a tall, chilled glass. Serves 10,000.
231
+ def Functions::substring( string, start, length=nil )
232
+ ruby_string = string(string)
233
+ ruby_length = if length.nil?
234
+ ruby_string.length.to_f
235
+ else
236
+ number(length)
237
+ end
238
+ ruby_start = number(start)
239
+
240
+ # Handle the special cases
241
+ return '' if (
242
+ ruby_length.nan? or
243
+ ruby_start.nan? or
244
+ ruby_start.infinite?
245
+ )
246
+
247
+ infinite_length = ruby_length.infinite? == 1
248
+ ruby_length = ruby_string.length if infinite_length
249
+
250
+ # Now, get the bounds. The XPath bounds are 1..length; the ruby bounds
251
+ # are 0..length. Therefore, we have to offset the bounds by one.
252
+ ruby_start = round(ruby_start) - 1
253
+ ruby_length = round(ruby_length)
254
+
255
+ if ruby_start < 0
256
+ ruby_length += ruby_start unless infinite_length
257
+ ruby_start = 0
258
+ end
259
+ return '' if ruby_length <= 0
260
+ ruby_string[ruby_start,ruby_length]
261
+ end
262
+
263
+ # UNTESTED
264
+ def Functions::string_length( string )
265
+ string(string).length
266
+ end
267
+
268
+ # UNTESTED
269
+ def Functions::normalize_space( string=nil )
270
+ string = string(@@context[:node]) if string.nil?
271
+ if string.kind_of? Array
272
+ string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string}
273
+ else
274
+ string.to_s.strip.gsub(/\s+/um, ' ')
275
+ end
276
+ end
277
+
278
+ # This is entirely Mike Stok's beast
279
+ def Functions::translate( string, tr1, tr2 )
280
+ from = string(tr1)
281
+ to = string(tr2)
282
+
283
+ # the map is our translation table.
284
+ #
285
+ # if a character occurs more than once in the
286
+ # from string then we ignore the second &
287
+ # subsequent mappings
288
+ #
289
+ # if a character maps to nil then we delete it
290
+ # in the output. This happens if the from
291
+ # string is longer than the to string
292
+ #
293
+ # there's nothing about - or ^ being special in
294
+ # http://www.w3.org/TR/xpath#function-translate
295
+ # so we don't build ranges or negated classes
296
+
297
+ map = Hash.new
298
+ 0.upto(from.length - 1) { |pos|
299
+ from_char = from[pos]
300
+ unless map.has_key? from_char
301
+ map[from_char] =
302
+ if pos < to.length
303
+ to[pos]
304
+ else
305
+ nil
306
+ end
307
+ end
308
+ }
309
+
310
+ if ''.respond_to? :chars
311
+ string(string).chars.collect { |c|
312
+ if map.has_key? c then map[c] else c end
313
+ }.compact.join
314
+ else
315
+ string(string).unpack('U*').collect { |c|
316
+ if map.has_key? c then map[c] else c end
317
+ }.compact.pack('U*')
318
+ end
319
+ end
320
+
321
+ # UNTESTED
322
+ def Functions::boolean( object=nil )
323
+ if object.kind_of? String
324
+ if object =~ /\d+/u
325
+ return object.to_f != 0
326
+ else
327
+ return object.size > 0
328
+ end
329
+ elsif object.kind_of? Array
330
+ object = object.find{|x| x and true}
331
+ end
332
+ return object ? true : false
333
+ end
334
+
335
+ # UNTESTED
336
+ def Functions::not( object )
337
+ not boolean( object )
338
+ end
339
+
340
+ # UNTESTED
341
+ def Functions::true( )
342
+ true
343
+ end
344
+
345
+ # UNTESTED
346
+ def Functions::false( )
347
+ false
348
+ end
349
+
350
+ # UNTESTED
351
+ def Functions::lang( language )
352
+ lang = false
353
+ node = @@context[:node]
354
+ attr = nil
355
+ until node.nil?
356
+ if node.node_type == :element
357
+ attr = node.attributes["xml:lang"]
358
+ unless attr.nil?
359
+ lang = compare_language(string(language), attr)
360
+ break
361
+ else
362
+ end
363
+ end
364
+ node = node.parent
365
+ end
366
+ lang
367
+ end
368
+
369
+ def Functions::compare_language lang1, lang2
370
+ lang2.downcase.index(lang1.downcase) == 0
371
+ end
372
+
373
+ # a string that consists of optional whitespace followed by an optional
374
+ # minus sign followed by a Number followed by whitespace is converted to
375
+ # the IEEE 754 number that is nearest (according to the IEEE 754
376
+ # round-to-nearest rule) to the mathematical value represented by the
377
+ # string; any other string is converted to NaN
378
+ #
379
+ # boolean true is converted to 1; boolean false is converted to 0
380
+ #
381
+ # a node-set is first converted to a string as if by a call to the string
382
+ # function and then converted in the same way as a string argument
383
+ #
384
+ # an object of a type other than the four basic types is converted to a
385
+ # number in a way that is dependent on that type
386
+ def Functions::number( object=nil )
387
+ object = @@context[:node] unless object
388
+ case object
389
+ when true
390
+ Float(1)
391
+ when false
392
+ Float(0)
393
+ when Array
394
+ number(string( object ))
395
+ when Numeric
396
+ object.to_f
397
+ else
398
+ str = string( object )
399
+ # If XPath ever gets scientific notation...
400
+ #if str =~ /^\s*-?(\d*\.?\d+|\d+\.)([Ee]\d*)?\s*$/
401
+ if str =~ /^\s*-?(\d*\.?\d+|\d+\.)\s*$/
402
+ str.to_f
403
+ else
404
+ (0.0 / 0.0)
405
+ end
406
+ end
407
+ end
408
+
409
+ def Functions::sum( nodes )
410
+ nodes = [nodes] unless nodes.kind_of? Array
411
+ nodes.inject(0) { |r,n| r + number(string(n)) }
412
+ end
413
+
414
+ def Functions::floor( number )
415
+ number(number).floor
416
+ end
417
+
418
+ def Functions::ceiling( number )
419
+ number(number).ceil
420
+ end
421
+
422
+ def Functions::round( number )
423
+ number = number(number)
424
+ begin
425
+ neg = number.negative?
426
+ number = number.abs.round
427
+ neg ? -number : number
428
+ rescue FloatDomainError
429
+ number
430
+ end
431
+ end
432
+
433
+ def Functions::processing_instruction( node )
434
+ node.node_type == :processing_instruction
435
+ end
436
+
437
+ def Functions::send(name, *args)
438
+ if @@available_functions[name.to_sym]
439
+ super
440
+ else
441
+ # TODO: Maybe, this is not XPath spec behavior.
442
+ # This behavior must be reconsidered.
443
+ XPath.match(@@context[:node], name.to_s)
444
+ end
445
+ end
446
+ end
447
+ end