julien51-sax-machine 0.0.14 → 0.0.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.
@@ -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