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.
- data/lib/rexle.rb +108 -71
- metadata +2 -2
data/lib/rexle.rb
CHANGED
@@ -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
|
-
|
45
|
+
|
43
46
|
if x.is_a? Rexle::Element then
|
44
|
-
|
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
|
-
|
53
|
-
|
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(
|
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,
|
121
|
-
|
122
|
-
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
226
|
-
|
227
|
-
|
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.
|
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)
|
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(< < > > & & &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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
@
|
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
|
-
|
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.
|
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-
|
13
|
+
date: 2011-12-21 00:00:00 +00:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|