feedtools 0.2.24 → 0.2.25

Sign up to get free protection for your applications and to get access to all the features.
@@ -1273,6 +1273,21 @@ module FeedTools
1273
1273
  ], :select_result_value => true)
1274
1274
  )
1275
1275
  end
1276
+ if @author.name.blank? && !@author.raw.blank? &&
1277
+ !@author.email.blank?
1278
+ name_scan = @author.raw.scan(
1279
+ /"?([^"]*)"? ?[\(<].*#{@author.email}.*[\)>].*/)
1280
+ if name_scan.flatten.size == 1
1281
+ @author.name = name_scan.flatten[0].strip
1282
+ end
1283
+ if @author.name.blank?
1284
+ name_scan = @author.raw.scan(
1285
+ /.*#{@author.email} ?[\(<]"?([^"]*)"?[\)>].*/)
1286
+ if name_scan.flatten.size == 1
1287
+ @author.name = name_scan.flatten[0].strip
1288
+ end
1289
+ end
1290
+ end
1276
1291
  @author.name = nil if @author.name.blank?
1277
1292
  @author.raw = nil if @author.raw.blank?
1278
1293
  @author.email = nil if @author.email.blank?
@@ -1839,11 +1854,15 @@ module FeedTools
1839
1854
  xml_builder.title(FeedTools::HtmlHelper.strip_html_tags(self.title))
1840
1855
  end
1841
1856
  unless self.link.blank?
1842
- xml_builder.link(link)
1857
+ xml_builder.link(self.link)
1843
1858
  end
1844
1859
  unless self.author.nil? || self.author.name.nil?
1845
1860
  xml_builder.tag!("dc:creator", self.author.name)
1846
1861
  end
1862
+ unless self.author.nil? || self.author.email.nil? ||
1863
+ self.author.name.nil?
1864
+ xml_builder.author("#{self.author.email} (#{self.author.name})")
1865
+ end
1847
1866
  unless self.summary.blank?
1848
1867
  xml_builder.description(self.summary)
1849
1868
  end
@@ -132,7 +132,9 @@ module FeedTools
132
132
  options[:form_data] = {} if options[:form_data].blank?
133
133
  request_params << options[:form_data]
134
134
  end
135
+ Thread.pass
135
136
  response = http.send(http_operation, *request_params)
137
+ Thread.pass
136
138
 
137
139
  case response
138
140
  when Net::HTTPSuccess
@@ -167,7 +169,7 @@ module FeedTools
167
169
 
168
170
  redirected_location = response['location']
169
171
  redirected_location = FeedTools::UriHelper.resolve_relative_uri(
170
- redirected_location, [uri.host])
172
+ redirected_location, [uri.to_s])
171
173
 
172
174
  if options[:response_chain].assoc(redirected_location) != nil
173
175
  raise FeedAccessError,
@@ -191,7 +193,7 @@ module FeedTools
191
193
  end
192
194
  rescue SocketError
193
195
  raise FeedAccessError, 'Socket error prevented feed retrieval'
194
- rescue Timeout::Error
196
+ rescue Timeout::Error, Errno::ETIMEDOUT
195
197
  raise FeedAccessError, 'Timeout while attempting to retrieve feed'
196
198
  rescue Errno::ENETUNREACH
197
199
  raise FeedAccessError, 'Network was unreachable'
@@ -23,11 +23,12 @@
23
23
 
24
24
  require 'feed_tools'
25
25
  require 'uri'
26
-
26
+
27
27
  module FeedTools
28
28
  # Generic url processing methods needed in numerous places throughout
29
29
  # FeedTools
30
30
  module UriHelper
31
+
31
32
  # Returns true if the idn module can be used.
32
33
  def self.idn_enabled?
33
34
  # This is an override variable to keep idn from being used even if it
@@ -0,0 +1,625 @@
1
+ require 'rexml/document'
2
+
3
+ module REXML # :nodoc:
4
+ class LiberalXPathParser < XPathParser # :nodoc:
5
+
6
+ private
7
+
8
+ # Monkey Patch for Ruby 1.8.4
9
+ def expr( path_stack, nodeset, context=nil )
10
+ #puts "#"*15
11
+ #puts "In expr with #{path_stack.inspect}"
12
+ #puts "Returning" if path_stack.length == 0 || nodeset.length == 0
13
+ node_types = ELEMENTS
14
+ return nodeset if path_stack.length == 0 || nodeset.length == 0
15
+ while path_stack.length > 0
16
+ #puts "Path stack = #{path_stack.inspect}"
17
+ #puts "Nodeset is #{nodeset.inspect}"
18
+ case (op = path_stack.shift)
19
+ when :document
20
+ nodeset = [ nodeset[0].root_node ]
21
+ #puts ":document, nodeset = #{nodeset.inspect}"
22
+
23
+ when :qname
24
+ #puts "IN QNAME"
25
+ prefix = path_stack.shift
26
+ name = path_stack.shift
27
+ ns = @namespaces[prefix]
28
+ ns = ns ? ns : ''
29
+ nodeset.delete_if do |node|
30
+ # FIXME: This DOUBLES the time XPath searches take
31
+ ns = node.namespace( prefix ) if node.node_type == :element and ns == ''
32
+ #puts "NS = #{ns.inspect}"
33
+ #puts "node.node_type == :element => #{node.node_type == :element}"
34
+ if node.node_type == :element
35
+ #puts "node.name == #{name} => #{node.name == name}"
36
+ if node.name.downcase == name.downcase
37
+ #puts "node.namespace == #{ns.inspect} => #{node.namespace == ns}"
38
+ end
39
+ end
40
+ !(node.node_type == :element and
41
+ node.name.downcase == name.downcase and
42
+ node.namespace == ns )
43
+ end
44
+ node_types = ELEMENTS
45
+
46
+ when :any
47
+ #puts "ANY 1: nodeset = #{nodeset.inspect}"
48
+ #puts "ANY 1: node_types = #{node_types.inspect}"
49
+ nodeset.delete_if { |node| !node_types.include?(node.node_type) }
50
+ #puts "ANY 2: nodeset = #{nodeset.inspect}"
51
+
52
+ when :self
53
+ # This space left intentionally blank
54
+
55
+ when :processing_instruction
56
+ target = path_stack.shift
57
+ nodeset.delete_if do |node|
58
+ (node.node_type != :processing_instruction) or
59
+ ( target!='' and ( node.target != target ) )
60
+ end
61
+
62
+ when :text
63
+ nodeset.delete_if { |node| node.node_type != :text }
64
+
65
+ when :comment
66
+ nodeset.delete_if { |node| node.node_type != :comment }
67
+
68
+ when :node
69
+ # This space left intentionally blank
70
+ node_types = ALL
71
+
72
+ when :child
73
+ new_nodeset = []
74
+ nt = nil
75
+ for node in nodeset
76
+ nt = node.node_type
77
+ new_nodeset += node.children if nt == :element or nt == :document
78
+ end
79
+ nodeset = new_nodeset
80
+ node_types = ELEMENTS
81
+
82
+ when :literal
83
+ literal = path_stack.shift
84
+ if literal =~ /^\d+(\.\d+)?$/
85
+ return ($1 ? literal.to_f : literal.to_i)
86
+ end
87
+ return literal
88
+
89
+ when :attribute
90
+ new_nodeset = []
91
+ case path_stack.shift
92
+ when :qname
93
+ prefix = path_stack.shift
94
+ name = path_stack.shift
95
+ for element in nodeset
96
+ if element.node_type == :element
97
+ for attribute_name in element.attributes.keys
98
+ if attribute_name.downcase == name.downcase
99
+ attrib = element.attribute( attribute_name,
100
+ @namespaces[prefix] )
101
+ new_nodeset << attrib if attrib
102
+ end
103
+ end
104
+ end
105
+ end
106
+ when :any
107
+ #puts "ANY"
108
+ for element in nodeset
109
+ if element.node_type == :element
110
+ new_nodeset += element.attributes.to_a
111
+ end
112
+ end
113
+ end
114
+ nodeset = new_nodeset
115
+
116
+ when :parent
117
+ #puts "PARENT 1: nodeset = #{nodeset}"
118
+ nodeset = nodeset.collect{|n| n.parent}.compact
119
+ #nodeset = expr(path_stack.dclone, nodeset.collect{|n| n.parent}.compact)
120
+ #puts "PARENT 2: nodeset = #{nodeset.inspect}"
121
+ node_types = ELEMENTS
122
+
123
+ when :ancestor
124
+ new_nodeset = []
125
+ for node in nodeset
126
+ while node.parent
127
+ node = node.parent
128
+ new_nodeset << node unless new_nodeset.include? node
129
+ end
130
+ end
131
+ nodeset = new_nodeset
132
+ node_types = ELEMENTS
133
+
134
+ when :ancestor_or_self
135
+ new_nodeset = []
136
+ for node in nodeset
137
+ if node.node_type == :element
138
+ new_nodeset << node
139
+ while ( node.parent )
140
+ node = node.parent
141
+ new_nodeset << node unless new_nodeset.include? node
142
+ end
143
+ end
144
+ end
145
+ nodeset = new_nodeset
146
+ node_types = ELEMENTS
147
+
148
+ when :predicate
149
+ new_nodeset = []
150
+ subcontext = { :size => nodeset.size }
151
+ pred = path_stack.shift
152
+ nodeset.each_with_index { |node, index|
153
+ subcontext[ :node ] = node
154
+ #puts "PREDICATE SETTING CONTEXT INDEX TO #{index+1}"
155
+ subcontext[ :index ] = index+1
156
+ pc = pred.dclone
157
+ #puts "#{node.hash}) Recursing with #{pred.inspect} and [#{node.inspect}]"
158
+ result = expr( pc, [node], subcontext )
159
+ result = result[0] if result.kind_of? Array and result.length == 1
160
+ #puts "#{node.hash}) Result = #{result.inspect} (#{result.class.name})"
161
+ if result.kind_of? Numeric
162
+ #puts "Adding node #{node.inspect}" if result == (index+1)
163
+ new_nodeset << node if result == (index+1)
164
+ elsif result.instance_of? Array
165
+ #puts "Adding node #{node.inspect}" if result.size > 0
166
+ new_nodeset << node if result.size > 0
167
+ else
168
+ #puts "Adding node #{node.inspect}" if result
169
+ new_nodeset << node if result
170
+ end
171
+ }
172
+ #puts "New nodeset = #{new_nodeset.inspect}"
173
+ #puts "Path_stack = #{path_stack.inspect}"
174
+ nodeset = new_nodeset
175
+ =begin
176
+ predicate = path_stack.shift
177
+ ns = nodeset.clone
178
+ result = expr( predicate, ns )
179
+ #puts "Result = #{result.inspect} (#{result.class.name})"
180
+ #puts "nodeset = #{nodeset.inspect}"
181
+ if result.kind_of? Array
182
+ nodeset = result.zip(ns).collect{|m,n| n if m}.compact
183
+ else
184
+ nodeset = result ? nodeset : []
185
+ end
186
+ #puts "Outgoing NS = #{nodeset.inspect}"
187
+ =end
188
+
189
+ when :descendant_or_self
190
+ rv = descendant_or_self( path_stack, nodeset )
191
+ path_stack.clear
192
+ nodeset = rv
193
+ node_types = ELEMENTS
194
+
195
+ when :descendant
196
+ results = []
197
+ nt = nil
198
+ for node in nodeset
199
+ nt = node.node_type
200
+ results += expr( path_stack.dclone.unshift( :descendant_or_self ),
201
+ node.children ) if nt == :element or nt == :document
202
+ end
203
+ nodeset = results
204
+ node_types = ELEMENTS
205
+
206
+ when :following_sibling
207
+ #puts "FOLLOWING_SIBLING 1: nodeset = #{nodeset}"
208
+ results = []
209
+ for node in nodeset
210
+ all_siblings = node.parent.children
211
+ current_index = all_siblings.index( node )
212
+ following_siblings = all_siblings[ current_index+1 .. -1 ]
213
+ results += expr( path_stack.dclone, following_siblings )
214
+ end
215
+ #puts "FOLLOWING_SIBLING 2: nodeset = #{nodeset}"
216
+ nodeset = results
217
+
218
+ when :preceding_sibling
219
+ results = []
220
+ for node in nodeset
221
+ all_siblings = node.parent.children
222
+ current_index = all_siblings.index( node )
223
+ preceding_siblings = all_siblings[ 0 .. current_index-1 ].reverse
224
+ #results += expr( path_stack.dclone, preceding_siblings )
225
+ end
226
+ nodeset = preceding_siblings
227
+ node_types = ELEMENTS
228
+
229
+ when :preceding
230
+ new_nodeset = []
231
+ for node in nodeset
232
+ new_nodeset += preceding( node )
233
+ end
234
+ #puts "NEW NODESET => #{new_nodeset.inspect}"
235
+ nodeset = new_nodeset
236
+ node_types = ELEMENTS
237
+
238
+ when :following
239
+ new_nodeset = []
240
+ for node in nodeset
241
+ new_nodeset += following( node )
242
+ end
243
+ nodeset = new_nodeset
244
+ node_types = ELEMENTS
245
+
246
+ when :namespace
247
+ new_set = []
248
+ for node in nodeset
249
+ new_nodeset << node.namespace if node.node_type == :element or node.node_type == :attribute
250
+ end
251
+ nodeset = new_nodeset
252
+
253
+ when :variable
254
+ var_name = path_stack.shift
255
+ return @variables[ var_name ]
256
+
257
+ # :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq
258
+ when :eq, :neq, :lt, :lteq, :gt, :gteq, :and, :or
259
+ left = expr( path_stack.shift, nodeset, context )
260
+ #puts "LEFT => #{left.inspect} (#{left.class.name})"
261
+ right = expr( path_stack.shift, nodeset, context )
262
+ #puts "RIGHT => #{right.inspect} (#{right.class.name})"
263
+ res = equality_relational_compare( left, op, right )
264
+ #puts "RES => #{res.inspect}"
265
+ return res
266
+
267
+ when :div
268
+ left = Functions::number(expr(path_stack.shift, nodeset, context)).to_f
269
+ right = Functions::number(expr(path_stack.shift, nodeset, context)).to_f
270
+ return (left / right)
271
+
272
+ when :mod
273
+ left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
274
+ right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
275
+ return (left % right)
276
+
277
+ when :mult
278
+ left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
279
+ right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
280
+ return (left * right)
281
+
282
+ when :plus
283
+ left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
284
+ right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
285
+ return (left + right)
286
+
287
+ when :minus
288
+ left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
289
+ right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
290
+ return (left - right)
291
+
292
+ when :union
293
+ left = expr( path_stack.shift, nodeset, context )
294
+ right = expr( path_stack.shift, nodeset, context )
295
+ return (left | right)
296
+
297
+ when :neg
298
+ res = expr( path_stack, nodeset, context )
299
+ return -(res.to_f)
300
+
301
+ when :not
302
+ when :function
303
+ func_name = path_stack.shift.tr('-','_')
304
+ arguments = path_stack.shift
305
+ #puts "FUNCTION 0: #{func_name}(#{arguments.collect{|a|a.inspect}.join(', ')})"
306
+ subcontext = context ? nil : { :size => nodeset.size }
307
+
308
+ res = []
309
+ cont = context
310
+ nodeset.each_with_index { |n, i|
311
+ if subcontext
312
+ subcontext[:node] = n
313
+ subcontext[:index] = i
314
+ cont = subcontext
315
+ end
316
+ arg_clone = arguments.dclone
317
+ args = arg_clone.collect { |arg|
318
+ #puts "FUNCTION 1: Calling expr( #{arg.inspect}, [#{n.inspect}] )"
319
+ expr( arg, [n], cont )
320
+ }
321
+ #puts "FUNCTION 2: #{func_name}(#{args.collect{|a|a.inspect}.join(', ')})"
322
+ Functions.context = cont
323
+ res << Functions.send( func_name, *args )
324
+ #puts "FUNCTION 3: #{res[-1].inspect}"
325
+ }
326
+ return res
327
+
328
+ end
329
+ end # while
330
+ #puts "EXPR returning #{nodeset.inspect}"
331
+ return nodeset
332
+ end
333
+
334
+ # Monkey Patch for Ruby 1.8.2
335
+ def internal_parse(path_stack, nodeset) # :nodoc:
336
+ return nodeset if nodeset.size == 0 or path_stack.size == 0
337
+ case path_stack.shift
338
+ when :document
339
+ return [ nodeset[0].root.parent ]
340
+
341
+ when :qname
342
+ prefix = path_stack.shift.downcase
343
+ name = path_stack.shift.downcase
344
+ n = nodeset.clone
345
+ ns = @namespaces[prefix]
346
+ ns = ns ? ns : ''
347
+ n.delete_if do |node|
348
+ if node.node_type == :element and ns == ''
349
+ ns = node.namespace( prefix )
350
+ end
351
+ !(node.node_type == :element and
352
+ node.name.downcase == name.downcase and node.namespace == ns )
353
+ end
354
+ return n
355
+
356
+ when :any
357
+ n = nodeset.clone
358
+ n.delete_if { |node| node.node_type != :element }
359
+ return n
360
+
361
+ when :self
362
+ # THIS SPACE LEFT INTENTIONALLY BLANK
363
+
364
+ when :processing_instruction
365
+ target = path_stack.shift
366
+ n = nodeset.clone
367
+ n.delete_if do |node|
368
+ (node.node_type != :processing_instruction) or
369
+ ( !target.nil? and ( node.target != target ) )
370
+ end
371
+ return n
372
+
373
+ when :text
374
+ n = nodeset.clone
375
+ n.delete_if do |node|
376
+ node.node_type != :text
377
+ end
378
+ return n
379
+
380
+ when :comment
381
+ n = nodeset.clone
382
+ n.delete_if do |node|
383
+ node.node_type != :comment
384
+ end
385
+ return n
386
+
387
+ when :node
388
+ return nodeset
389
+
390
+ when :child
391
+ new_nodeset = []
392
+ nt = nil
393
+ for node in nodeset
394
+ nt = node.node_type
395
+ new_nodeset += node.children if nt == :element or nt == :document
396
+ end
397
+ return new_nodeset
398
+
399
+ when :literal
400
+ literal = path_stack.shift
401
+ if literal =~ /^\d+(\.\d+)?$/
402
+ return ($1 ? literal.to_f : literal.to_i)
403
+ end
404
+ return literal
405
+
406
+ when :attribute
407
+ new_nodeset = []
408
+ case path_stack.shift
409
+ when :qname
410
+ prefix = path_stack.shift
411
+ name = path_stack.shift
412
+ for element in nodeset
413
+ if element.node_type == :element
414
+ for attribute_name in element.attributes.keys
415
+ if attribute_name.downcase == name.downcase
416
+ attrib = element.attribute( attribute_name,
417
+ @namespaces[prefix] )
418
+ new_nodeset << attrib if attrib
419
+ end
420
+ end
421
+ end
422
+ end
423
+ when :any
424
+ for element in nodeset
425
+ if element.node_type == :element
426
+ new_nodeset += element.attributes.to_a
427
+ end
428
+ end
429
+ end
430
+ return new_nodeset
431
+
432
+ when :parent
433
+ return internal_parse( path_stack,
434
+ nodeset.collect{|n| n.parent}.compact )
435
+
436
+ when :ancestor
437
+ new_nodeset = []
438
+ for node in nodeset
439
+ while node.parent
440
+ node = node.parent
441
+ new_nodeset << node unless new_nodeset.include? node
442
+ end
443
+ end
444
+ return new_nodeset
445
+
446
+ when :ancestor_or_self
447
+ new_nodeset = []
448
+ for node in nodeset
449
+ if node.node_type == :element
450
+ new_nodeset << node
451
+ while ( node.parent )
452
+ node = node.parent
453
+ new_nodeset << node unless new_nodeset.include? node
454
+ end
455
+ end
456
+ end
457
+ return new_nodeset
458
+
459
+ when :predicate
460
+ predicate = path_stack.shift
461
+ new_nodeset = []
462
+ Functions::size = nodeset.size
463
+ nodeset.size.times do |index|
464
+ node = nodeset[index]
465
+ Functions::node = node
466
+ Functions::index = index+1
467
+ result = Predicate( predicate, node )
468
+ if result.kind_of? Numeric
469
+ new_nodeset << node if result == (index+1)
470
+ elsif result.instance_of? Array
471
+ new_nodeset << node if result.size > 0
472
+ else
473
+ new_nodeset << node if result
474
+ end
475
+ end
476
+ return new_nodeset
477
+
478
+ when :descendant_or_self
479
+ rv = descendant_or_self( path_stack, nodeset )
480
+ path_stack.clear
481
+ return rv
482
+
483
+ when :descendant
484
+ results = []
485
+ nt = nil
486
+ for node in nodeset
487
+ nt = node.node_type
488
+ if nt == :element or nt == :document
489
+ results += internal_parse(
490
+ path_stack.clone.unshift( :descendant_or_self ),
491
+ node.children )
492
+ end
493
+ end
494
+ return results
495
+
496
+ when :following_sibling
497
+ results = []
498
+ for node in nodeset
499
+ all_siblings = node.parent.children
500
+ current_index = all_siblings.index( node )
501
+ following_siblings = all_siblings[ current_index+1 .. -1 ]
502
+ results += internal_parse( path_stack.clone, following_siblings )
503
+ end
504
+ return results
505
+
506
+ when :preceding_sibling
507
+ results = []
508
+ for node in nodeset
509
+ all_siblings = node.parent.children
510
+ current_index = all_siblings.index( node )
511
+ preceding_siblings = all_siblings[ 0 .. current_index-1 ]
512
+ results += internal_parse( path_stack.clone, preceding_siblings )
513
+ end
514
+ return results
515
+
516
+ when :preceding
517
+ new_nodeset = []
518
+ for node in nodeset
519
+ new_nodeset += preceding( node )
520
+ end
521
+ return new_nodeset
522
+
523
+ when :following
524
+ new_nodeset = []
525
+ for node in nodeset
526
+ new_nodeset += following( node )
527
+ end
528
+ return new_nodeset
529
+
530
+ when :namespace
531
+ new_set = []
532
+ for node in nodeset
533
+ if node.node_type == :element or node.node_type == :attribute
534
+ new_nodeset << node.namespace
535
+ end
536
+ end
537
+ return new_nodeset
538
+
539
+ when :variable
540
+ var_name = path_stack.shift
541
+ return @variables[ var_name ]
542
+
543
+ end
544
+ nodeset
545
+ end
546
+ end
547
+
548
+ class XPath # :nodoc:
549
+ def self.liberal_match(element, path=nil, namespaces={},
550
+ variables={}) # :nodoc:
551
+ parser = LiberalXPathParser.new
552
+ parser.namespaces = namespaces
553
+ parser.variables = variables
554
+ path = "*" unless path
555
+ element = [element] unless element.kind_of? Array
556
+ parser.parse(path, element)
557
+ end
558
+
559
+ def self.liberal_first(element, path=nil, namespaces={},
560
+ variables={}) # :nodoc:
561
+ parser = LiberalXPathParser.new
562
+ parser.namespaces = namespaces
563
+ parser.variables = variables
564
+ path = "*" unless path
565
+ element = [element] unless element.kind_of? Array
566
+ parser.parse(path, element)[0]
567
+ end
568
+
569
+ def self.liberal_each(element, path=nil, namespaces={},
570
+ variables={}, &block) # :nodoc:
571
+ parser = LiberalXPathParser.new
572
+ parser.namespaces = namespaces
573
+ parser.variables = variables
574
+ path = "*" unless path
575
+ element = [element] unless element.kind_of? Array
576
+ parser.parse(path, element).each( &block )
577
+ end
578
+ end
579
+
580
+ class Element # :nodoc:
581
+ unless REXML::Element.public_instance_methods.include? :inner_xml
582
+ def inner_xml # :nodoc:
583
+ result = ""
584
+ self.each_child do |child|
585
+ if child.kind_of? REXML::Comment
586
+ result << "<!--" + child.to_s + "-->"
587
+ else
588
+ result << child.to_s
589
+ end
590
+ end
591
+ return result.strip
592
+ end
593
+ else
594
+ warn("inner_xml method already exists.")
595
+ end
596
+
597
+ def base_uri # :nodoc:
598
+ begin
599
+ base_attribute = FeedTools::XmlHelper.try_xpaths(self, [
600
+ '@xml:base'
601
+ ])
602
+ if parent == nil || parent.kind_of?(REXML::Document)
603
+ return nil if base_attribute == nil
604
+ return base_attribute.value
605
+ end
606
+ if base_attribute != nil && parent == nil
607
+ return base_attribute.value
608
+ elsif parent != nil && base_attribute == nil
609
+ return parent.base_uri
610
+ elsif parent != nil && base_attribute != nil
611
+ parent_base_uri = parent.base_uri
612
+ if parent_base_uri != nil
613
+ uri = URI.parse(parent_base_uri)
614
+ return (uri + base_attribute.value).to_s
615
+ else
616
+ return base_attribute.value
617
+ end
618
+ end
619
+ return nil
620
+ rescue
621
+ return nil
622
+ end
623
+ end
624
+ end
625
+ end