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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
-
|
124
|
-
|
125
|
-
}
|
126
|
-
entities.keys.inject(str) { |string, key|
|
127
|
-
|
128
|
-
}
|
111
|
+
# entities = {
|
112
|
+
# '#38' => '&',
|
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 == "
|
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&lang=en-us&format=atom' foo='bar'>asdf</link>")
|
141
|
-
document.link.should == "http://api.flickr.com/services/feeds/photos_public.gne?id=49724566@N00&
|
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
|