rexle 0.9.14 → 0.9.15

Sign up to get free protection for your applications and to get access to all the features.
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