rexle 0.9.14 → 0.9.15

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 (2) hide show
  1. data/lib/rexle.rb +108 -71
  2. metadata +2 -2
@@ -11,6 +11,8 @@ include REXML
11
11
 
12
12
 
13
13
  # modifications:
14
+ # 21-Dec-2011: Bug fix: xpath modified to allow querying from the actual
15
+ # root rather than the 1st child element from the root
14
16
  # 04-Sep-2011: Bug fix: xpath will now only return Rexle:elements when
15
17
  # * is used.
16
18
  # 03-Sep-2011: Implemented deep_clone as well as modifying clone to function
@@ -26,6 +28,7 @@ module XMLhelper
26
28
  body = children.empty? ? self.root.value : scan_print(children).join
27
29
  a = self.root.attributes.to_a.map{|k,v| "%s='%s'" % [k,v]}
28
30
  "<%s%s>%s</%s>" % [self.root.name, a.empty? ? '' : ' ' + a.join(' '), body, self.root.name]
31
+ #"<%s%s>%s</%s>" % [self.root.name, a.empty? ? '' : ' ' + a.join(' '), body]
29
32
  end
30
33
 
31
34
  def doc_pretty_print(children)
@@ -39,9 +42,9 @@ module XMLhelper
39
42
  def scan_print(nodes)
40
43
 
41
44
  nodes.map do |x|
42
- #puts 'x: ' + x.class.to_s #+ ' name: ' + x.name.to_s
45
+
43
46
  if x.is_a? Rexle::Element then
44
- unless x.name == '![' then
47
+ if x.name.chr != '!' then
45
48
  a = x.attributes.to_a.map{|k,v| "%s='%s'" % [k,v]}
46
49
  tag = x.name + (a.empty? ? '' : ' ' + a.join(' '))
47
50
 
@@ -49,8 +52,10 @@ module XMLhelper
49
52
  out << x.value unless x.value.nil? || x.value.empty?
50
53
  out << scan_print(x.children)
51
54
  out << "</%s>" % x.name
52
- else
53
- "<![CDATA[%s]]>" % x.value
55
+ elsif x.name == '!-' then
56
+ "<!--%s-->" % x.value
57
+ else
58
+ "<![CDATA[%s]]>" % x.value
54
59
  end
55
60
  elsif x.is_a? String then
56
61
  x
@@ -91,7 +96,8 @@ class Rexle
91
96
  include XMLhelper
92
97
 
93
98
  attr_reader :prefixes
94
-
99
+
100
+ def self.version() "1.1.1" end
95
101
  def initialize(x=nil)
96
102
  super()
97
103
 
@@ -103,13 +109,13 @@ class Rexle
103
109
  :"REXML::Document" => proc {|x| scan_doc x.root}
104
110
  }
105
111
 
112
+ doc_node = ['doc','',{}]
106
113
  @a = procs[x.class.to_s.to_sym].call(x)
107
- @doc = scan_element(*@a)
114
+ @doc = scan_element(*(doc_node << @a))
108
115
 
109
116
  # fetch the namespaces
110
117
  @prefixes = []
111
118
  if @doc.root.attributes then
112
- #puts 'attrs : ' + @doc.root.attributes.inspect
113
119
  xmlns = @doc.root.attributes.select {|k,v| k[/^xmlns:/]}
114
120
  @prefixes = xmlns.keys.map{|x| x[/\w+$/]}
115
121
  end
@@ -117,31 +123,9 @@ class Rexle
117
123
 
118
124
  end
119
125
 
120
- def xpath(path, &blk)
121
-
122
- # is it a function
123
- fn_match = path.match(/^(\w+)\(([^\)]+)\)$/)
124
-
125
- # Array: proc {|x| x.flatten.compact},
126
- if (fn_match and fn_match.captures.first[/^(attribute|@)/]) or fn_match.nil? then
127
- procs = {
128
- Array: proc {|x| block_given? ? x : x.flatten },
129
- String: proc {|x| x},
130
- :"Rexle::Element" => proc {|x| [x]}
131
- }
132
- bucket = []
133
- result = @doc.xpath(path, bucket, &blk)
134
-
135
- procs[result.class.to_s.to_sym].call(result)
136
-
137
- else
138
- #puts 'fn ' + fn_match.captures.inspect
139
- m, xpath_value = fn_match.captures
140
- method(m.to_sym).call(xpath_value)
141
- end
142
-
143
-
144
- end
126
+ def xpath(path, &blk)
127
+ @doc.xpath(path, &blk)
128
+ end
145
129
 
146
130
  class Element
147
131
  include XMLhelper
@@ -160,29 +144,74 @@ class Rexle
160
144
  @child_lookup = []
161
145
  end
162
146
 
147
+ def count(path)
148
+ length = query_xpath(path).flatten.compact.length
149
+ length
150
+ end
151
+
152
+ def max(path) query_xpath(path).flatten.compact.map(&:to_i).max end
153
+
163
154
  def name()
164
- #puts 'zzz : ' + @rexle.prefixes.inspect
165
- #puts '@rexle : ' + @rexle.inspect
155
+
166
156
  if @rexle then
167
157
  prefix = @rexle.prefixes.find {|x| x == @name[/^(\w+):/,1] } if @rexle.prefixes.is_a? Array
168
- #puts 'ppp: ' + prefix.inspect
169
158
  prefix ? @name.sub(prefix + ':', '') : @name
170
159
  else
171
160
  @name
172
161
  end
173
162
  end
174
163
 
175
- def xpath(xpath_value, rlist=[], &blk)
164
+ def xpath(path, rlist=[], &blk)
165
+ filter_xpath(path, rlist=[], &blk)
166
+ end
167
+
168
+ def filter_xpath(path, rlist=[], &blk)
169
+
170
+ # is it a function
171
+ fn_match = path.match(/^(\w+)\(([^\)]+)\)$/)
172
+
173
+ # Array: proc {|x| x.flatten.compact},
174
+ if (fn_match and fn_match.captures.first[/^(attribute|@)/]) or fn_match.nil? then
175
+ procs = {
176
+ Array: proc {|x| block_given? ? x : x.flatten },
177
+ String: proc {|x| x},
178
+ TrueClass: proc{|x| x},
179
+ FalseClass: proc{|x| x},
180
+ :"Rexle::Element" => proc {|x| [x]}
181
+ }
182
+ bucket = []
183
+ result = query_xpath(path, bucket, &blk)
184
+ procs[result.class.to_s.to_sym].call(result)
185
+
186
+ else
176
187
 
177
- #remove any prefixes
188
+ m, xpath_value = fn_match.captures
189
+ method(m.to_sym).call(xpath_value)
190
+ end
191
+
192
+ end
193
+
194
+ def query_xpath(raw_xpath_value, rlist=[], &blk)
195
+
196
+ #remove any pre'fixes
178
197
  #@rexle.prefixes.each {|x| xpath_value.sub!(x + ':','') }
198
+ flag_func = false
199
+
200
+ xpath_value = raw_xpath_value.sub(/^\[/,'*[')
201
+
202
+ if xpath_value[/^[\w\/]+\s*=.*/] then
203
+ flag_func = true
204
+ xpath_value = raw_xpath_value.sub(/^\w+\s*=.*/,'.[\0]')
205
+ xpath_value = raw_xpath_value.sub(/\/([\w]+\s*=.*)/,'[\1]')
206
+ #result = self.element xpath_value
207
+ #return [(result.is_a?(Rexle::Element) ? true : false)]
208
+ end
179
209
 
180
- xpath_value.sub!(/^\[/,'*[')
181
- #xpath_value.sub!(/^attribute::/,'*/attribute::')
182
210
  raw_path, raw_condition = xpath_value.sub(/^\/(?!\/)/,'').match(/([^\[]+)(\[[^\]]+\])?/).captures
183
211
 
184
212
  remaining_path = ($').to_s
185
213
  a_path = raw_path.split('/')
214
+
186
215
  condition = raw_condition if a_path.length <= 1
187
216
 
188
217
  if raw_path[0,2] == '//' then
@@ -196,15 +225,17 @@ class Rexle
196
225
  return [@attributes[attribute.to_sym]] if attribute and @attributes and @attributes.has_key?(attribute.to_sym)
197
226
 
198
227
  s = a_path.shift
228
+
199
229
  end
200
230
 
201
231
  # isolate the xpath to return just the path to the current element
202
232
  elmnt_path = s[/^([\w\*]+\[[^\]]+\])|[\/]+{,2}[^\/]+/]
233
+
203
234
  element_part = elmnt_path[/(^@?[^\[]+)?/,1] if elmnt_path
204
235
 
205
236
  if element_part then
206
237
  unless element_part[/^@/] then
207
- element_name = element_part
238
+ element_name = element_part[/^[\w\*]+/]
208
239
  else
209
240
  condition = element_part
210
241
  element_name = nil
@@ -212,27 +243,28 @@ class Rexle
212
243
 
213
244
  end
214
245
 
215
- #element_name ||= '*'
216
246
  raw_condition = '' if condition
217
247
 
218
248
  attr_search = format_condition(condition) if condition and condition.length > 0
219
-
249
+
250
+ return_elements = []
251
+
220
252
  if raw_path[0,2] == '//'
221
253
  rs = scan_match(self, xpath_value).flatten.compact
222
254
  return rs
223
255
  else
224
256
 
225
- return_elements = @child_lookup.map.with_index.select do |x|
226
- x[0][0] == element_name or (element_name == '*' && x[0].is_a?(Array))
227
- end
228
-
257
+ return_elements = @child_lookup.map.with_index.select do |x|
258
+ (x[0][0] == element_name || element_name == '.') or \
259
+ (element_name == '*' && x[0].is_a?(Array))
260
+ end
229
261
  end
230
262
 
231
263
  if return_elements.length > 0 then
232
264
 
233
265
  if (a_path + [remaining_path]).join.empty? then
234
-
235
266
  rlist = return_elements.map.with_index {|x,i| filter(x, i+1, attr_search, &blk)}.compact
267
+
236
268
  rlist = rlist[0] if rlist.length == 1
237
269
  else
238
270
 
@@ -253,6 +285,7 @@ class Rexle
253
285
  rlist = rlist.flatten(1) unless rlist.length > 1 and rlist[0].is_a? Array
254
286
 
255
287
  end
288
+
256
289
  rlist.compact! if rlist.is_a? Array
257
290
 
258
291
  else
@@ -264,9 +297,10 @@ class Rexle
264
297
  self.xpath(new_xpath + raw_condition.to_s + remaining_path, rlist,&blk)
265
298
  end
266
299
  end
267
-
300
+
268
301
  rlist = rlist.flatten(1) unless not(rlist.is_a? Array) or (rlist.length > 1 and rlist[0].is_a? Array)
269
302
  rlist = [rlist] if rlist.is_a? Rexle::Element
303
+ rlist = (rlist.length > 0 ? true : false) if flag_func == true
270
304
  rlist
271
305
  end
272
306
 
@@ -314,7 +348,7 @@ class Rexle
314
348
  def attributes() @attributes end
315
349
  def children() @child_elements end
316
350
  def children=(a) @child_elements = a end
317
- def deep_clone() self.original_clone end
351
+ def deep_clone() Rexle.new(self.xml).root end
318
352
  def clone() Element.new(@name, @value, @attributes) end
319
353
 
320
354
  def delete(obj=nil)
@@ -326,7 +360,10 @@ class Rexle
326
360
  end
327
361
  end
328
362
 
329
- def element(s) self.xpath(s).first end
363
+ def element(s)
364
+ r = self.xpath(s)
365
+ r.is_a?(Array) ? r.first : r
366
+ end
330
367
 
331
368
  def elements(s=nil)
332
369
  procs = {
@@ -349,9 +386,8 @@ class Rexle
349
386
  e = self.element(s)
350
387
  result = e.value if e
351
388
  end
389
+ result = CGI.unescape_html result.to_s
352
390
 
353
- result = CGI.unescape_html result
354
-
355
391
  def result.unescape()
356
392
  s = self.clone
357
393
  %w(&lt; < &gt; > &amp; & &pos; ').each_slice(2){|x| s.gsub!(*x)}
@@ -388,7 +424,7 @@ class Rexle
388
424
  private
389
425
 
390
426
  def format_condition(condition)
391
- #raw_items = condition[1..-1].scan(/\'[^\']*\'|and|or|\d+|[!=]+|[@\w\.\/]+/)
427
+
392
428
  raw_items = condition[1..-1].scan(/\'[^\']*\'|and|or|\d+|[!=<>]+|position\(\)|[@\w\.\/]+/)
393
429
 
394
430
  if raw_items[0][/^\d+$/] then
@@ -411,7 +447,8 @@ class Rexle
411
447
  x[1] = '==' if x[1] == '='
412
448
  "h[:'%s'] %s %s" % x
413
449
  else
414
- x
450
+
451
+ x.join[/^(and|or)$/] ? x : ("h[:'%s']" % x)
415
452
  end
416
453
  end
417
454
 
@@ -422,6 +459,7 @@ class Rexle
422
459
  items = cons_items.map do |x|
423
460
 
424
461
  if x.length >= 3 then
462
+
425
463
  x[1] = '==' if x[1] == '='
426
464
  if x[0] != '.' then
427
465
  if x[0][/\//] then
@@ -429,7 +467,7 @@ class Rexle
429
467
 
430
468
  "e.xpath('#{path}').first.value == #{value}"
431
469
  else
432
- "(name == '%s' and value %s %s)" % [x[0], x[1], x[2]]
470
+ "(name == '%s' and value %s '%s')" % [x[0], x[1], x[2].sub(/^['"](.*)['"]$/,'\1')]
433
471
  end
434
472
  else
435
473
  "e.value %s %s" % [x[1], x[2]]
@@ -438,7 +476,7 @@ class Rexle
438
476
  x
439
477
  end
440
478
  end
441
-
479
+
442
480
  return items.join(' ')
443
481
  end
444
482
  end
@@ -451,17 +489,19 @@ class Rexle
451
489
 
452
490
  r = node.xpath(xpath[2..-1])
453
491
  r << node.children.map {|n| scan_match(n, xpath) if n.is_a? Rexle::Element}
454
- #puts 'r: ' + r.inspect
492
+
455
493
  r
456
494
  end
457
495
 
458
496
  def filter(raw_element, i, attr_search, &blk)
459
497
 
460
498
  x = raw_element
461
- e = @child_elements[x.last]
462
499
 
500
+ e = @child_elements[x.last]
501
+ name, value = e.name, e.value if e.is_a? Rexle::Element
463
502
  h = x[0][1] # <-- fetch the attributes
464
503
 
504
+
465
505
  if attr_search then
466
506
  if attr_search.is_a? Fixnum then
467
507
  block_given? ? blk.call(e) : e if i == attr_search
@@ -469,11 +509,15 @@ class Rexle
469
509
  block_given? ? blk.call(e) : e
470
510
  elsif h and attr_search[/^h\[/] and eval(attr_search)
471
511
  block_given? ? blk.call(e) : e
472
- elsif attr_search[/^\(name ==/] and e.child_lookup.select{|name, attributes, value| eval(attr_search) }.length > 0
512
+ elsif attr_search[/^\(name ==/] and e.child_lookup.select{|name, attributes, value| eval(attr_search) }.length > 0
513
+
473
514
  block_given? ? blk.call(e) : e
515
+ elsif attr_search[/^\(name ==/] and eval(attr_search)
516
+ block_given? ? blk.call(e) : e
474
517
  elsif attr_search[/^e\.value/] and eval(attr_search)
475
518
  block_given? ? blk.call(e) : e
476
519
  elsif attr_search[/^e\.xpath/] and eval(attr_search)
520
+
477
521
  block_given? ? blk.call(e) : e
478
522
  end
479
523
  else
@@ -511,8 +555,9 @@ class Rexle
511
555
  else
512
556
  a = yield
513
557
  end
514
-
515
- @doc = scan_element(*a)
558
+ doc_node = ['doc','',{}]
559
+ @a = procs[x.class.to_s.to_sym].call(x)
560
+ @doc = scan_element(*(doc_node << @a))
516
561
  self
517
562
  end
518
563
 
@@ -535,7 +580,7 @@ class Rexle
535
580
  def to_a() @a end
536
581
  def to_s(options={}) self.xml options end
537
582
  def text(xpath) @doc.text(xpath) end
538
- def root() @doc end
583
+ def root() @doc.children.first end
539
584
 
540
585
  def write(f)
541
586
  f.write xml
@@ -576,7 +621,7 @@ class Rexle
576
621
  end
577
622
 
578
623
  def scan_element(name, value=nil, attributes=nil, *children)
579
- #puts 'name : ' + name.inspect
624
+
580
625
  element = Element.new(name, value, attributes, self)
581
626
 
582
627
  if children then
@@ -591,14 +636,6 @@ class Rexle
591
636
  return element
592
637
  end
593
638
 
594
- def count(path)
595
- #puts 'path : ' + path
596
- length = @doc.xpath(path).flatten.compact.length
597
- #puts 'length = ' + length
598
- length
599
- end
600
-
601
- def max(path) @doc.xpath(path).flatten.compact.map(&:to_i).max end
602
639
 
603
640
  # scan a rexml doc
604
641
  #
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rexle
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.9.14
5
+ version: 0.9.15
6
6
  platform: ruby
7
7
  authors:
8
8
  - James Robertson
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-12-07 00:00:00 +00:00
13
+ date: 2011-12-21 00:00:00 +00:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency