julien51-sax-machine 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,12 +29,17 @@ module SAXMachine
29
29
  end
30
30
  end
31
31
 
32
- def element_config_for_tag(name, attrs)
32
+ def element_config_for_tag(name, attrs, nsstack)
33
+ prefix, name = name.split(':', 2)
34
+ prefix, name = nil, prefix unless name # No prefix
35
+ namespace = nsstack[prefix]
36
+
33
37
  @top_level_elements.detect do |element_config|
34
38
  element_config.name == name &&
39
+ element_config.xmlns_match?(namespace) &&
35
40
  element_config.attrs_match?(attrs)
36
41
  end
37
42
  end
38
43
 
39
44
  end
40
- end
45
+ end
@@ -39,7 +39,7 @@ module SAXMachine
39
39
  # this is how we allow custom parsing behavior. So you could define the setter
40
40
  # and have it parse the string into a date or whatever.
41
41
  attr_reader options[:as] unless instance_methods.include?(options[:as].to_s)
42
- attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
42
+ attr_writer_once options[:as] unless instance_methods.include?("#{options[:as]}=")
43
43
  end
44
44
 
45
45
  def columns
@@ -89,6 +89,14 @@ module SAXMachine
89
89
  def sax_config
90
90
  @sax_config ||= SAXConfig.new
91
91
  end
92
+
93
+ def attr_writer_once(attr)
94
+ class_eval <<-SRC
95
+ def #{attr}=(val)
96
+ @#{attr} ||= val
97
+ end
98
+ SRC
99
+ end
92
100
  end
93
101
 
94
102
  end
@@ -30,6 +30,12 @@ module SAXMachine
30
30
  end
31
31
  @data_class = options[:class]
32
32
  @required = options[:required]
33
+
34
+ @xmlns = case options[:xmlns]
35
+ when Array then options[:xmlns]
36
+ when String then [options[:xmlns]]
37
+ else nil
38
+ end
33
39
  end
34
40
 
35
41
  def column
@@ -55,6 +61,10 @@ module SAXMachine
55
61
  def has_value_and_attrs_match?(attrs)
56
62
  !@value.nil? && attrs_match?(attrs)
57
63
  end
64
+
65
+ def xmlns_match?(ns)
66
+ @xmlns.nil? || @xmlns.include?(ns)
67
+ end
58
68
 
59
69
  def collection?
60
70
  @collection
@@ -62,4 +72,4 @@ module SAXMachine
62
72
  end
63
73
 
64
74
  end
65
- end
75
+ end
@@ -1,4 +1,5 @@
1
1
  require "nokogiri"
2
+ require "sax-machine/ns_stack"
2
3
 
3
4
  module SAXMachine
4
5
  class SAXHandler < Nokogiri::XML::SAX::Document
@@ -6,7 +7,7 @@ module SAXMachine
6
7
 
7
8
  def initialize(object)
8
9
  @object = object
9
- @parsed_configs = {}
10
+ @nsstack = nil
10
11
  end
11
12
 
12
13
  def characters(string)
@@ -25,6 +26,7 @@ module SAXMachine
25
26
 
26
27
  @name = name
27
28
  @attrs = attrs.map { |a| SAXHandler.decode_xml(a) }
29
+ @nsstack = NSStack.new(@nsstack, @attrs)
28
30
 
29
31
  if parsing_collection?
30
32
  @collection_handler.start_element(@name, @attrs)
@@ -51,11 +53,11 @@ module SAXMachine
51
53
  @collection_handler.end_element(name)
52
54
 
53
55
  elsif characaters_captured?
54
- mark_as_parsed
55
56
  @object.send(@element_config.setter, @value)
56
57
  end
57
58
 
58
59
  reset_current_tag
60
+ @nsstack = @nsstack.pop
59
61
  end
60
62
 
61
63
  def characaters_captured?
@@ -75,27 +77,14 @@ module SAXMachine
75
77
 
76
78
  def parse_element_attributes(element_configs)
77
79
  element_configs.each do |ec|
78
- unless parsed_config?(ec)
79
- @object.send(ec.setter, ec.value_from_attrs(@attrs))
80
- mark_as_parsed(ec)
81
- end
80
+ @object.send(ec.setter, ec.value_from_attrs(@attrs))
82
81
  end
83
82
  @element_config = nil
84
83
  end
85
84
 
86
85
  def set_element_config_for_element_value
87
86
  @value = ""
88
- @element_config = sax_config.element_config_for_tag(@name, @attrs)
89
- end
90
-
91
- def mark_as_parsed(element_config=nil)
92
- element_config ||= @element_config
93
- @parsed_configs[element_config] = true unless element_config.collection?
94
- end
95
-
96
- def parsed_config?(element_config=nil)
97
- element_config ||= @element_config
98
- @parsed_configs[element_config]
87
+ @element_config = sax_config.element_config_for_tag(@name, @attrs, @nsstack)
99
88
  end
100
89
 
101
90
  def reset_current_collection
@@ -119,14 +108,15 @@ module SAXMachine
119
108
  def self.decode_xml(str)
120
109
  return str.map &method(:decode_xml) if str.kind_of?(Array)
121
110
 
122
- entities = {
123
- '#38' => '&amp;',
124
- '#13' => "\r",
125
- }
126
- entities.keys.inject(str) { |string, key|
127
- string.gsub(/&#{key};/, entities[key])
128
- }
111
+ # entities = {
112
+ # '#38' => '&amp;',
113
+ # '#13' => "\r",
114
+ # }
115
+ # entities.keys.inject(str) { |string, key|
116
+ # string.gsub(/&#{key};/, entities[key])
117
+ # }
118
+ CGI.unescapeHTML(str)
129
119
  end
130
120
 
131
121
  end
132
- end
122
+ end
data/lib/sax-machine.rb CHANGED
@@ -1,7 +1,7 @@
1
- require "rubygems"
2
-
3
1
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
4
2
 
3
+ require "cgi"
4
+
5
5
  require "sax-machine/sax_document"
6
6
  require "sax-machine/sax_handler"
7
7
  require "sax-machine/sax_config"
@@ -62,11 +62,11 @@ describe "SAXMachine" do
62
62
  document.title.should == "Title"
63
63
  end
64
64
 
65
- it "should overwrite the value when the element is present" do
65
+ it "should *not* overwrite the value when the element is present (new behaviour!)" do
66
66
  document = @klass.new
67
67
  document.title = "Old title"
68
68
  document.parse("<title>New title</title>")
69
- document.title.should == "New title"
69
+ document.title.should == "Old title"
70
70
  end
71
71
 
72
72
  it "should save the element text into an accessor" do
@@ -138,7 +138,7 @@ describe "SAXMachine" do
138
138
 
139
139
  it "should escape correctly the ampersand" do
140
140
  document = @klass.parse("<link href='http://api.flickr.com/services/feeds/photos_public.gne?id=49724566@N00&amp;lang=en-us&amp;format=atom' foo='bar'>asdf</link>")
141
- document.link.should == "http://api.flickr.com/services/feeds/photos_public.gne?id=49724566@N00&amp;lang=en-us&amp;format=atom"
141
+ document.link.should == "http://api.flickr.com/services/feeds/photos_public.gne?id=49724566@N00&lang=en-us&format=atom"
142
142
  end
143
143
 
144
144
  it "should save the value of a matching element" do
@@ -281,6 +281,52 @@ describe "SAXMachine" do
281
281
  document.link_bar.should == 'test2'
282
282
  end
283
283
  end
284
+
285
+ describe "when specifying namespaces" do
286
+ before :all do
287
+ @klass = Class.new do
288
+ include SAXMachine
289
+ element :a, :xmlns => 'urn:test'
290
+ element :b, :xmlns => ['', 'urn:test']
291
+ end
292
+ end
293
+
294
+ it "should get the element with the xmlns" do
295
+ document = @klass.parse("<a xmlns='urn:test'>hello</a>")
296
+ document.a.should == 'hello'
297
+ end
298
+
299
+ it "shouldn't get the element without the xmlns" do
300
+ document = @klass.parse("<a>hello</a>")
301
+ document.a.should be_nil
302
+ end
303
+
304
+ it "shouldn't get the element with the wrong xmlns" do
305
+ document = @klass.parse("<a xmlns='urn:test2'>hello</a>")
306
+ document.a.should be_nil
307
+ end
308
+
309
+ it "should get an element without xmlns if the empty namespace is desired" do
310
+ document = @klass.parse("<b>hello</b>")
311
+ document.b.should == 'hello'
312
+ end
313
+
314
+ it "should get an element with the right prefix" do
315
+ document = @klass.parse("<p:a xmlns:p='urn:test'>hello</p:a>")
316
+ document.a.should == 'hello'
317
+ end
318
+
319
+ it "should not get an element with the wrong prefix" do
320
+ document = @klass.parse("<x:a xmlns:p='urn:test' xmlns:x='urn:test2'>hello</x:a>")
321
+ document.a.should be_nil
322
+ end
323
+
324
+ it "should get a prefixed element without xmlns if the empty namespace is desired" do
325
+ pending "this needs a less pickier nokogiri push parser"
326
+ document = @klass.parse("<x:b>hello</x:b>")
327
+ document.b.should == 'hello'
328
+ end
329
+ end
284
330
 
285
331
  end
286
332
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: julien51-sax-machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Dix