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
|
-
|
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
|