astro-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.
@@ -0,0 +1,38 @@
|
|
1
|
+
module SAXMachine
|
2
|
+
class NSStack < Hash
|
3
|
+
def initialize(parent=nil, attrs=[])
|
4
|
+
# Initialize
|
5
|
+
super()
|
6
|
+
@parent = parent
|
7
|
+
|
8
|
+
# Parse attributes
|
9
|
+
attrs.each do |attr|
|
10
|
+
if attr.kind_of?(Array)
|
11
|
+
k, v = attr
|
12
|
+
case k
|
13
|
+
when 'xmlns' then self[''] = v
|
14
|
+
when /^xmlns:(.+)/ then self[$1] = v
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Lookup
|
21
|
+
def [](name)
|
22
|
+
if (ns = super(name.to_s))
|
23
|
+
# I've got it
|
24
|
+
ns
|
25
|
+
elsif @parent
|
26
|
+
# Parent may have it
|
27
|
+
@parent[name]
|
28
|
+
else
|
29
|
+
# Undefined, empty namespace
|
30
|
+
''
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def pop
|
35
|
+
@parent
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -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
|
@@ -129,4 +118,4 @@ module SAXMachine
|
|
129
118
|
end
|
130
119
|
|
131
120
|
end
|
132
|
-
end
|
121
|
+
end
|
@@ -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
|
@@ -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: astro-sax-machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Dix
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- lib/sax-machine/sax_element_config.rb
|
38
38
|
- lib/sax-machine/sax_document.rb
|
39
39
|
- lib/sax-machine/sax_handler.rb
|
40
|
+
- lib/sax-machine/ns_stack.rb
|
40
41
|
- README.textile
|
41
42
|
- Rakefile
|
42
43
|
- spec/spec.opts
|