rexle 0.9.5 → 0.9.6
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 +121 -330
- metadata +18 -5
data/lib/rexle.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/
|
1
|
+
#!/usr/bin/ruby
|
2
2
|
|
3
3
|
# file: rexle.rb
|
4
4
|
|
@@ -6,48 +6,21 @@ require 'rexml/document'
|
|
6
6
|
require 'rexleparser'
|
7
7
|
require 'dynarex-parser'
|
8
8
|
require 'polyrex-parser'
|
9
|
-
require 'cgi'
|
10
9
|
include REXML
|
11
10
|
|
12
|
-
# modifications:
|
13
|
-
# 20-Oct-2012: feature: added Rexle::Element#texts which is the equivalent
|
14
|
-
# of REXML::Element#texts
|
15
|
-
# 10-Sep-2012: bug fix: Removed code from method pretty_print in order to
|
16
|
-
# get the XML displayed properly
|
17
|
-
# 23-Aug-2012: feature: implemented xpath function contains()
|
18
|
-
# 17-Aug-2012: bug fix: pretty print now ignores text containing empty space
|
19
|
-
# 16-Aug-2012: the current element's text (if its not empty) is now returned
|
20
|
-
# from its children method
|
21
|
-
# 15-Aug-2012: feature: xpath containing child:: now supported
|
22
|
-
# 13-Aug-2012: bug fix: xpath can now handle the name() function
|
23
|
-
# 11-Aug-2012: bug fix: separated the max() method from 1 line into 3
|
24
|
-
# and that fixed it
|
25
|
-
# 08-Aug-2012: feature: added Element#insert_before and Element#insert_after
|
26
|
-
# 19-Jul-2012: Changed children to elements where appropriate
|
27
|
-
# 15-Jul-2012: bug fix: self.root.value is no longer appended
|
28
|
-
# to the body if there are no child elements
|
29
|
-
# 19-Jun-2012: a bug fix for .//*[@class]
|
30
|
-
# 17-Jun-2012: a couple of new xpath things are supported '.' and '|'
|
31
|
-
# 15-Apr-2012: bug fix: New element names are typecast as string
|
32
|
-
# 16-Mar-2012: bug fix: Element names which contain a colon can now be selected
|
33
|
-
# in the xpath.
|
34
|
-
# 22-Feb-2012: bug resolution: Deactivated the PolyrexParser; using RexleParser instead
|
35
|
-
# 14-Jan-2012: Implemented Rexle::Elements#each
|
36
|
-
# 21-Dec-2011: Bug fix: xpath modified to allow querying from the actual
|
37
|
-
# root rather than the 1st child element from the root
|
38
11
|
|
39
12
|
module XMLhelper
|
40
13
|
|
41
14
|
def doc_print(children)
|
42
|
-
|
43
|
-
body =
|
15
|
+
|
16
|
+
body = children.empty? ? self.root.value : scan_print(children).join
|
44
17
|
a = self.root.attributes.to_a.map{|k,v| "%s='%s'" % [k,v]}
|
45
18
|
"<%s%s>%s</%s>" % [self.root.name, a.empty? ? '' : ' ' + a.join(' '), body, self.root.name]
|
46
19
|
end
|
47
20
|
|
48
21
|
def doc_pretty_print(children)
|
49
22
|
|
50
|
-
body = pretty_print(children,2).join
|
23
|
+
body = children.empty? ? self.value : pretty_print(children,2).join
|
51
24
|
a = self.root.attributes.to_a.map{|k,v| "%s='%s'" % [k,v]}
|
52
25
|
ind = "\n "
|
53
26
|
"<%s%s>%s%s%s</%s>" % [self.root.name, a.empty? ? '' : ' ' + a.join(' '), ind, body, "\n", self.root.name]
|
@@ -56,24 +29,18 @@ module XMLhelper
|
|
56
29
|
def scan_print(nodes)
|
57
30
|
|
58
31
|
nodes.map do |x|
|
59
|
-
|
32
|
+
#puts 'x: ' + x.class.to_s #+ ' name: ' + x.name.to_s
|
60
33
|
if x.is_a? Rexle::Element then
|
61
|
-
|
34
|
+
unless x.name == '![' then
|
62
35
|
a = x.attributes.to_a.map{|k,v| "%s='%s'" % [k,v]}
|
63
36
|
tag = x.name + (a.empty? ? '' : ' ' + a.join(' '))
|
64
37
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
out = ["<%s/>" % tag]
|
72
|
-
end
|
73
|
-
elsif x.name == '!-' then
|
74
|
-
"<!--%s-->" % x.value
|
75
|
-
else
|
76
|
-
"<![CDATA[%s]]>" % x.value
|
38
|
+
out = ["<%s>" % tag]
|
39
|
+
out << x.value unless x.value.nil? || x.value.empty?
|
40
|
+
out << scan_print(x.children)
|
41
|
+
out << "</%s>" % x.name
|
42
|
+
else
|
43
|
+
"<![CDATA[%s]]>" % x.value
|
77
44
|
end
|
78
45
|
elsif x.is_a? String then
|
79
46
|
x
|
@@ -84,24 +51,19 @@ module XMLhelper
|
|
84
51
|
|
85
52
|
def pretty_print(nodes, indent='0')
|
86
53
|
indent = indent.to_i
|
87
|
-
|
88
|
-
nodes.select(){|x| x.is_a? Rexle::Element or x.strip.length > 0}
|
89
|
-
.map.with_index do |x, i|
|
90
|
-
|
54
|
+
nodes.map.with_index do |x, i|
|
91
55
|
if x.is_a? Rexle::Element then
|
92
56
|
unless x.name == '![' then
|
93
|
-
#return ["<%s/>" % x.name] if x.value = ''
|
94
57
|
a = x.attributes.to_a.map{|k,v| "%s='%s'" % [k,v]}
|
95
|
-
a ||= []
|
96
58
|
tag = x.name + (a.empty? ? '' : ' ' + a.join(' '))
|
97
59
|
|
98
|
-
|
99
|
-
|
100
|
-
("\n" + ' ' * indent) : ''
|
60
|
+
ind1 = x.children.length > 0 ? ("\n" + ' ' * indent) : ''
|
61
|
+
start = i > 0 ? ("\n" + ' ' * (indent - 1)) : ''
|
101
62
|
out = ["%s<%s>%s" % [start, tag, ind1]]
|
102
63
|
|
64
|
+
out << x.value.sub(/^[\n\s]+$/,'') unless x.value.nil? || x.value.empty?
|
103
65
|
out << pretty_print(x.children, (indent + 1).to_s.clone)
|
104
|
-
ind2 =
|
66
|
+
ind2 = x.children.length > 0 ? ("\n" + ' ' * (indent - 1)) : ''
|
105
67
|
out << "%s</%s>" % [ind2, x.name]
|
106
68
|
else
|
107
69
|
"<![CDATA[%s]]>" % x.value
|
@@ -119,10 +81,6 @@ class Rexle
|
|
119
81
|
include XMLhelper
|
120
82
|
|
121
83
|
attr_reader :prefixes
|
122
|
-
|
123
|
-
def self.version()
|
124
|
-
'0.9.xx'
|
125
|
-
end
|
126
84
|
|
127
85
|
def initialize(x=nil)
|
128
86
|
super()
|
@@ -134,144 +92,85 @@ class Rexle
|
|
134
92
|
Array: proc {|x| x},
|
135
93
|
:"REXML::Document" => proc {|x| scan_doc x.root}
|
136
94
|
}
|
137
|
-
|
138
|
-
doc_node = ['doc','',{}]
|
139
|
-
|
140
95
|
|
141
96
|
@a = procs[x.class.to_s.to_sym].call(x)
|
142
|
-
@doc = scan_element(
|
97
|
+
@doc = scan_element(*@a)
|
143
98
|
|
144
99
|
# fetch the namespaces
|
145
100
|
@prefixes = []
|
146
101
|
if @doc.root.attributes then
|
147
|
-
|
102
|
+
#puts 'attrs : ' + @doc.root.attributes.inspect
|
148
103
|
xmlns = @doc.root.attributes.select {|k,v| k[/^xmlns:/]}
|
149
104
|
@prefixes = xmlns.keys.map{|x| x[/\w+$/]}
|
150
105
|
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
def xpath(path, &blk)
|
111
|
+
|
112
|
+
# is it a function
|
113
|
+
fn_match = path.match(/^(\w+)\(([^\)]+)\)$/)
|
151
114
|
|
115
|
+
# Array: proc {|x| x.flatten.compact},
|
116
|
+
if (fn_match and fn_match.captures.first[/^(attribute|@)/]) or fn_match.nil? then
|
117
|
+
procs = {
|
118
|
+
Array: proc {|x| block_given? ? x : x.flatten },
|
119
|
+
String: proc {|x| x},
|
120
|
+
:"Rexle::Element" => proc {|x| [x]}
|
121
|
+
}
|
122
|
+
bucket = []
|
123
|
+
result = @doc.xpath(path, bucket, &blk)
|
124
|
+
|
125
|
+
procs[result.class.to_s.to_sym].call(result)
|
126
|
+
|
127
|
+
else
|
128
|
+
#puts 'fn ' + fn_match.captures.inspect
|
129
|
+
m, xpath_value = fn_match.captures
|
130
|
+
method(m.to_sym).call(xpath_value)
|
152
131
|
end
|
153
132
|
|
133
|
+
|
154
134
|
end
|
155
|
-
|
156
|
-
def xpath(path, &blk)
|
157
|
-
@doc.xpath(path, &blk)
|
158
|
-
end
|
159
135
|
|
160
136
|
class Element
|
161
137
|
include XMLhelper
|
162
138
|
|
163
139
|
attr_accessor :name, :value, :parent
|
164
|
-
attr_reader :child_lookup
|
165
|
-
|
166
|
-
alias original_clone clone
|
140
|
+
attr_reader :child_lookup
|
167
141
|
|
168
142
|
def initialize(name=nil, value='', attributes={}, rexle=nil)
|
169
143
|
@rexle = rexle
|
170
144
|
super()
|
171
|
-
@name, @value, @attributes = name
|
145
|
+
@name, @value, @attributes = name, value, attributes
|
172
146
|
raise "Element name must not be blank" unless name
|
173
147
|
@child_elements = []
|
174
148
|
@child_lookup = []
|
175
149
|
end
|
176
150
|
|
177
|
-
def contains(raw_args)
|
178
|
-
path, raw_val = raw_args.split(',',2)
|
179
|
-
val = raw_val.strip[/^["']?.*["']?$/]
|
180
|
-
|
181
|
-
anode = query_xpath(path)
|
182
|
-
return unless anode
|
183
|
-
a = scan_contents(anode.first)
|
184
|
-
|
185
|
-
[a.grep(/#{val}/).length > 0]
|
186
|
-
end
|
187
|
-
|
188
|
-
def count(path)
|
189
|
-
length = query_xpath(path).flatten.compact.length
|
190
|
-
length
|
191
|
-
end
|
192
|
-
|
193
|
-
def max(path)
|
194
|
-
a = query_xpath(path).flatten.compact.map(&:to_i)
|
195
|
-
a.max
|
196
|
-
end
|
197
|
-
|
198
151
|
def name()
|
152
|
+
#puts 'zzz : ' + @rexle.prefixes.inspect
|
153
|
+
#puts '@rexle : ' + @rexle.inspect
|
199
154
|
if @rexle then
|
200
|
-
|
201
|
-
|
155
|
+
prefix = @rexle.prefixes.find {|x| x == @name[/^(\w+):/,1] } if @rexle.prefixes.is_a? Array
|
156
|
+
#puts 'ppp: ' + prefix.inspect
|
157
|
+
prefix ? @name.sub(prefix + ':', '') : @name
|
202
158
|
else
|
203
|
-
|
159
|
+
@name
|
204
160
|
end
|
205
161
|
end
|
206
162
|
|
207
|
-
def xpath(
|
208
|
-
r = filter_xpath(path, rlist=[], &blk)
|
209
|
-
r.is_a?(Array) ? r.compact : r
|
210
|
-
end
|
211
|
-
|
212
|
-
def filter_xpath(path, rlist=[], &blk)
|
213
|
-
|
214
|
-
# is it a function
|
215
|
-
fn_match = path.match(/^(\w+)\(["']?([^\)]*)["']?\)$/)
|
216
|
-
|
217
|
-
# Array: proc {|x| x.flatten.compact},
|
218
|
-
if (fn_match and fn_match.captures.first[/^(attribute|@)/]) or fn_match.nil? then
|
219
|
-
procs = {
|
220
|
-
Array: proc {|x| block_given? ? x : x.flatten.uniq },
|
221
|
-
String: proc {|x| x},
|
222
|
-
Hash: proc {|x| x},
|
223
|
-
TrueClass: proc{|x| x},
|
224
|
-
FalseClass: proc{|x| x},
|
225
|
-
:"Rexle::Element" => proc {|x| [x]}
|
226
|
-
}
|
227
|
-
bucket = []
|
228
|
-
raw_results = path.split('|').map do |xp|
|
229
|
-
query_xpath(xp, bucket, &blk)
|
230
|
-
end
|
231
|
-
|
232
|
-
#results = raw_results.inject(&:+)
|
233
|
-
results = raw_results.last
|
234
|
-
procs[results.class.to_s.to_sym].call(results) if results
|
235
|
-
|
236
|
-
else
|
237
|
-
m, xpath_value = fn_match.captures
|
238
|
-
xpath_value.empty? ? method(m.to_sym).call : method(m.to_sym).call(xpath_value)
|
239
|
-
end
|
240
|
-
|
241
|
-
end
|
242
|
-
|
243
|
-
def query_xpath(raw_xpath_value, rlist=[], &blk)
|
163
|
+
def xpath(xpath_value, rlist=[], &blk)
|
244
164
|
|
245
|
-
#remove any
|
165
|
+
#remove any prefixes
|
246
166
|
#@rexle.prefixes.each {|x| xpath_value.sub!(x + ':','') }
|
247
|
-
|
248
|
-
|
249
|
-
xpath_value = raw_xpath_value.sub('child::','./')
|
250
|
-
#xpath_value.sub!(/\.\/(?=[\/])/,'')
|
251
|
-
|
252
|
-
if xpath_value[/^[\w\/]+\s*=.*/] then
|
253
|
-
flag_func = true
|
254
|
-
|
255
|
-
xpath_value.sub!(/^\w+\s*=.*/,'.[\0]')
|
256
|
-
xpath_value.sub!(/\/([\w]+\s*=.*)/,'[\1]')
|
257
|
-
|
258
|
-
#result = self.element xpath_value
|
259
|
-
#return [(result.is_a?(Rexle::Element) ? true : false)]
|
260
|
-
end
|
261
|
-
|
167
|
+
|
168
|
+
xpath_value.sub!(/^\[/,'*[')
|
262
169
|
#xpath_value.sub!(/^attribute::/,'*/attribute::')
|
263
|
-
raw_path, raw_condition = xpath_value.sub(
|
264
|
-
.match(/([^\[]+)(\[[^\]]+\])?/).captures
|
170
|
+
raw_path, raw_condition = xpath_value.sub(/^\/(?!\/)/,'').match(/([^\[]+)(\[[^\]]+\])?/).captures
|
265
171
|
|
266
172
|
remaining_path = ($').to_s
|
267
|
-
|
268
|
-
r = raw_path[/([^\/]+)(?=\/\/)/,1]
|
269
|
-
if r then
|
270
|
-
a_path = raw_path.split(/(?=\/\/)/,2)
|
271
|
-
else
|
272
|
-
a_path = raw_path.split('/',2)
|
273
|
-
end
|
274
|
-
|
173
|
+
a_path = raw_path.split('/')
|
275
174
|
condition = raw_condition if a_path.length <= 1
|
276
175
|
|
277
176
|
if raw_path[0,2] == '//' then
|
@@ -282,23 +181,20 @@ class Rexle
|
|
282
181
|
else
|
283
182
|
|
284
183
|
attribute = xpath_value[/^(attribute::|@)(.*)/,2]
|
285
|
-
|
286
|
-
|
287
|
-
return [@attributes[attribute.to_sym]] if attribute and @attributes and @attributes.has_key?(attribute.to_sym)
|
184
|
+
return [@attributes[attribute]] if attribute and @attributes and @attributes.has_key?(attribute)
|
185
|
+
|
288
186
|
s = a_path.shift
|
289
187
|
end
|
290
188
|
|
291
189
|
# isolate the xpath to return just the path to the current element
|
292
|
-
|
293
|
-
elmnt_path = s[/^([\w:\*]+\[[^\]]+\])|[\/]+{,2}[^\/]+/]
|
190
|
+
elmnt_path = s[/^([\w\*]+\[[^\]]+\])|[\/]+{,2}[^\/]+/]
|
294
191
|
element_part = elmnt_path[/(^@?[^\[]+)?/,1] if elmnt_path
|
295
|
-
|
192
|
+
|
296
193
|
if element_part then
|
297
194
|
unless element_part[/^@/] then
|
298
|
-
element_name = element_part
|
195
|
+
element_name = element_part
|
299
196
|
else
|
300
|
-
|
301
|
-
condition = xpath_value[/^\[/] ? xpath_value : element_part
|
197
|
+
condition = element_part
|
302
198
|
element_name = nil
|
303
199
|
end
|
304
200
|
|
@@ -306,32 +202,15 @@ class Rexle
|
|
306
202
|
|
307
203
|
#element_name ||= '*'
|
308
204
|
raw_condition = '' if condition
|
309
|
-
attr_search = format_condition(condition) if condition and condition.length > 0
|
310
|
-
|
311
|
-
attr_search2 = xpath_value[/^\[(.*)\]$/,1]
|
312
|
-
if attr_search2 then
|
313
|
-
r4 = attribute_search(attr_search, self, self.attributes)
|
314
|
-
return r4
|
315
|
-
end
|
316
|
-
|
317
|
-
return_elements = []
|
318
|
-
|
319
|
-
if raw_path[0,2] == '//' then
|
320
205
|
|
321
|
-
|
322
|
-
n = xpath_value[regex,1]
|
323
|
-
xpath_value.slice!(regex)
|
324
|
-
|
325
|
-
rs = scan_match(self, xpath_value).flatten.compact
|
326
|
-
return n ? rs[n.to_i-1] : rs
|
206
|
+
attr_search = format_condition(condition) if condition and condition.length > 0
|
327
207
|
|
328
|
-
|
329
|
-
return
|
208
|
+
if raw_path[0,2] == '//'
|
209
|
+
return scan_match(self, xpath_value)
|
330
210
|
else
|
331
211
|
|
332
|
-
return_elements = @child_lookup.map.with_index.select do |x|
|
333
|
-
|
334
|
-
(element_name == '*' && x[0].is_a?(Array))
|
212
|
+
return_elements = @child_lookup.map.with_index.select do |x|
|
213
|
+
x[0][0] == element_name or element_name == '*'
|
335
214
|
end
|
336
215
|
|
337
216
|
end
|
@@ -339,6 +218,7 @@ class Rexle
|
|
339
218
|
if return_elements.length > 0 then
|
340
219
|
|
341
220
|
if (a_path + [remaining_path]).join.empty? then
|
221
|
+
|
342
222
|
rlist = return_elements.map.with_index {|x,i| filter(x, i+1, attr_search, &blk)}.compact
|
343
223
|
rlist = rlist[0] if rlist.length == 1
|
344
224
|
else
|
@@ -348,9 +228,7 @@ class Rexle
|
|
348
228
|
rtn_element = filter(x, i+1, attr_search){|e| r = e.xpath(a_path.join('/') + raw_condition.to_s + remaining_path, &blk); (r || e) }
|
349
229
|
next if rtn_element.nil? or (rtn_element.is_a? Array and rtn_element.empty?)
|
350
230
|
|
351
|
-
if rtn_element.is_a?
|
352
|
-
rtn_element
|
353
|
-
elsif rtn_element.is_a? Array then
|
231
|
+
if rtn_element.is_a? Array then
|
354
232
|
rtn_element
|
355
233
|
elsif (rtn_element.is_a? String) || (rtn_element.is_a?(Array) and not(rtn_element[0].is_a? String))
|
356
234
|
rtn_element
|
@@ -359,26 +237,23 @@ class Rexle
|
|
359
237
|
end
|
360
238
|
end
|
361
239
|
#
|
362
|
-
|
363
240
|
rlist = rlist.flatten(1) unless rlist.length > 1 and rlist[0].is_a? Array
|
364
241
|
|
365
242
|
end
|
366
|
-
|
367
243
|
rlist.compact! if rlist.is_a? Array
|
368
244
|
|
369
245
|
else
|
370
246
|
|
371
247
|
# strip off the 1st element from the XPath
|
372
|
-
new_xpath = xpath_value[
|
373
|
-
|
248
|
+
new_xpath = xpath_value[/^\/\/\w+\/(.*)/,1]
|
249
|
+
|
374
250
|
if new_xpath then
|
375
251
|
self.xpath(new_xpath + raw_condition.to_s + remaining_path, rlist,&blk)
|
376
252
|
end
|
377
253
|
end
|
378
|
-
|
254
|
+
|
379
255
|
rlist = rlist.flatten(1) unless not(rlist.is_a? Array) or (rlist.length > 1 and rlist[0].is_a? Array)
|
380
256
|
rlist = [rlist] if rlist.is_a? Rexle::Element
|
381
|
-
rlist = (rlist.length > 0 ? true : false) if flag_func == true
|
382
257
|
rlist
|
383
258
|
end
|
384
259
|
|
@@ -398,11 +273,7 @@ class Rexle
|
|
398
273
|
end
|
399
274
|
|
400
275
|
def inspect()
|
401
|
-
if self.xml.length > 30 then
|
402
276
|
"%s ... </>" % self.xml[/<[^>]+>/]
|
403
|
-
else
|
404
|
-
self.xml
|
405
|
-
end
|
406
277
|
end
|
407
278
|
|
408
279
|
alias add add_element
|
@@ -422,28 +293,11 @@ class Rexle
|
|
422
293
|
|
423
294
|
def add_text(s) @value = s; self end
|
424
295
|
|
425
|
-
def attribute(key)
|
426
|
-
key = key.to_sym if key.is_a? String
|
427
|
-
@attributes[key].gsub('<','<').gsub('>','>')
|
428
|
-
end
|
429
|
-
|
296
|
+
def attribute(key) @attributes[key] end
|
430
297
|
def attributes() @attributes end
|
431
|
-
|
432
|
-
def children()
|
433
|
-
|
434
|
-
r = (@value.empty? ? [] : [@value]) + @child_elements
|
435
|
-
def r.is_an_empty_string?()
|
436
|
-
self.length == 1 and self.first == ''
|
437
|
-
end
|
438
|
-
|
439
|
-
return r
|
440
|
-
end
|
441
|
-
|
442
|
-
def children=(a) @child_elements = a end
|
443
|
-
|
444
|
-
def deep_clone() Rexle.new(self.xml).root end
|
445
|
-
def clone() Element.new(@name, @value, @attributes) end
|
446
|
-
|
298
|
+
def children() @child_elements end
|
299
|
+
def children=(a) @child_elements = a end
|
300
|
+
|
447
301
|
def delete(obj=nil)
|
448
302
|
if obj then
|
449
303
|
i = @child_elements.index(obj)
|
@@ -453,14 +307,11 @@ class Rexle
|
|
453
307
|
end
|
454
308
|
end
|
455
309
|
|
456
|
-
def element(s)
|
457
|
-
r = self.xpath(s)
|
458
|
-
r.is_a?(Array) ? r.first : r
|
459
|
-
end
|
310
|
+
def element(s) self.xpath(s).first end
|
460
311
|
|
461
312
|
def elements(s=nil)
|
462
313
|
procs = {
|
463
|
-
NilClass: proc {Elements.new(@child_elements
|
314
|
+
NilClass: proc {Elements.new(@child_elements)},
|
464
315
|
String: proc {|x| @child_elements[x]}
|
465
316
|
}
|
466
317
|
|
@@ -468,14 +319,7 @@ class Rexle
|
|
468
319
|
end
|
469
320
|
|
470
321
|
def doc_root() @rexle.root end
|
471
|
-
def each(&blk)
|
472
|
-
@child_elements.each(&blk) #unless @child_elements.empty?
|
473
|
-
end
|
474
|
-
def has_elements?() !self.elements.empty? end
|
475
|
-
|
476
|
-
def insert_after(node) insert(node, 1) end
|
477
|
-
def insert_before(node) insert(node) end
|
478
|
-
|
322
|
+
def each(&blk) @child_elements.each(&blk) end
|
479
323
|
def root() self end #@rexle.root end
|
480
324
|
|
481
325
|
def text(s='')
|
@@ -486,7 +330,6 @@ class Rexle
|
|
486
330
|
e = self.element(s)
|
487
331
|
result = e.value if e
|
488
332
|
end
|
489
|
-
result = CGI.unescape_html result.to_s
|
490
333
|
|
491
334
|
def result.unescape()
|
492
335
|
s = self.clone
|
@@ -496,14 +339,10 @@ class Rexle
|
|
496
339
|
|
497
340
|
result
|
498
341
|
end
|
499
|
-
|
500
|
-
def texts()
|
501
|
-
[@value] + @child_elements.select {|x| x.is_a? String}
|
502
|
-
end
|
503
342
|
|
504
343
|
def value=(raw_s)
|
505
344
|
|
506
|
-
@value =
|
345
|
+
@value = raw_s.to_s.clone
|
507
346
|
escape_chars = %w(& & < < > >).each_slice(2).to_a
|
508
347
|
escape_chars.each{|x| @value.gsub!(*x)}
|
509
348
|
|
@@ -523,27 +362,17 @@ class Rexle
|
|
523
362
|
method(msg).call(self.children)
|
524
363
|
end
|
525
364
|
|
526
|
-
alias to_s xml
|
527
365
|
|
528
366
|
private
|
529
|
-
|
530
|
-
def insert(node,offset=0)
|
531
|
-
i = parent.child_elements.index(self)
|
532
|
-
return unless i
|
533
|
-
parent.child_elements.insert(i+offset,node)
|
534
|
-
parent.child_lookup.insert(i+offset, [node.name, node.attributes, node.value])
|
535
|
-
self
|
536
|
-
end
|
537
367
|
|
538
368
|
def format_condition(condition)
|
539
|
-
|
540
|
-
raw_items = condition[1..-1].scan(/\'[^\']*\'
|
369
|
+
#raw_items = condition[1..-1].scan(/\'[^\']*\'|and|or|\d+|[!=]+|[@\w\.\/]+/)
|
370
|
+
raw_items = condition[1..-1].scan(/\'[^\']*\'|and|or|\d+|[!=<>]+|position\(\)|[@\w\.\/]+/)
|
541
371
|
|
542
372
|
if raw_items[0][/^\d+$/] then
|
543
373
|
return raw_items[0].to_i
|
544
374
|
elsif raw_items[0] == 'position()' then
|
545
|
-
|
546
|
-
return rrr
|
375
|
+
return "i %s %s" % raw_items[1..-1]
|
547
376
|
else
|
548
377
|
|
549
378
|
andor_items = raw_items.map.with_index.select{|x,i| x[/\band\b|\bor\b/]}.map{|x| [x.last, x.last + 1]}.flatten
|
@@ -558,10 +387,9 @@ class Rexle
|
|
558
387
|
|
559
388
|
if x.length >= 3 then
|
560
389
|
x[1] = '==' if x[1] == '='
|
561
|
-
"h[
|
390
|
+
"h['%s'] %s %s" % x
|
562
391
|
else
|
563
|
-
|
564
|
-
x.join[/^(and|or)$/] ? x : ("h[:'%s']" % x)
|
392
|
+
x
|
565
393
|
end
|
566
394
|
end
|
567
395
|
|
@@ -572,7 +400,6 @@ class Rexle
|
|
572
400
|
items = cons_items.map do |x|
|
573
401
|
|
574
402
|
if x.length >= 3 then
|
575
|
-
|
576
403
|
x[1] = '==' if x[1] == '='
|
577
404
|
if x[0] != '.' then
|
578
405
|
if x[0][/\//] then
|
@@ -580,7 +407,7 @@ class Rexle
|
|
580
407
|
|
581
408
|
"e.xpath('#{path}').first.value == #{value}"
|
582
409
|
else
|
583
|
-
"(name == '%s' and value %s
|
410
|
+
"(name == '%s' and value %s %s)" % [x[0], x[1], x[2]]
|
584
411
|
end
|
585
412
|
else
|
586
413
|
"e.value %s %s" % [x[1], x[2]]
|
@@ -589,7 +416,7 @@ class Rexle
|
|
589
416
|
x
|
590
417
|
end
|
591
418
|
end
|
592
|
-
|
419
|
+
|
593
420
|
return items.join(' ')
|
594
421
|
end
|
595
422
|
end
|
@@ -598,46 +425,35 @@ class Rexle
|
|
598
425
|
end
|
599
426
|
|
600
427
|
|
601
|
-
def scan_match(node,
|
602
|
-
|
603
|
-
r = []
|
604
|
-
xpath2 = path[2..-1]
|
605
|
-
xpath2.sub!(/^\*\//,'')
|
606
|
-
xpath2.sub!(/^\*/,self.name)
|
607
|
-
xpath2.sub!(/^\w+/,'').sub!(/^\//,'') if xpath2[/^\w+/] == self.name
|
608
|
-
|
428
|
+
def scan_match(node, xpath)
|
609
429
|
|
610
|
-
r
|
611
|
-
r << node.
|
430
|
+
r = node.xpath(xpath[2..-1])
|
431
|
+
r << node.children.map {|n| scan_match(n, xpath)}
|
432
|
+
#puts 'r: ' + r.inspect
|
612
433
|
r
|
613
434
|
end
|
614
|
-
|
615
|
-
# used by xpath function contains()
|
616
|
-
#
|
617
|
-
def scan_contents(node)
|
618
|
-
|
619
|
-
a = []
|
620
|
-
a << node.text
|
621
|
-
|
622
|
-
node.elements.each do |child|
|
623
|
-
a.concat scan_contents(child)
|
624
|
-
end
|
625
|
-
a
|
626
|
-
end
|
627
|
-
|
628
435
|
|
629
436
|
def filter(raw_element, i, attr_search, &blk)
|
630
437
|
|
631
438
|
x = raw_element
|
632
439
|
e = @child_elements[x.last]
|
633
440
|
|
634
|
-
|
635
|
-
name, value = e.name, e.value if e.is_a? Rexle::Element
|
441
|
+
h = x[0][1] # <-- fetch the attributes
|
636
442
|
|
637
|
-
h = x[0][1] # <-- fetch the attributes
|
638
|
-
|
639
443
|
if attr_search then
|
640
|
-
|
444
|
+
if attr_search.is_a? Fixnum then
|
445
|
+
block_given? ? blk.call(e) : e if i == attr_search
|
446
|
+
elsif attr_search[/i\s[<>\=]\s\d+/] and eval(attr_search) then
|
447
|
+
block_given? ? blk.call(e) : e
|
448
|
+
elsif h and attr_search[/^h\[/] and eval(attr_search)
|
449
|
+
block_given? ? blk.call(e) : e
|
450
|
+
elsif attr_search[/^\(name ==/] and e.child_lookup.select{|name, attributes, value| eval(attr_search) }.length > 0
|
451
|
+
block_given? ? blk.call(e) : e
|
452
|
+
elsif attr_search[/^e\.value/] and eval(attr_search)
|
453
|
+
block_given? ? blk.call(e) : e
|
454
|
+
elsif attr_search[/^e\.xpath/] and eval(attr_search)
|
455
|
+
block_given? ? blk.call(e) : e
|
456
|
+
end
|
641
457
|
else
|
642
458
|
|
643
459
|
block_given? ? blk.call(e) : e
|
@@ -645,28 +461,9 @@ class Rexle
|
|
645
461
|
|
646
462
|
end
|
647
463
|
|
648
|
-
def attribute_search(attr_search, e, h, i=nil, &blk)
|
649
|
-
if attr_search.is_a? Fixnum then
|
650
|
-
block_given? ? blk.call(e) : e if i == attr_search
|
651
|
-
elsif attr_search[/i\s[<>\=]\s\d+/] and eval(attr_search) then
|
652
|
-
block_given? ? blk.call(e) : e
|
653
|
-
elsif h and attr_search[/^h\[/] and eval(attr_search)
|
654
|
-
block_given? ? blk.call(e) : e
|
655
|
-
elsif attr_search[/^\(name ==/] and e.child_lookup.select{|name, attributes, value| eval(attr_search) }.length > 0
|
656
|
-
block_given? ? blk.call(e) : e
|
657
|
-
elsif attr_search[/^\(name ==/] and eval(attr_search)
|
658
|
-
block_given? ? blk.call(e) : e
|
659
|
-
elsif attr_search[/^e\.value/] and eval(attr_search)
|
660
|
-
block_given? ? blk.call(e) : e
|
661
|
-
elsif attr_search[/^e\.xpath/] and eval(attr_search)
|
662
|
-
block_given? ? blk.call(e) : e
|
663
|
-
end
|
664
|
-
end
|
665
464
|
end # -- end of element --
|
666
465
|
|
667
466
|
class Elements
|
668
|
-
include Enumerable
|
669
|
-
|
670
467
|
def initialize(elements=[])
|
671
468
|
super()
|
672
469
|
@elements = elements
|
@@ -675,10 +472,6 @@ class Rexle
|
|
675
472
|
def [](i)
|
676
473
|
@elements[i-1]
|
677
474
|
end
|
678
|
-
|
679
|
-
def each(&blk) @elements.each(&blk) end
|
680
|
-
def to_a() @elements end
|
681
|
-
|
682
475
|
end # -- end of elements --
|
683
476
|
|
684
477
|
|
@@ -696,9 +489,8 @@ class Rexle
|
|
696
489
|
else
|
697
490
|
a = yield
|
698
491
|
end
|
699
|
-
|
700
|
-
@
|
701
|
-
@doc = scan_element(*(doc_node << @a))
|
492
|
+
|
493
|
+
@doc = scan_element(*a)
|
702
494
|
self
|
703
495
|
end
|
704
496
|
|
@@ -710,18 +502,14 @@ class Rexle
|
|
710
502
|
|
711
503
|
alias add add_element
|
712
504
|
|
713
|
-
def delete(xpath)
|
714
|
-
e = @doc.element(xpath)
|
715
|
-
e.delete if e
|
716
|
-
end
|
717
|
-
|
505
|
+
def delete(xpath) @doc.element(xpath).delete end
|
718
506
|
def element(xpath) self.xpath(xpath).first end
|
719
507
|
def elements(s=nil) @doc.elements(s) end
|
720
508
|
def name() @doc.root.name end
|
721
509
|
def to_a() @a end
|
722
510
|
def to_s(options={}) self.xml options end
|
723
511
|
def text(xpath) @doc.text(xpath) end
|
724
|
-
def root() @doc
|
512
|
+
def root() @doc end
|
725
513
|
|
726
514
|
def write(f)
|
727
515
|
f.write xml
|
@@ -730,11 +518,9 @@ class Rexle
|
|
730
518
|
def xml(options={})
|
731
519
|
o = {pretty: false, declaration: true}.merge(options)
|
732
520
|
msg = o[:pretty] == false ? :doc_print : :doc_pretty_print
|
733
|
-
|
734
521
|
r = ''
|
735
522
|
r = "<?xml version='1.0' encoding='UTF-8'?>\n" if o[:declaration] == true
|
736
523
|
r << method(msg).call(self.root.children)
|
737
|
-
|
738
524
|
r
|
739
525
|
end
|
740
526
|
|
@@ -751,23 +537,20 @@ class Rexle
|
|
751
537
|
if recordx_type then
|
752
538
|
procs = {
|
753
539
|
'dynarex' => proc {|x| DynarexParser.new(x).to_a},
|
754
|
-
'polyrex' => proc {|x| PolyrexParser.new(x).to_a}
|
755
|
-
'polyrex' => proc {|x| RexleParser.new(x).to_a}
|
540
|
+
'polyrex' => proc {|x| PolyrexParser.new(x).to_a}
|
756
541
|
}
|
757
542
|
procs[recordx_type].call(x)
|
758
543
|
else
|
759
|
-
|
760
544
|
RexleParser.new(x).to_a
|
761
545
|
end
|
762
546
|
else
|
763
|
-
|
764
547
|
RexleParser.new(x).to_a
|
765
548
|
end
|
766
549
|
|
767
550
|
end
|
768
551
|
|
769
552
|
def scan_element(name, value=nil, attributes=nil, *children)
|
770
|
-
|
553
|
+
#puts 'name : ' + name.inspect
|
771
554
|
element = Element.new(name, value, attributes, self)
|
772
555
|
|
773
556
|
if children then
|
@@ -782,6 +565,14 @@ class Rexle
|
|
782
565
|
return element
|
783
566
|
end
|
784
567
|
|
568
|
+
def count(path)
|
569
|
+
#puts 'path : ' + path
|
570
|
+
length = @doc.xpath(path).flatten.compact.length
|
571
|
+
#puts 'length = ' + length
|
572
|
+
length
|
573
|
+
end
|
574
|
+
|
575
|
+
def max(path) @doc.xpath(path).flatten.compact.map(&:to_i).max end
|
785
576
|
|
786
577
|
# scan a rexml doc
|
787
578
|
#
|
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.6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- James Robertson
|
@@ -10,7 +10,8 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2011-07-19 00:00:00 +01:00
|
14
|
+
default_executable:
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
16
17
|
name: rexleparser
|
@@ -46,7 +47,7 @@ dependencies:
|
|
46
47
|
type: :runtime
|
47
48
|
version_requirements: *id003
|
48
49
|
- !ruby/object:Gem::Dependency
|
49
|
-
name:
|
50
|
+
name: nokogiri
|
50
51
|
prerelease: false
|
51
52
|
requirement: &id004 !ruby/object:Gem::Requirement
|
52
53
|
none: false
|
@@ -56,6 +57,17 @@ dependencies:
|
|
56
57
|
version: "0"
|
57
58
|
type: :runtime
|
58
59
|
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: rexle-builder
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
type: :runtime
|
70
|
+
version_requirements: *id005
|
59
71
|
description:
|
60
72
|
email:
|
61
73
|
executables: []
|
@@ -66,6 +78,7 @@ extra_rdoc_files: []
|
|
66
78
|
|
67
79
|
files:
|
68
80
|
- lib/rexle.rb
|
81
|
+
has_rdoc: true
|
69
82
|
homepage:
|
70
83
|
licenses: []
|
71
84
|
|
@@ -89,9 +102,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
102
|
requirements: []
|
90
103
|
|
91
104
|
rubyforge_project:
|
92
|
-
rubygems_version: 1.
|
105
|
+
rubygems_version: 1.5.2
|
93
106
|
signing_key:
|
94
107
|
specification_version: 3
|
95
|
-
summary:
|
108
|
+
summary: rexle
|
96
109
|
test_files: []
|
97
110
|
|