rexle 1.5.9 → 1.5.13

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 (6) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/rexle.rb +372 -349
  4. data.tar.gz.sig +0 -0
  5. metadata +35 -34
  6. metadata.gz.sig +0 -0
data/lib/rexle.rb CHANGED
@@ -13,31 +13,37 @@ require 'backtrack-xpath'
13
13
 
14
14
  # modifications:
15
15
 
16
+ # 14-Jan-2022: bug fix: Related to previous bug fix; Unescape is
17
+ # now only applied to objects of type Attributes::Value
18
+ # 01-Jan-2022: bug fix: Attribute values are no longer unescaped when
19
+ # called from Rexle#xml
20
+ # 03-Apr-2021: bug fix: Using *to_a* a CDATA element if present is now output
21
+ # 20-Feb-2021: bug fix: The @instructions accessor is now ignored if nil.
16
22
  # 11-Sep-2020: feature: Rexle::Element#text now has unescaped HTML using CGI
17
23
  # 30-Jul-2020: minor improvement: #plaintext now unescapes & to &
18
24
  # 11-May-2020: bug fix: Rexle#css now responds correctly to valid selectors
19
25
  # 23-Apr-2020: feature: Added public method *plaintext*.
20
26
  # 04-Feb-2020: minor bug fix: Element A is now defined as a non self-closing tag
21
- # 18-Sep-2019: minor bug fix: &apos is now unescaped properly
22
- # 09-Jul-2019: minor improvement: A comment tag now has a
27
+ # 18-Sep-2019: minor bug fix: &apos is now unescaped properly
28
+ # 09-Jul-2019: minor improvement: A comment tag now has a
23
29
  # new line when pretty printed
24
30
  # 02-Feb-2019: feature: A comment tag can now have nested elements
25
31
  # 03-Nov-2018: feature: Debug messages can now use coloured text
26
32
  # 02-Oct-2018: feature: Added Rexle::Elements#last
27
- # 18-Jan-2018: bug fix: An Element's attributes are now cloned too
28
- # 16-Sep-2017: improvement: Multiple results are now returned if the
33
+ # 18-Jan-2018: bug fix: An Element's attributes are now cloned too
34
+ # 16-Sep-2017: improvement: Multiple results are now returned if the
29
35
  # xpath contains an *and* operator
30
- # 14-Sep-2017: improvement: An *and* operator can now be
36
+ # 14-Sep-2017: improvement: An *and* operator can now be
31
37
  # used between xpath statements
32
38
  # 10-Sep-2017: bug fix: The following XPath has now been tested => //.[@id]
33
- # 10-Aug-2017: feature: Rexle now has a member variable (@rexle) to keep
34
- # track of the working document when elements are passed to
39
+ # 10-Aug-2017: feature: Rexle now has a member variable (@rexle) to keep
40
+ # track of the working document when elements are passed to
35
41
  # different documents
36
42
  # bug fix: Element prefixes are now only processed if they exist
37
- # 13-Apr-2017: bug fix: Rexle::Elements#index was implemented which fixes the
43
+ # 13-Apr-2017: bug fix: Rexle::Elements#index was implemented which fixes the
38
44
  # Rexle::Element#next_sibling and Rexle::Element#previous_sibling bugs
39
- # 25-Feb-2017: improvement:
40
- # An input rexle array can now have an empty array for
45
+ # 25-Feb-2017: improvement:
46
+ # An input rexle array can now have an empty array for
41
47
  # children e.g. doc = Rexle.new(["records", {}, "", []])
42
48
  # 25-Dec-2016: revision for Ruby 2.4: Replaced Fixnum with Integer
43
49
 
@@ -51,7 +57,14 @@ module XMLhelper
51
57
  scan_print(children).join.force_encoding("utf-8")
52
58
 
53
59
  a = self.root.attributes.to_a.map do |k,v|
54
- "%s='%s'" % [k,(v.is_a?(Array) ? v.join(' ') : v.to_s)]
60
+
61
+ val = if v.is_a?(Array) then
62
+ v.join(' ')
63
+ else
64
+ v.is_a?(String) ? v : v.to_s(unescape: false)
65
+ end
66
+
67
+ "%s='%s'" % [k, val]
55
68
  end
56
69
 
57
70
  xml = "<%s%s>%s</%s>" % [self.root.name, a.empty? ? '' : \
@@ -59,7 +72,7 @@ module XMLhelper
59
72
 
60
73
  if self.instructions and declaration then
61
74
  processing_instructions() + xml
62
- else
75
+ else
63
76
  xml
64
77
  end
65
78
  end
@@ -68,43 +81,43 @@ module XMLhelper
68
81
 
69
82
  body = pretty_print(children,2).join
70
83
 
71
- a = self.root.attributes.to_a.map do |k,v|
72
- "%s='%s'" % [k,(v.is_a?(Array) ? v.join(' ') : v)]
84
+ a = self.root.attributes.to_a.map do |k,v|
85
+ "%s='%s'" % [k,(v.is_a?(Array) ? v.join(' ') : v.to_s)]
73
86
  end
74
-
75
- ind = "\n "
87
+
88
+ ind = "\n "
76
89
  xml = "<%s%s>%s%s%s</%s>" % [self.root.name, a.empty? ? '' : \
77
90
  ' ' + a.join(' '), ind, body, "\n", self.root.name]
78
91
 
79
92
  if self.instructions and declaration then
80
93
  processing_instructions("") + xml
81
- else
94
+ else
82
95
  xml
83
96
  end
84
97
  end
85
-
86
- def inspect()
98
+
99
+ def inspect()
87
100
  "#<Rexle:%s>" % [self.object_id]
88
101
  end
89
102
 
90
103
  def processing_instructions(s='')
91
104
  self.instructions.map do |instruction|
92
- "<?%s?>\n" % instruction.join(' ')
105
+ "<?%s?>\n" % instruction.join(' ')
93
106
  end.join s
94
107
  end
95
108
 
96
109
  def scan_print(nodes)
97
110
 
98
111
  r2 = nodes.map do |x|
99
-
112
+
100
113
  r = if x.is_a? Rexle::Element then
101
114
 
102
- a = x.attributes.to_a.map do |k,v|
115
+ a = x.attributes.to_a.map do |k,v|
103
116
  "%s='%s'" % [k,(v.is_a?(Array) ? v.join(' ') : v)]
104
117
  end
105
118
 
106
119
  tag = x.name + (a.empty? ? '' : ' ' + a.join(' '))
107
-
120
+
108
121
  non_self_closing_tags = %w(script textarea iframe div object a)
109
122
 
110
123
  if (x.children and x.children.length > 0 \
@@ -118,20 +131,20 @@ module XMLhelper
118
131
  else
119
132
  out = ["<%s/>" % tag]
120
133
  end
121
-
134
+
122
135
  elsif x.is_a? String then x
123
- elsif x.is_a? Rexle::CData then x.print
124
- elsif x.is_a? Rexle::Comment then x.print
125
-
136
+ elsif x.is_a? Rexle::CData then x.print
137
+ elsif x.is_a? Rexle::Comment then x.print
138
+
126
139
  end
127
140
 
128
141
  r
129
142
  end
130
-
143
+
131
144
  r2
132
145
 
133
146
  end
134
-
147
+
135
148
  def scan_to_a(nodes)
136
149
 
137
150
  nodes.inject([]) do |r,x|
@@ -140,6 +153,10 @@ module XMLhelper
140
153
 
141
154
  a = [String.new(x.name), Hash.new(x.attributes), x.value.to_s]
142
155
 
156
+ if x.cdatas.any? then
157
+ a.concat x.cdatas.map {|cdata| ['![', {}, cdata] }
158
+ end
159
+
143
160
  (a.concat(scan_to_a(x.children))) if x.children.length > 1
144
161
  r << a
145
162
  elsif x.is_a? String then
@@ -150,7 +167,7 @@ module XMLhelper
150
167
  end
151
168
 
152
169
  end
153
-
170
+
154
171
 
155
172
 
156
173
  def pretty_print(nodes, indent='0')
@@ -163,13 +180,13 @@ module XMLhelper
163
180
 
164
181
  if x.is_a? Rexle::Element then
165
182
 
166
- a = x.attributes.to_a.map do |k,v|
183
+ a = x.attributes.to_a.map do |k,v|
167
184
  "%s='%s'" % [k,(v.is_a?(Array) ? v.join(' ') : v)]
168
185
  end
169
186
  a ||= []
170
187
 
171
188
  tag = x.name + (a.empty? ? '' : ' ' + a.join(' '))
172
- start = i > 0 ? ("\n" + ' ' * (indent - 1)) : ''
189
+ start = i > 0 ? ("\n" + ' ' * (indent - 1)) : ''
173
190
 
174
191
  if (x.value and x.value.length > 0) \
175
192
  or (x.children and x.children.length > 0 \
@@ -177,13 +194,13 @@ module XMLhelper
177
194
  x.name == 'script' or x.name == 'textarea' or \
178
195
  x.name == 'iframe' then
179
196
 
180
- ind1 = (x.children and x.children.grep(Rexle::Element).length > 0) ?
197
+ ind1 = (x.children and x.children.grep(Rexle::Element).length > 0) ?
181
198
  ("\n" + ' ' * indent) : ''
182
-
199
+
183
200
  out = ["%s<%s>%s" % [start, tag, ind1]]
184
- out << pretty_print(x.children, (indent + 1).to_s.clone)
201
+ out << pretty_print(x.children, (indent + 1).to_s.clone)
185
202
  ind2 = (ind1 and ind1.length > 0) ? ("\n" + ' ' * (indent - 1)) : ''
186
- out << "%s</%s>" % [ind2, x.name]
203
+ out << "%s</%s>" % [ind2, x.name]
187
204
  else
188
205
 
189
206
  out = ["%s<%s/>" % [start, tag]]
@@ -191,8 +208,8 @@ module XMLhelper
191
208
 
192
209
 
193
210
  elsif x.is_a? String then x.sub(/^[\n\s]+$/,'')
194
- elsif x.is_a? Rexle::CData then x.print
195
- elsif x.is_a? Rexle::Comment then "\n" + (' ' * indent) + x.print
211
+ elsif x.is_a? Rexle::CData then x.print
212
+ elsif x.is_a? Rexle::Comment then "\n" + (' ' * indent) + x.print
196
213
 
197
214
  end
198
215
  end
@@ -207,17 +224,17 @@ class Rexle
207
224
 
208
225
  attr_reader :prefixes, :doctype
209
226
  attr_accessor :instructions
210
-
227
+
211
228
  def initialize(x=nil, rexle: self, debug: false)
212
229
 
213
230
  @rexle, @debug = rexle, debug
214
231
  $debug = @debug
215
-
232
+
216
233
  puts 'inside Rexle'.debug if debug
217
-
234
+
218
235
  super()
219
236
 
220
- @instructions = [["xml", "version='1.0' encoding='UTF-8'"]]
237
+ @instructions = [["xml", "version='1.0' encoding='UTF-8'"]]
221
238
  @doctype = :xml
222
239
 
223
240
  # what type of input is it? Is it a string, array
@@ -227,11 +244,11 @@ class Rexle
227
244
  Array: proc {|x| x},
228
245
  RexleParser: ->(x){ parse_rexle(x)}
229
246
  }
230
-
247
+
231
248
  doc_node = ['doc', Attributes.new]
232
-
249
+
233
250
  @a = procs[x.class.to_s.to_sym].call(x)
234
-
251
+
235
252
  @doc = scan_element(*(doc_node << @a))
236
253
 
237
254
  # fetch the namespaces
@@ -242,78 +259,78 @@ class Rexle
242
259
  xmlns = @doc.root.attributes.select {|k,v| k[/^xmlns:/]}
243
260
  @prefixes = xmlns.keys.map{|x| x[/\w+$/]}
244
261
  end
245
-
262
+
246
263
  end
247
264
 
248
265
  end
249
-
266
+
250
267
  def clone()
251
268
  Rexle.new self.to_a
252
269
  end
253
-
270
+
254
271
  def at_css(selector)
255
272
  @doc.root.element RexleCSS.new(selector).to_xpath
256
- end
257
-
273
+ end
274
+
258
275
  def css(selector)
259
-
260
- a = selector.split(',').flat_map do |x|
276
+
277
+ a = selector.split(',').flat_map do |x|
261
278
  @doc.root.xpath RexleCSS.new(x).to_xpath
262
279
  end
263
-
280
+
264
281
  return a
265
282
  end
266
-
283
+
267
284
  def xpath(path, &blk)
268
285
  @doc.xpath(path, &blk)
269
- end
286
+ end
270
287
 
271
288
  class Element
272
289
  include XMLhelper
273
-
290
+
274
291
  class Value < String
275
-
292
+
276
293
  def initialize(value)
277
294
  super(value)
278
295
  end
279
-
296
+
280
297
  def <(val2)
281
298
  self.to_f < val2.to_f
282
- end
283
-
299
+ end
300
+
284
301
  def >(val2)
285
302
  self.to_f > val2.to_f
286
- end
287
- end
288
-
303
+ end
304
+ end
305
+
289
306
  class Attribute
290
-
307
+
291
308
  attr_reader :value
292
-
309
+
293
310
  def initialize(value)
294
311
  @value = value
295
312
  end
296
-
313
+
297
314
  def to_f()
298
315
  @value.to_f
299
- end
300
-
316
+ end
317
+
301
318
  def to_i()
302
319
  @value.to_i
303
320
  end
304
-
321
+
305
322
  alias to_s value
306
-
323
+
307
324
  end
308
-
325
+
309
326
  attr_accessor :name, :value, :parent
310
327
  attr_reader :child_elements, :doc_id, :instructions
311
-
328
+
312
329
  alias original_clone clone
313
330
 
314
331
  def initialize(name=nil, value: nil, attributes: Attributes.new, rexle: self)
315
332
 
316
- @rexle = rexle
333
+ @rexle = rexle
317
334
  super()
318
335
 
319
336
  @name, @attributes = name.to_s, attributes
@@ -323,11 +340,11 @@ class Rexle
323
340
  self.add_text value if value
324
341
 
325
342
  end
326
-
343
+
327
344
  def backtrack(use_attributes: true)
328
345
  BacktrackXPath.new(self, use_attributes: use_attributes)
329
346
  end
330
-
347
+
331
348
  def cdata?()
332
349
  self.is_a? CData
333
350
  end
@@ -335,8 +352,8 @@ class Rexle
335
352
  def contains(raw_args)
336
353
 
337
354
  path, raw_val = raw_args.split(',',2)
338
- val = raw_val.strip[/^["']?.*["']?$/]
339
-
355
+ val = raw_val.strip[/^["']?.*["']?$/]
356
+
340
357
  anode = query_xpath(path)
341
358
 
342
359
  return [false] if anode.nil? or anode.empty?
@@ -345,21 +362,21 @@ class Rexle
345
362
  r = [a.grep(/#{val.sub(/^["'](.*)["']$/,'\1')}/).length > 0]
346
363
 
347
364
  r.any?
348
- end
349
-
365
+ end
366
+
350
367
  def count(path)
351
368
  length = query_xpath(path).flatten.compact.length
352
369
  length
353
370
  end
354
-
371
+
355
372
  def current()
356
373
  self
357
374
  end
358
375
 
359
376
  def at_css(selector)
360
377
  self.root.element RexleCSS.new(selector).to_xpath
361
- end
362
-
378
+ end
379
+
363
380
  def css(selector)
364
381
 
365
382
  selector.split(',')\
@@ -370,76 +387,76 @@ class Rexle
370
387
  def lowercase(s)
371
388
 
372
389
  end
373
-
374
- def max(path)
390
+
391
+ def max(path)
375
392
  a = query_xpath(path).flatten.select{|x| x.is_a? String or x.is_a? Rexle::Element::Attribute}.map(&:to_i)
376
- a.max
393
+ a.max
377
394
  end
378
-
395
+
379
396
  def name()
380
-
397
+
381
398
  if @rexle and @rexle.respond_to? :prefixes then
382
-
399
+
383
400
  if @rexle.prefixes.is_a? Array then
384
- prefix = @rexle.prefixes.find {|x| x == @name[/^(\w+):/,1] }
401
+ prefix = @rexle.prefixes.find {|x| x == @name[/^(\w+):/,1] }
385
402
  end
386
-
403
+
387
404
  prefix ? @name.sub(prefix + ':', '') : @name
388
-
405
+
389
406
  else
390
407
  @name
391
408
  end
392
-
409
+
393
410
  end
394
-
395
- def next_element()
411
+
412
+ def next_element()
396
413
 
397
414
  id = self.object_id
398
- a = self.parent.elements
415
+ a = self.parent.elements
399
416
 
400
417
  i = a.index {|x| x.object_id == id} + 2
401
418
  a[i] if i < a.length + 1
402
-
419
+
403
420
  end
404
-
421
+
405
422
  alias next_sibling next_element
406
-
423
+
407
424
  def not(bool)
408
425
 
409
426
  r = self.xpath(bool).any?
410
427
 
411
428
  !r
412
429
  end
413
-
414
- def previous_element()
415
-
430
+
431
+ def previous_element()
432
+
416
433
  id = self.object_id
417
- a = self.parent.elements
434
+ a = self.parent.elements
418
435
  i = a.index {|x| x.object_id == id}
419
436
 
420
- a[i] if i > 0
437
+ a[i] if i > 0
421
438
 
422
439
  end
423
-
440
+
424
441
  alias previous_sibling previous_element
425
-
442
+
426
443
  def xpath(path, rlist=[], &blk)
427
-
444
+
428
445
  #@log.debug 'inside xpath ' + path.inspect
429
446
 
430
447
  r = filter_xpath(path, rlist=[], &blk)
431
448
  #@log.debug 'after filter_xpath : ' + r.inspect
432
-
449
+
433
450
  if r.is_a?(Array) then
434
-
451
+
435
452
  Recordset.new(r.compact)
436
-
453
+
437
454
  else
438
455
  r
439
456
  end
440
-
457
+
441
458
  end
442
-
459
+
443
460
  def filter_xpath(raw_path, rlist=[], &blk)
444
461
  #@log.debug 'inside filter_xpath : ' + raw_path.inspect
445
462
  path = String.new raw_path
@@ -449,25 +466,25 @@ class Rexle
449
466
  #fn_match = path.match(/^(\w+)\(/)
450
467
  #@log.debug 'fn_match : ' + fn_match.inspect
451
468
  end_fn_match = path.slice!(/\[\w+\(\)\]$/)
452
-
469
+
453
470
  if end_fn_match then
454
-
471
+
455
472
  m = end_fn_match[1..-4]
456
473
  #@log.debug 'its a function'
457
474
  [method(m.to_sym).call(xpath path)]
458
-
459
- elsif (fn_match and fn_match.captures.first[/^(attribute|@)/])
475
+
476
+ elsif (fn_match and fn_match.captures.first[/^(attribute|@)/])
460
477
 
461
478
  procs = {
462
479
 
463
- Array: proc { |x|
464
- if block_given? then
465
- x.flatten(1)
480
+ Array: proc { |x|
481
+ if block_given? then
482
+ x.flatten(1)
466
483
  else
467
484
  rs = x.flatten
468
- rs.any?{|x| x == true or x == false} ? rs : rs.uniq(&:object_id)
485
+ rs.any?{|x| x == true or x == false} ? rs : rs.uniq(&:object_id)
469
486
  end
470
- },
487
+ },
471
488
  String: proc {|x| x},
472
489
  Hash: proc {|x| x},
473
490
  TrueClass: proc{|x| x},
@@ -476,25 +493,25 @@ class Rexle
476
493
  }
477
494
  bucket = []
478
495
  raw_results = path.split('|').map do |xp|
479
- query_xpath(xp.strip, bucket, &blk)
496
+ query_xpath(xp.strip, bucket, &blk)
480
497
  end
481
-
498
+
482
499
  results = raw_results
483
500
 
484
- procs[results.class.to_s.to_sym].call(results) if results
485
-
501
+ procs[results.class.to_s.to_sym].call(results) if results
502
+
486
503
  elsif fn_match.nil?
487
-
504
+
488
505
  procs = {
489
506
 
490
- Array: proc { |x|
491
- if block_given? then
492
- x.flatten(1)
507
+ Array: proc { |x|
508
+ if block_given? then
509
+ x.flatten(1)
493
510
  else
494
511
  rs = x.flatten
495
- rs.any?{|x| x == true or x == false} ? rs : rs.uniq(&:object_id)
512
+ rs.any?{|x| x == true or x == false} ? rs : rs.uniq(&:object_id)
496
513
  end
497
- },
514
+ },
498
515
  String: proc {|x| x},
499
516
  Hash: proc {|x| x},
500
517
  TrueClass: proc{|x| x},
@@ -502,23 +519,23 @@ class Rexle
502
519
  :"Rexle::Element" => proc {|x| [x]}
503
520
  }
504
521
  bucket = []
505
-
522
+
506
523
  results = if path =~ /[\[]|\(/ then
507
524
 
508
525
  raw_results = path.split(/\|/).map do |xp|
509
- query_xpath(xp.strip, bucket, &blk)
526
+ query_xpath(xp.strip, bucket, &blk)
510
527
  end
511
528
 
512
529
  raw_results.flatten.index(true) ? [true] : []
513
-
530
+
514
531
  else
515
532
  raw_results = path.split(/ *(?:\||\band\b) */).map do |xp|
516
- query_xpath(xp.strip, bucket, &blk)
517
- end
533
+ query_xpath(xp.strip, bucket, &blk)
534
+ end
518
535
 
519
536
  if path =~ / and / then
520
537
 
521
- raw_results.flatten.select {|x| x == true or x == false}
538
+ raw_results.flatten.select {|x| x == true or x == false}
522
539
 
523
540
  else
524
541
  raw_results.flatten.index(true) ? [true] : []
@@ -527,12 +544,12 @@ class Rexle
527
544
 
528
545
  return results if !path[/[><]/] and results.any?
529
546
  results = raw_results # .flatten.select {|x| x}
530
-
531
- procs[results.class.to_s.to_sym].call(results) if results
547
+
548
+ procs[results.class.to_s.to_sym].call(results) if results
532
549
 
533
550
  else
534
-
535
- m, xpath_value, index = fn_match.captures
551
+
552
+ m, xpath_value, index = fn_match.captures
536
553
 
537
554
  if m == 'text' then
538
555
  a = texts()
@@ -546,14 +563,14 @@ class Rexle
546
563
 
547
564
  end
548
565
 
549
- end
550
-
566
+ end
567
+
551
568
  def query_xpath(raw_xpath_value, rlist=[], &blk)
552
569
 
553
570
  #@log.debug 'query_xpath : ' + raw_xpath_value.inspect
554
571
  #@log.debug '++ ' + self.xml.inspect
555
572
 
556
- flag_func = false
573
+ flag_func = false
557
574
 
558
575
  xpath_value = raw_xpath_value.sub('child::','./')
559
576
 
@@ -577,38 +594,38 @@ class Rexle
577
594
 
578
595
  raw_condition = raw_condition ? raw_condition + '/' + remaining_path \
579
596
  : remaining_path
580
- remaining_path = ''
597
+ remaining_path = ''
581
598
  end
582
599
 
583
- r = raw_path[/^([^\/]+)(?=\/\/)/,1]
600
+ r = raw_path[/^([^\/]+)(?=\/\/)/,1]
584
601
 
585
602
  if r then
586
603
  a_path = raw_path.split(/(?=\/\/)/,2)
587
604
  else
588
605
  a_path = raw_path.split('/',2)
589
606
  end
590
-
607
+
591
608
  condition = raw_condition if a_path.length <= 1 #and not raw_condition[/^\[\w+\(.*\)\]$/]
592
609
 
593
610
  if raw_path[0,2] == '//' then
594
611
  s = ''
595
- elsif raw_path == 'text()'
612
+ elsif raw_path == 'text()'
596
613
 
597
614
  a_path.shift
598
615
  #return @value
599
616
  return self.texts
600
617
  else
601
618
 
602
- attribute = xpath_value[/^(attribute::|@)(.*)/,2]
603
-
619
+ attribute = xpath_value[/^(attribute::|@)(.*)/,2]
620
+
604
621
  return @attributes if attribute == '*'
605
-
622
+
606
623
  if attribute and @attributes and \
607
624
  @attributes.has_key?(attribute.to_sym) then
608
625
  return [Attribute.new(@attributes[attribute.to_sym])]
609
626
  end
610
627
  s = a_path.shift
611
- end
628
+ end
612
629
 
613
630
  # isolate the xpath to return just the path to the current element
614
631
 
@@ -624,7 +641,7 @@ class Rexle
624
641
  if element_name and element_name[/^\d/] then
625
642
  element_name = nil
626
643
  end
627
-
644
+
628
645
  condition = raw_xpath_value if element_name.nil?
629
646
 
630
647
  else
@@ -660,11 +677,11 @@ class Rexle
660
677
  r4 = attribute_search(attr_search, self, self.attributes)
661
678
  return r4
662
679
  end
663
-
664
-
680
+
681
+
665
682
  return_elements = []
666
-
667
-
683
+
684
+
668
685
 
669
686
  if raw_path[0,2] == '//' then
670
687
 
@@ -679,25 +696,25 @@ class Rexle
679
696
 
680
697
  if element_name.is_a? String then
681
698
  ename, raw_selector = (element_name.split('::',2)).reverse
682
-
699
+
683
700
  selector = case raw_selector
684
701
  when 'following-sibling' then 1
685
702
  when 'preceding-sibling' then -1
686
703
  end
687
-
704
+
688
705
  else
689
706
  ename = element_name
690
- end
707
+ end
691
708
 
692
709
  if ename == '..' then
693
-
710
+
694
711
  remaining_xpath = raw_path[/\.\.\/(.*)/,1]
695
712
  # select the parent element
696
713
 
697
714
  r2 = self.parent.xpath(remaining_xpath)
698
715
 
699
716
  return r2
700
-
717
+
701
718
  elsif ename == '.'
702
719
 
703
720
  remaining_xpath = raw_path[1..-1]
@@ -706,41 +723,41 @@ class Rexle
706
723
  if xpath_value.length > 0 and xpath_value =~ /\[/ then
707
724
 
708
725
  r = eval(attr_search.sub(/^h/,'self.attributes'))
709
- return self if r
726
+ return self if r
710
727
 
711
728
  else
712
729
  return self
713
730
  end
714
731
  else
715
732
  return self.xpath(remaining_xpath)
716
- end
733
+ end
717
734
 
718
735
  elsif element_name.nil?
719
736
  puts ('attr_search: ' + attr_search.inspect).debug if $debug
720
- return eval attr_search
737
+ return eval attr_search
721
738
  else
722
739
 
723
740
  if raw_selector.nil? and ename != element_part then
724
741
 
725
742
  right_cond = element_part[/#{ename}(.*)/,1]
726
743
 
727
- end
744
+ end
728
745
 
729
746
  return_elements = @child_elements.map.with_index.select do |x, i|
730
747
 
731
748
  next unless x.is_a? Rexle::Element
732
749
 
733
750
  #x.name == ename or (ename == '*')
734
-
751
+
735
752
  r10 = ((x.name == ename) or (ename == '*'))
736
753
 
737
-
754
+
738
755
 
739
756
  end
740
-
757
+
741
758
  if right_cond then
742
-
743
-
759
+
760
+
744
761
  r12 = return_elements.map do |x, i|
745
762
 
746
763
  if x.text then
@@ -750,15 +767,15 @@ class Rexle
750
767
  else
751
768
  false
752
769
  end
753
-
770
+
754
771
  end
755
-
772
+
756
773
  return r12
757
-
758
- end
759
-
774
+
775
+ end
776
+
760
777
  if selector then
761
- ne = return_elements.inject([]) do |r,x|
778
+ ne = return_elements.inject([]) do |r,x|
762
779
  i = x.last + selector
763
780
  if i >= 0 then
764
781
  r << i
@@ -769,17 +786,17 @@ class Rexle
769
786
 
770
787
  return_elements = ne.map {|x| [@child_elements[x], x] if x}
771
788
  end
772
-
789
+
773
790
 
774
791
  end
775
792
  end
776
-
793
+
777
794
  if return_elements.length > 0 then
778
795
 
779
796
  if (a_path + [remaining_path]).join.empty? then
780
797
 
781
798
  # pass in a block to the filter if it is function contains?
782
- rlist = return_elements.map.with_index do |x,i|
799
+ rlist = return_elements.map.with_index do |x,i|
783
800
  r5 = filter(x, i+1, attr_search, &blk)
784
801
 
785
802
  r5
@@ -789,9 +806,9 @@ class Rexle
789
806
 
790
807
  else
791
808
 
792
- rlist << return_elements.map.with_index do |x,i|
809
+ rlist << return_elements.map.with_index do |x,i|
793
810
 
794
- rtn_element = filter(x, i+1, attr_search) do |e|
811
+ rtn_element = filter(x, i+1, attr_search) do |e|
795
812
 
796
813
  r = e.xpath(a_path.join('/') + raw_condition.to_s \
797
814
  + remaining_path, &blk)
@@ -837,7 +854,7 @@ class Rexle
837
854
  rlist,&blk)
838
855
  end
839
856
  end
840
-
857
+
841
858
  rlist = rlist.flatten(1) unless not(rlist.is_a? Array) \
842
859
  or (rlist.length > 1 and rlist[0].is_a? Array)
843
860
  rlist = [rlist] if rlist.is_a? Rexle::Element
@@ -854,21 +871,21 @@ class Rexle
854
871
  elsif item.is_a? Rexle::CData then
855
872
  @child_elements << item
856
873
  elsif item.is_a? Rexle::Comment then
857
- @child_elements << item
874
+ @child_elements << item
858
875
  elsif item.is_a? Rexle::Element then
859
876
 
860
877
  @child_elements << item
861
878
  # add a reference from this element (the parent) to the child
862
879
  item.parent = self
863
- item
864
-
880
+ item
881
+
865
882
  elsif item.is_a? Rexle then
866
883
  self.add_element(item.root)
867
884
  end
868
885
 
869
- end
886
+ end
870
887
 
871
- def add(item)
888
+ def add(item)
872
889
 
873
890
  if item.is_a? Rexle::Element then
874
891
 
@@ -894,13 +911,13 @@ class Rexle
894
911
  "%s ... </>" % self.xml[/<[^>]+>/]
895
912
  else
896
913
  self.xml
897
- end
914
+ end
898
915
  end
899
916
 
900
917
  def add_attribute(*x)
901
-
918
+
902
919
  proc_hash = lambda {|x| Hash[*x]}
903
-
920
+
904
921
  procs = {
905
922
  Hash: lambda {|x| x[0] || {}},
906
923
  String: proc_hash,
@@ -918,57 +935,57 @@ class Rexle
918
935
  def add_text(s)
919
936
 
920
937
  self.child_elements << s
921
- self
938
+ self
922
939
  end
923
-
924
- def attribute(key)
925
-
940
+
941
+ def attribute(key)
942
+
926
943
  key = key.to_sym if key.is_a? String
927
-
944
+
928
945
  if @attributes[key].is_a? String then
929
- @attributes[key].gsub('&lt;','<').gsub('&gt;','>')
946
+ @attributes[key].gsub('&lt;','<').gsub('&gt;','>')
930
947
  else
931
948
  @attributes[key]
932
949
  end
933
- end
934
-
935
- def attributes() @attributes end
936
-
950
+ end
951
+
952
+ def attributes() @attributes end
953
+
937
954
  def cdatas()
938
955
  self.children.inject([]){|r,x| x.is_a?(Rexle::CData) ? r << x.to_s : r }
939
956
  end
940
-
957
+
941
958
  def children()
942
959
 
943
960
  r = @child_elements
944
-
961
+
945
962
  def r.is_an_empty_string?()
946
963
  self.length == 1 and self.first == ''
947
- end
948
-
964
+ end
965
+
949
966
  return r
950
- end
967
+ end
951
968
 
952
969
  def children=(a) @child_elements = a if a.is_a? Array end
953
-
970
+
954
971
  def deep_clone() Rexle.new(self.xml).root end
955
-
956
- def clone()
957
- Element.new(@name, attributes: Marshal.load( Marshal.dump(@attributes)))
972
+
973
+ def clone()
974
+ Element.new(@name, attributes: Marshal.load( Marshal.dump(@attributes)))
958
975
  end
959
-
976
+
960
977
  def delete(obj=nil)
961
978
 
962
979
  if obj then
963
980
 
964
981
  if obj.is_a? String then
965
-
982
+
966
983
  self.xpath(obj).each {|e| e.delete; e = nil}
967
-
984
+
968
985
  else
969
986
 
970
987
  i = @child_elements.index(obj)
971
- [@child_elements].each{|x| x.delete_at i} if i
988
+ [@child_elements].each{|x| x.delete_at i} if i
972
989
  end
973
990
  else
974
991
 
@@ -990,50 +1007,50 @@ class Rexle
990
1007
  String: proc {|x| @child_elements[x]}
991
1008
  }
992
1009
 
993
- procs[s.class.to_s.to_sym].call(s)
1010
+ procs[s.class.to_s.to_sym].call(s)
994
1011
  end
995
1012
 
996
1013
  def doc_root() @rexle.root end
997
1014
  def each(&blk) self.children.each(&blk) end
998
1015
  def each_recursive(&blk) recursive_scan(self.children,&blk) end
999
1016
  alias traverse each_recursive
1000
- def has_elements?() !self.elements.empty? end
1001
- def insert_after(node) insert(node, 1) end
1017
+ def has_elements?() !self.elements.empty? end
1018
+ def insert_after(node) insert(node, 1) end
1002
1019
  def insert_before(node) insert(node) end
1003
1020
  def last(a) a.last end
1004
- def map(&blk) self.children.map(&blk) end
1005
-
1021
+ def map(&blk) self.children.map(&blk) end
1022
+
1006
1023
  def plaintext()
1007
1024
  CGI.unescapeHTML xml().gsub(/<\/?[^>]+>/,'').gsub('&nbsp;',' ')\
1008
1025
  .gsub(/\n\s+/,' ')
1009
1026
  end
1010
-
1011
- def root() self end
1027
+
1028
+ def root() self end
1012
1029
 
1013
1030
  def text(s='')
1014
-
1015
- return self.value if s.empty?
1016
-
1031
+
1032
+ return self.value if s.empty?
1033
+
1017
1034
  e = self.element(s)
1018
1035
  return e if e.is_a? String
1019
-
1036
+
1020
1037
  e.value if e
1021
1038
  end
1022
-
1039
+
1023
1040
  def texts()
1024
1041
 
1025
1042
  r = @child_elements.select do |x|
1026
1043
  x.is_a? String or x.is_a? Rexle::CData
1027
1044
  end
1028
-
1045
+
1029
1046
  r.map do |x|
1030
1047
  def x.unescape()
1031
1048
  s = self.to_s.clone
1032
1049
  %w(&lt; < &gt; > &amp; & &apos; ').each_slice(2){|x| s.gsub!(*x)}
1033
1050
  s
1034
- end
1051
+ end
1035
1052
  end
1036
-
1053
+
1037
1054
  return r
1038
1055
  end
1039
1056
 
@@ -1041,20 +1058,20 @@ class Rexle
1041
1058
 
1042
1059
  r = @child_elements.first
1043
1060
  return nil unless r.is_a? String
1044
-
1061
+
1045
1062
  def r.unescape()
1046
1063
  s = self.clone
1047
1064
  %w(&lt; < &gt; > &amp; & &apos; ').each_slice(2){|x| s.gsub!(*x)}
1048
1065
  s
1049
- end
1050
-
1066
+ end
1067
+
1051
1068
  return r
1052
1069
  end
1053
-
1070
+
1054
1071
  def value=(raw_s)
1055
1072
 
1056
1073
  val = Value.new(raw_s.to_s.clone)
1057
-
1074
+
1058
1075
  escape_chars = %w(& &amp; ' &apos; < &lt; > &gt;).each_slice(2).to_a
1059
1076
  escape_chars.each{|x| val.gsub!(*x)}
1060
1077
 
@@ -1064,9 +1081,15 @@ class Rexle
1064
1081
  end
1065
1082
 
1066
1083
  alias text= value=
1067
-
1084
+
1068
1085
  def to_a()
1086
+
1069
1087
  e = [String.new(self.name), Hash.new(self.attributes)]
1088
+
1089
+ if self.cdatas.any? then
1090
+ e.concat self.cdatas.map {|cdata| ['![', {}, cdata] }
1091
+ end
1092
+
1070
1093
  [*e, *scan_to_a(self.children)]
1071
1094
  end
1072
1095
 
@@ -1076,10 +1099,10 @@ class Rexle
1076
1099
  Hash: lambda {|x|
1077
1100
  o = {pretty: false}.merge(x)
1078
1101
  msg = o[:pretty] == false ? :doc_print : :doc_pretty_print
1079
-
1102
+
1080
1103
  method(msg).call(self.children)
1081
1104
  },
1082
- String: lambda {|x|
1105
+ String: lambda {|x|
1083
1106
  r = self.element(x)
1084
1107
  r ? r.xml : ''
1085
1108
  }
@@ -1092,18 +1115,18 @@ class Rexle
1092
1115
  end
1093
1116
 
1094
1117
  def prepend(item)
1095
-
1118
+
1096
1119
  @child_elements.unshift item
1097
-
1120
+
1098
1121
  # add a reference from this element (the parent) to the child
1099
1122
  item.parent = self
1100
- item
1101
- end
1102
-
1123
+ item
1124
+ end
1125
+
1103
1126
  alias to_s xml
1104
1127
 
1105
1128
  private
1106
-
1129
+
1107
1130
  def insert(node,offset=0)
1108
1131
 
1109
1132
  i = parent.child_elements.index(self)
@@ -1115,7 +1138,7 @@ class Rexle
1115
1138
  node.instance_variable_set(:@doc_id, self.doc_root.object_id)
1116
1139
 
1117
1140
  self
1118
- end
1141
+ end
1119
1142
 
1120
1143
  def format_condition(condition)
1121
1144
 
@@ -1140,21 +1163,21 @@ class Rexle
1140
1163
  elsif raw_items[0][/^not\(/]
1141
1164
 
1142
1165
  return raw_items[0]
1143
-
1166
+
1144
1167
  else
1145
1168
 
1146
1169
  andor_items = raw_items.map.with_index\
1147
1170
  .select{|x,i| x[/\band\b|\bor\b/]}\
1148
1171
  .map{|x| [x.last, x.last + 1]}.flatten
1149
-
1172
+
1150
1173
  indices = [0] + andor_items + [raw_items.length]
1151
1174
 
1152
1175
  if raw_items[0][0] == '@' then
1153
1176
 
1154
1177
  raw_items.each{|x| x.gsub!(/^@/,'')}
1155
- cons_items = indices.each_cons(2).map{|x,y| raw_items.slice(x...y)}
1178
+ cons_items = indices.each_cons(2).map{|x,y| raw_items.slice(x...y)}
1156
1179
 
1157
- items = cons_items.map do |x|
1180
+ items = cons_items.map do |x|
1158
1181
 
1159
1182
  if x.length >= 3 then
1160
1183
  if x[0] != 'class' then
@@ -1173,17 +1196,17 @@ class Rexle
1173
1196
  else
1174
1197
 
1175
1198
  cons_items = indices.each_cons(2).map{|x,y| raw_items.slice(x...y)}
1176
-
1177
- items = cons_items.map do |x|
1199
+
1200
+ items = cons_items.map do |x|
1178
1201
 
1179
1202
  if x.length >= 3 then
1180
1203
 
1181
1204
  x[1] = '==' if x[1] == '='
1182
1205
  if x[0] != '.' then
1183
1206
  if x[0][/\//] then
1184
-
1207
+
1185
1208
  path, value = x.values_at(0,-1)
1186
-
1209
+
1187
1210
  if x[0][/@\w+$/] then
1188
1211
  "r = e.xpath('#{path}').first; r and r.value == #{value}"
1189
1212
  else
@@ -1207,16 +1230,16 @@ class Rexle
1207
1230
 
1208
1231
 
1209
1232
  end
1210
-
1233
+
1211
1234
  def scan_match(node, path)
1212
-
1235
+
1213
1236
  if path == '//' then
1214
- return [node, node.text,
1237
+ return [node, node.text,
1215
1238
  node.elements.map {|x| scan_match x, path}]
1216
1239
  end
1217
-
1240
+
1218
1241
  r = []
1219
- xpath2 = path[2..-1]
1242
+ xpath2 = path[2..-1]
1220
1243
  #jr150316 xpath2.sub!(/^\*\//,'')
1221
1244
  #jr150316xpath2.sub!(/^\*/,self.name)
1222
1245
  #jr150316xpath2.sub!(/^\w+/,'').sub!(/^\//,'') if xpath2[/^\w+/] == self.name
@@ -1239,17 +1262,17 @@ class Rexle
1239
1262
  end
1240
1263
  a
1241
1264
  end
1242
-
1243
-
1265
+
1266
+
1244
1267
  def filter(raw_element, i, attr_search, &blk)
1245
-
1268
+
1246
1269
  x, index = raw_element
1247
1270
  e = @child_elements[index]
1248
1271
 
1249
1272
  return unless e.is_a? Rexle::Element
1250
1273
  name, value = e.name, e.value if e.is_a? Rexle::Element
1251
1274
 
1252
- h = x.attributes # <-- fetch the attributes
1275
+ h = x.attributes # <-- fetch the attributes
1253
1276
 
1254
1277
  if attr_search then
1255
1278
 
@@ -1265,21 +1288,21 @@ class Rexle
1265
1288
  def attribute_search(attr_search, e, h, i=nil, &blk)
1266
1289
 
1267
1290
  r2 = if attr_search.is_a? Integer then
1268
- block_given? ? blk.call(e) : e if i == attr_search
1291
+ block_given? ? blk.call(e) : e if i == attr_search
1269
1292
  elsif attr_search[/i\s(?:<|>|==|%)\s\d+/] and eval(attr_search) then
1270
- block_given? ? blk.call(e) : e
1293
+ block_given? ? blk.call(e) : e
1271
1294
  elsif h and !h.empty? and attr_search[/^h\[/] and eval(attr_search) then
1272
1295
  block_given? ? blk.call(e) : e
1273
- elsif attr_search[/^\(name ==/] and e.child_elements.select {|x|
1296
+ elsif attr_search[/^\(name ==/] and e.child_elements.select {|x|
1274
1297
  next unless x.is_a? Rexle::Element
1275
1298
  name, attributes, value = x.name, x.attributes, x.value.to_s
1276
1299
  b = eval(attr_search)
1277
1300
  b}.length > 0
1278
1301
 
1279
1302
  block_given? ? blk.call(e) : e
1280
-
1281
- elsif attr_search[/^\(name ==/] and eval(attr_search)
1282
- block_given? ? blk.call(e) : e
1303
+
1304
+ elsif attr_search[/^\(name ==/] and eval(attr_search)
1305
+ block_given? ? blk.call(e) : e
1283
1306
  elsif attr_search[/^e\.value/]
1284
1307
 
1285
1308
  v = attr_search[/[^\s]+$/]
@@ -1293,92 +1316,92 @@ class Rexle
1293
1316
  block_given? ? blk.call(e) : e
1294
1317
  elsif attr_search[/^\w*\(/] and e.element(attr_search)
1295
1318
  block_given? ? blk.call(e) : e
1296
- end
1319
+ end
1297
1320
 
1298
1321
  r2
1299
1322
  end
1300
-
1323
+
1301
1324
  def recursive_scan(nodes, &blk)
1302
-
1325
+
1303
1326
  nodes.each do |x|
1304
1327
 
1305
1328
  if x.is_a? Rexle::Element then
1306
1329
  blk.call(x)
1307
1330
  recursive_scan(x.children, &blk) if x.children.length > 0
1308
- end
1331
+ end
1309
1332
  end
1310
1333
  end
1311
-
1334
+
1312
1335
  end # -- end of element --
1313
-
1336
+
1314
1337
 
1315
1338
  class CData
1316
-
1339
+
1317
1340
  def initialize(val='')
1318
1341
  @value = val
1319
1342
  end
1320
-
1343
+
1321
1344
  def clone()
1322
1345
  CData.new(@value)
1323
1346
  end
1324
-
1347
+
1325
1348
  def inspect()
1326
1349
  @value.inspect
1327
1350
  end
1328
-
1351
+
1329
1352
  def print()
1330
1353
  "<![CDATA[%s]]>" % @value
1331
1354
  end
1332
-
1355
+
1333
1356
  def to_s()
1334
1357
  @value
1335
1358
  end
1336
-
1359
+
1337
1360
  def unescape()
1338
1361
  s = @value.clone
1339
1362
  %w(&lt; < &gt; > &amp; & &apos; ').each_slice(2){|x| s.gsub!(*x)}
1340
1363
  s
1341
- end
1342
-
1364
+ end
1365
+
1343
1366
  end
1344
-
1345
-
1367
+
1368
+
1346
1369
  class Comment
1347
-
1370
+
1348
1371
 
1349
1372
  def initialize(val='')
1350
1373
  @e = Element.new('_').add_text val
1351
1374
  @value = val
1352
1375
  end
1353
-
1376
+
1354
1377
  def add_element(e2)
1355
1378
  @e.add e2
1356
1379
  end
1357
-
1380
+
1358
1381
  def add_text(t)
1359
1382
  @e.add_text t
1360
1383
  end
1361
-
1384
+
1362
1385
  def inspect()
1363
1386
  @value
1364
1387
  end
1365
-
1388
+
1366
1389
  def print()
1367
1390
  "<!--%s-->" % @e.root.xpath('//./text()').join
1368
1391
  end
1369
-
1392
+
1370
1393
  def texts()
1371
1394
  @e.texts
1372
1395
  end
1373
-
1396
+
1374
1397
  def to_s()
1375
1398
  @value
1376
1399
  end
1377
1400
  end
1378
-
1401
+
1379
1402
  class Elements
1380
1403
  include Enumerable
1381
-
1404
+
1382
1405
  def initialize(elements=[])
1383
1406
  super()
1384
1407
  @elements = elements
@@ -1390,63 +1413,63 @@ class Rexle
1390
1413
  i = raw_i - 1
1391
1414
  @elements[i]
1392
1415
  end
1393
-
1416
+
1394
1417
  def each(&blk) @elements.each(&blk) end
1395
1418
  def empty?() @elements.empty? end
1396
-
1419
+
1397
1420
  def index(e=nil, &blk)
1398
-
1421
+
1399
1422
  if block_given? then
1400
1423
  @elements.index(&blk)
1401
1424
  else
1402
1425
  @elements.index e
1403
1426
  end
1404
1427
  end
1405
-
1428
+
1406
1429
  def last() @elements.last end
1407
1430
  def length() @elements.length end
1408
1431
  def to_a() @elements end
1409
-
1432
+
1410
1433
  end # -- end of elements --
1411
1434
 
1412
1435
 
1413
1436
  def parse(x=nil)
1414
-
1437
+
1415
1438
  a = []
1416
-
1439
+
1417
1440
  if x then
1418
1441
  procs = {
1419
1442
  String: proc {|x| parse_string(x)},
1420
1443
  Array: proc {|x| x}
1421
1444
  }
1422
1445
  a = procs[x.class.to_s.to_sym].call(x)
1423
- else
1446
+ else
1424
1447
  a = yield
1425
1448
  end
1426
-
1449
+
1427
1450
  doc_node = ['doc',Attributes.new]
1428
1451
  @a = procs[x.class.to_s.to_sym].call(x)
1429
1452
  @doc = scan_element(*(doc_node << @a))
1430
-
1453
+
1431
1454
  self
1432
1455
  end
1433
1456
 
1434
1457
  def add_attribute(x) @doc.attribute(x) end
1435
1458
  def attribute(key) @doc.attribute(key) end
1436
1459
  def attributes() @doc.attributes end
1437
-
1438
- def add_element(element)
1439
1460
 
1440
- if @doc then
1461
+ def add_element(element)
1462
+
1463
+ if @doc then
1441
1464
  raise 'attempted adding second root element to document' if @doc.root
1442
- @doc.root.add_element(element)
1465
+ @doc.root.add_element(element)
1443
1466
  else
1444
- doc_node = ['doc', Attributes.new, element.to_a]
1445
- @doc = scan_element(*doc_node)
1467
+ doc_node = ['doc', Attributes.new, element.to_a]
1468
+ @doc = scan_element(*doc_node)
1446
1469
  end
1447
1470
  element
1448
1471
  end
1449
-
1472
+
1450
1473
  def add_text(s) end
1451
1474
 
1452
1475
  alias add add_element
@@ -1456,26 +1479,26 @@ class Rexle
1456
1479
  @doc.xpath(xpath).each {|e| e.delete; e = nil }
1457
1480
 
1458
1481
  end
1459
-
1482
+
1460
1483
  alias remove delete
1461
1484
 
1462
- def element(xpath) self.xpath(xpath).first end
1485
+ def element(xpath) self.xpath(xpath).first end
1463
1486
  def elements(s=nil) @doc.elements(s) end
1464
1487
  def name() @doc.root.name end
1465
1488
  def to_a() @a end
1466
-
1467
- def to_s(options={})
1489
+
1490
+ def to_s(options={})
1468
1491
  return '<UNDEFINED/>' unless @doc
1469
- self.xml options
1492
+ self.xml options
1470
1493
  end
1471
-
1494
+
1472
1495
  def text(xpath) @doc.text(xpath) end
1473
- def root()
1474
- @doc.elements.first
1496
+ def root()
1497
+ @doc.elements.first
1475
1498
  end
1476
1499
 
1477
- def write(f)
1478
- f.write xml
1500
+ def write(f)
1501
+ f.write xml
1479
1502
  end
1480
1503
 
1481
1504
  def xml(options={})
@@ -1488,7 +1511,7 @@ class Rexle
1488
1511
 
1489
1512
  if o[:declaration] == true then
1490
1513
 
1491
- unless @instructions.assoc 'xml' then
1514
+ unless @instructions and @instructions.assoc 'xml' then
1492
1515
  @instructions.unshift ["xml","version='1.0' encoding='UTF-8'"]
1493
1516
  end
1494
1517
  end
@@ -1504,14 +1527,14 @@ class Rexle
1504
1527
  private
1505
1528
 
1506
1529
  def parse_rexle(x)
1507
-
1530
+
1508
1531
  rp = RexleParser.new(x)
1509
1532
  a = rp.to_a
1510
1533
 
1511
1534
  @instructions = rp.instructions
1512
- return a
1535
+ return a
1513
1536
  end
1514
-
1537
+
1515
1538
  def parse_string(x)
1516
1539
 
1517
1540
  # check if the XML string is a dynarex document
@@ -1527,50 +1550,50 @@ class Rexle
1527
1550
  'polyrex' => proc {|x| parse_rexle(x)}
1528
1551
  }
1529
1552
  other_parser = procs[recordx_type]
1530
-
1553
+
1531
1554
  if other_parser then
1532
-
1555
+
1533
1556
  begin
1534
1557
  other_parser.call(x)
1535
1558
  rescue
1536
1559
  parse_rexle x
1537
1560
  end
1538
-
1561
+
1539
1562
  else
1540
-
1563
+
1541
1564
  parse_rexle x
1542
-
1543
- end
1544
-
1565
+
1566
+ end
1567
+
1545
1568
  else
1546
1569
 
1547
1570
  parse_rexle x
1548
-
1571
+
1549
1572
  end
1550
1573
  else
1551
1574
 
1552
1575
  parse_rexle x
1553
-
1576
+
1554
1577
  end
1555
1578
 
1556
1579
  end
1557
-
1580
+
1558
1581
  def scan_element(name=nil, attributes=nil, *children)
1559
-
1582
+
1560
1583
  return unless name
1561
-
1584
+
1562
1585
  return Rexle::CData.new(children.first) if name == '!['
1563
1586
  return Rexle::Comment.new(children.first) if name == '!-'
1564
1587
 
1565
- element = Rexle::Element.new(name, attributes: attributes, rexle: @rexle)
1588
+ element = Rexle::Element.new(name, attributes: attributes, rexle: @rexle)
1566
1589
 
1567
1590
  if children then
1568
1591
 
1569
1592
  children.each do |x4|
1570
-
1593
+
1571
1594
 
1572
1595
  if x4.is_a? Array then
1573
- element.add_element scan_element(*x4)
1596
+ element.add_element scan_element(*x4)
1574
1597
  elsif x4.is_a? String then
1575
1598
 
1576
1599
  e = if x4.is_a? String then
@@ -1579,22 +1602,22 @@ class Rexle
1579
1602
  elsif x4.name == '![' then
1580
1603
 
1581
1604
  Rexle::CData.new(x4)
1582
-
1605
+
1583
1606
  elsif x4.name == '!-' then
1584
1607
 
1585
1608
  Rexle::Comment.new(x4)
1586
-
1609
+
1587
1610
  end
1588
1611
 
1589
1612
  element.add_element e
1590
1613
  end
1591
1614
  end
1592
1615
  end
1593
-
1616
+
1594
1617
  return element
1595
1618
  end
1596
1619
 
1597
-
1620
+
1598
1621
  # scan a rexml doc
1599
1622
  #
1600
1623
  def scan_doc(node)
@@ -1602,28 +1625,28 @@ class Rexle
1602
1625
  attributes = node.attributes.inject({}){|r,x| r.merge(Hash[*x])}
1603
1626
  [node.name, node.text.to_s, attributes, *children]
1604
1627
  end
1605
-
1628
+
1606
1629
  class Recordset < Array
1607
1630
 
1608
1631
  def initialize(a)
1609
1632
  super(a)
1610
1633
  end
1611
-
1634
+
1612
1635
  def to_doc(root: 'root')
1613
-
1636
+
1614
1637
  recordset = self.map(&:to_a)
1615
1638
  Rexle.new([root,{}, *recordset])
1616
-
1639
+
1617
1640
  end
1618
-
1641
+
1619
1642
  def xpath(xpath)
1620
1643
  self.to_doc.root.xpath(xpath)
1621
1644
  end
1622
-
1645
+
1623
1646
  def element(xpath)
1624
1647
  self.to_doc.root.element(xpath)
1625
1648
  end
1626
1649
 
1627
- end
1628
-
1650
+ end
1651
+
1629
1652
  end