rsxml 0.1.4 → 0.2.0
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.
- data/README.rdoc +47 -6
- data/VERSION +1 -1
- data/lib/rsxml.rb +23 -149
- data/lib/rsxml/namespace.rb +175 -0
- data/lib/rsxml/sexp.rb +90 -0
- data/lib/rsxml/util.rb +25 -0
- data/lib/rsxml/visitor.rb +132 -0
- data/lib/rsxml/xml.rb +99 -0
- data/spec/rsxml/namespace_spec.rb +250 -0
- data/spec/rsxml/sexp_spec.rb +15 -0
- data/spec/rsxml/util_spec.rb +41 -0
- data/spec/rsxml/visitor_spec.rb +82 -0
- data/spec/rsxml/xml_spec.rb +68 -0
- data/spec/rsxml_spec.rb +88 -32
- metadata +20 -5
data/lib/rsxml/util.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rsxml
|
2
|
+
module Util
|
3
|
+
module_function
|
4
|
+
|
5
|
+
# simple option checking, with value constraints and sub-hash checking
|
6
|
+
def check_opts(constraints, opts)
|
7
|
+
opts ||= {}
|
8
|
+
opts.each{|k,v| raise "opt not permitted: #{k.inspect}" if !constraints.has_key?(k)}
|
9
|
+
Hash[constraints.map do |k,constraint|
|
10
|
+
if opts.has_key?(k)
|
11
|
+
v = opts[k]
|
12
|
+
if constraint.is_a?(Array)
|
13
|
+
raise "unknown value for opt #{k.inspect}: #{v.inspect}. permitted values are: #{constraint.inspect}" if !constraint.include?(v)
|
14
|
+
[k,v]
|
15
|
+
elsif constraint.is_a?(Hash)
|
16
|
+
raise "opt #{k.inspect} must be a Hash" if !v.is_a?(Hash)
|
17
|
+
[k,check_opts(constraint, v || {})]
|
18
|
+
else
|
19
|
+
[k,v]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Rsxml
|
2
|
+
module Visitor
|
3
|
+
class << self
|
4
|
+
include Util
|
5
|
+
end
|
6
|
+
|
7
|
+
class Context
|
8
|
+
attr_reader :ns_stack
|
9
|
+
attr_reader :node_stack
|
10
|
+
attr_reader :prev_siblings
|
11
|
+
def initialize(initial_ns_bindings = nil)
|
12
|
+
@ns_stack=[]
|
13
|
+
@ns_stack << initial_ns_bindings if initial_ns_bindings
|
14
|
+
@node_stack=[]
|
15
|
+
@prev_siblings=[]
|
16
|
+
@sibling_stack=[]
|
17
|
+
end
|
18
|
+
|
19
|
+
def push_node(node)
|
20
|
+
node_stack.push(node)
|
21
|
+
@sibling_stack.push(@prev_siblings)
|
22
|
+
@prev_siblings=[]
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop_node
|
26
|
+
n = node_stack.pop
|
27
|
+
@prev_siblings = @sibling_stack.pop
|
28
|
+
@prev_siblings << n
|
29
|
+
end
|
30
|
+
|
31
|
+
def processed_node(node)
|
32
|
+
@prev_siblings << node
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class WriteXmlVisitor
|
37
|
+
attr_reader :xml
|
38
|
+
|
39
|
+
def initialize(xml_builder=nil)
|
40
|
+
@xml = xml_builder || Builder::XmlMarkup.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def tag(context, name, attrs)
|
44
|
+
qname = Namespace::compact_qname(context.ns_stack, name)
|
45
|
+
qattrs = Namespace::compact_attr_qnames(context.ns_stack, attrs)
|
46
|
+
|
47
|
+
xml.__send__(qname, qattrs) do
|
48
|
+
yield
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def text(context, text)
|
53
|
+
xml << text
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
xml.target!
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class BuildRsxmlVisitor
|
62
|
+
attr_reader :sexp
|
63
|
+
attr_reader :cursor_stack
|
64
|
+
attr_reader :opts
|
65
|
+
|
66
|
+
# The <tt>:style</tt> option specifies how the Rsxml is to be produced
|
67
|
+
# :xml style is with compact <tt>"prefix:local_name"</tt> Strings for QNames, and namespace declaration attributes
|
68
|
+
# :exploded style is with <tt>[local_name, prefix, uri]</tt> triples for QNames, and no namespace declaration attributes
|
69
|
+
OPTS = {:style=>[:xml, :exploded]}
|
70
|
+
|
71
|
+
def initialize(opts=nil)
|
72
|
+
@opts = opts || {}
|
73
|
+
opts = Util.check_opts(OPTS, opts)
|
74
|
+
@cursor_stack = []
|
75
|
+
@sexp
|
76
|
+
end
|
77
|
+
|
78
|
+
def compact_qname(qname)
|
79
|
+
local_name, prefix, uri = qname
|
80
|
+
|
81
|
+
[prefix, local_name].map{|s| (!s || s.empty?) ? nil : s}.compact.join(":")
|
82
|
+
end
|
83
|
+
|
84
|
+
def compact_attr_names(attrs)
|
85
|
+
Hash[attrs.map{|qname,value| [compact_qname(qname), value]}]
|
86
|
+
end
|
87
|
+
|
88
|
+
# strip namespace decls from exploded attributes
|
89
|
+
def strip_namespace_decls(attrs)
|
90
|
+
Hash[attrs.map do |qname,value|
|
91
|
+
local_name, prefix, uri = qname
|
92
|
+
if !(prefix=="xmlns" || (prefix==nil && local_name=="xmlns"))
|
93
|
+
[qname,value]
|
94
|
+
end
|
95
|
+
end.compact]
|
96
|
+
end
|
97
|
+
|
98
|
+
def tag(context, tag, attrs)
|
99
|
+
|
100
|
+
opts[:style] ||= :exploded
|
101
|
+
if opts[:style] == :xml
|
102
|
+
tag = compact_qname(tag)
|
103
|
+
attrs = compact_attr_names(attrs)
|
104
|
+
elsif opts[:style] == :exploded
|
105
|
+
attrs = strip_namespace_decls(attrs)
|
106
|
+
end
|
107
|
+
|
108
|
+
el = [tag, (attrs if attrs.size>0)].compact
|
109
|
+
|
110
|
+
if !cursor_stack.last
|
111
|
+
@sexp = el
|
112
|
+
else
|
113
|
+
cursor_stack.last << el
|
114
|
+
end
|
115
|
+
cursor_stack.push(el)
|
116
|
+
|
117
|
+
begin
|
118
|
+
yield
|
119
|
+
ensure
|
120
|
+
cursor_stack.pop
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def text(context, text)
|
125
|
+
cursor_stack.last << text
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
data/lib/rsxml/xml.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
module Rsxml
|
2
|
+
module Xml
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
WRAP_ELEMENT = "RsxmlXmlWrapper"
|
7
|
+
|
8
|
+
def wrap_fragment(fragment, ns_prefixes)
|
9
|
+
return fragment if !ns_prefixes
|
10
|
+
|
11
|
+
ns_attrs = Hash[ns_prefixes.map do |prefix,href|
|
12
|
+
prefix = nil if prefix.to_s.length == 0
|
13
|
+
[["xmlns", prefix].compact.join(":"), href]
|
14
|
+
end]
|
15
|
+
xml = Builder::XmlMarkup.new
|
16
|
+
xml.__send__(WRAP_ELEMENT, ns_attrs) do
|
17
|
+
xml << fragment
|
18
|
+
end
|
19
|
+
xml.target!
|
20
|
+
end
|
21
|
+
|
22
|
+
def unwrap_fragment(node)
|
23
|
+
if node.name==WRAP_ELEMENT
|
24
|
+
node.children.first
|
25
|
+
else
|
26
|
+
node
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def explode_node(node)
|
31
|
+
node_name = node.name
|
32
|
+
if node.namespace
|
33
|
+
node_prefix = node.namespace.prefix || "" # nokogiri has nil prefix for default namespace
|
34
|
+
node_uri = node.namespace.href
|
35
|
+
end
|
36
|
+
node = node_uri ? [node_name, node_prefix, node_uri] : node_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def explode_ns_definitions(element)
|
40
|
+
Hash[element.namespace_definitions.map do |ns|
|
41
|
+
if ns.prefix
|
42
|
+
[[ns.prefix, "xmlns"], ns.href]
|
43
|
+
else
|
44
|
+
["xmlns", ns.href]
|
45
|
+
end
|
46
|
+
end]
|
47
|
+
end
|
48
|
+
|
49
|
+
# given a <tt>Nokogiri::XML::Element</tt> in +element+ , produce
|
50
|
+
# a <tt>[[local_name, prefix, namespace], {[local_name, prefix, namespace]=>value}</tt>
|
51
|
+
# pair of exploded element name and attributes with exploded names
|
52
|
+
def explode_element(element)
|
53
|
+
eelement = explode_node(element)
|
54
|
+
|
55
|
+
eattrs = Hash[element.attributes.map do |name,attr|
|
56
|
+
[explode_node(attr), attr.value]
|
57
|
+
end]
|
58
|
+
|
59
|
+
ns_decl_attrs = explode_ns_definitions(element)
|
60
|
+
eattrs = eattrs.merge(ns_decl_attrs)
|
61
|
+
|
62
|
+
[eelement, eattrs]
|
63
|
+
end
|
64
|
+
|
65
|
+
# pre-order traversal of the Nokogiri Nodes, calling methods on
|
66
|
+
# the visitor with each Node
|
67
|
+
def traverse(element, visitor, context = Visitor::Context.new)
|
68
|
+
eelement, eattrs = explode_element(element)
|
69
|
+
|
70
|
+
ns_bindings = Rsxml::Namespace.extract_declared_namespace_bindings(element.namespaces)
|
71
|
+
context.ns_stack.push(ns_bindings)
|
72
|
+
|
73
|
+
begin
|
74
|
+
visitor.tag(context, eelement, eattrs) do
|
75
|
+
context.push_node([eelement, eattrs])
|
76
|
+
begin
|
77
|
+
element.children.each do |child|
|
78
|
+
if child.element?
|
79
|
+
traverse(child, visitor, context)
|
80
|
+
elsif child.text?
|
81
|
+
visitor.text(context, child.content)
|
82
|
+
context.processed_node(child.content)
|
83
|
+
else
|
84
|
+
Rsxml.log{|logger| logger.warn("unknown Nokogiri Node type: #{child.inspect}")}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
ensure
|
88
|
+
context.pop_node
|
89
|
+
end
|
90
|
+
end
|
91
|
+
ensure
|
92
|
+
context.ns_stack.pop
|
93
|
+
end
|
94
|
+
|
95
|
+
visitor
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Rsxml
|
4
|
+
describe "find_namespace_uri" do
|
5
|
+
it "should find a namespace uri in a stack of prefix bindings" do
|
6
|
+
Namespace.find_namespace_uri([{"foo"=>"http://foo.com/foo"},
|
7
|
+
{"bar"=>"http://bar.com/bar"}],
|
8
|
+
"bar").should == "http://bar.com/bar"
|
9
|
+
Namespace.find_namespace_uri([{"foo"=>"http://foo.com/foo"},
|
10
|
+
{"bar"=>"http://bar.com/bar"}],
|
11
|
+
"foo").should == "http://foo.com/foo"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return nil if there is no matching binding" do
|
15
|
+
Namespace.find_namespace_uri([{"foo"=>"http://foo.com/foo"},
|
16
|
+
{"bar"=>"http://bar.com/bar"}],
|
17
|
+
"blah").should == nil
|
18
|
+
Namespace.find_namespace_uri([],
|
19
|
+
"blah").should == nil
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "explode_qname" do
|
25
|
+
it "should do nothing to an array with more than one element" do
|
26
|
+
Namespace.explode_qname([], ["bar", "foo", "http://foo.com/foo"]).should ==
|
27
|
+
["bar", "foo", "http://foo.com/foo"]
|
28
|
+
Namespace.explode_qname([], ["bar", "foo"]).should ==
|
29
|
+
["bar", "foo"]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return the first element of an array with only the first non-nil element" do
|
33
|
+
Namespace.explode_qname([], ["bar"]).should ==
|
34
|
+
"bar"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should raise an error if prefix is nil but uri is not" do
|
38
|
+
lambda {
|
39
|
+
Namespace.explode_qname([], ["bar", nil, "http://foo.com/foo"])
|
40
|
+
}.should raise_error(/invalid name/)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should unqualify an unprefixed name with no default namespace" do
|
44
|
+
Namespace.explode_qname([], "bar").should == "bar"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should unqualify an unprefixed name in the default namespace" do
|
48
|
+
Namespace.explode_qname([{""=>"http://foo.com/foo"}], "bar").should ==
|
49
|
+
["bar", "", "http://foo.com/foo"]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should unqualify a prefixed name with a bound namespace" do
|
53
|
+
Namespace.explode_qname([{"foo"=>"http://foo.com/foo"}], "foo:bar").should ==
|
54
|
+
["bar", "foo", "http://foo.com/foo"]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should raise an error with a prefixed name with no bound namespace" do
|
58
|
+
lambda {
|
59
|
+
Namespace.explode_qname([], "foo:bar")
|
60
|
+
}.should raise_error(/not bound/)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "split_qname" do
|
65
|
+
it "should split a name with prefix" do
|
66
|
+
Namespace.split_qname("foo:bar").should == ["bar", "foo"]
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should leave a name without prefix unchanged" do
|
70
|
+
Namespace.split_qname("bar").should == "bar"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should leave an array unchanged" do
|
74
|
+
Namespace.split_qname(["bar", "foo"]).should == ["bar", "foo"]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "compact_attr_qnames" do
|
79
|
+
it "should qualify attribute names when there is a default namespaces" do
|
80
|
+
Namespace.compact_attr_qnames([{""=>"http://default.com/default","foo"=>"http://foo.com/foo"}], {["bar", "foo"] => "barbar", ["boo", ""] => "booboo", "baz" =>"bazbaz"}).should ==
|
81
|
+
{"foo:bar"=>"barbar", "boo"=>"booboo", "baz"=>"bazbaz"}
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should raise an exception if a namespace is referenced but not bound" do
|
85
|
+
lambda {
|
86
|
+
Namespace.compact_attr_qnames([], {["bar", "foo"] => "barbar", "baz" =>"bazbaz"})
|
87
|
+
}.should raise_error(/not bound/)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should raise an exception if default namespace referenced but not bound" do
|
91
|
+
lambda {
|
92
|
+
Namespace.compact_attr_qnames([{"foo"=>"http://foo.com/foo"}], {["bar", "foo"] => "barbar", ["boo", ""] => "booboo", "baz" =>"bazbaz"})
|
93
|
+
}.should raise_error(/not bound/)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "explode_attr_qnames" do
|
98
|
+
it "should unqualify attributes when there is no default namespace" do
|
99
|
+
Namespace.explode_attr_qnames([{"foo"=>"http://foo.com/foo"}], {"foo:bar"=>"barbar", "baz"=>"bazbaz"}).should ==
|
100
|
+
{["bar", "foo", "http://foo.com/foo"]=>"barbar", "baz"=>"bazbaz"}
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should unqualify attributes when there is a default namespace" do
|
104
|
+
Namespace.explode_attr_qnames([{""=>"http://default.com/default", "foo"=>"http://foo.com/foo"}], {"foo:bar"=>"barbar", "baz"=>"bazbaz"}).should ==
|
105
|
+
{["bar", "foo", "http://foo.com/foo"]=>"barbar", "baz"=>"bazbaz"}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "compact_qname" do
|
110
|
+
it "should produce a qname from a pair or triple" do
|
111
|
+
Namespace.compact_qname([{"foo"=>"http://foo.com/foo"}],
|
112
|
+
["bar", "foo"]).should ==
|
113
|
+
"foo:bar"
|
114
|
+
Namespace.compact_qname([{"foo"=>"http://foo.com/foo"}],
|
115
|
+
["bar", "foo", "http://foo.com/foo"]).should ==
|
116
|
+
"foo:bar"
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should produce a qname with default namespace" do
|
120
|
+
Namespace.compact_qname([{""=>"http://foo.com/foo"}],
|
121
|
+
["bar", ""]).should ==
|
122
|
+
"bar"
|
123
|
+
|
124
|
+
Namespace.compact_qname([{""=>"http://foo.com/foo"}],
|
125
|
+
["bar", "", "http://foo.com/foo"]).should ==
|
126
|
+
"bar"
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should do nothing to a String" do
|
130
|
+
Namespace.compact_qname([], "foo:bar").should == "foo:bar"
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should raise an error if prefix is nil but uri is not" do
|
134
|
+
lambda {
|
135
|
+
Namespace.compact_qname([], ["bar", nil, "http://foo.com/foo"])
|
136
|
+
}.should raise_error(/invalid name/)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should raise an error if a prefix is not bound" do
|
140
|
+
lambda {
|
141
|
+
Namespace.compact_qname([],
|
142
|
+
["bar", "foo", "http://foo.com/foo"])
|
143
|
+
}.should raise_error(/not bound/)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should raise an error if a prefix binding clashes" do
|
147
|
+
lambda {
|
148
|
+
Namespace.compact_qname([{"foo"=>"http://foo.com/foo"}],
|
149
|
+
["bar", "foo", "http://bar.com/bar"])
|
150
|
+
}.should raise_error(/'foo' is bound/)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should raise an error if default namespace binding clashes" do
|
154
|
+
lambda {
|
155
|
+
Namespace.compact_qname([{""=>"http://foo.com/foo"}],
|
156
|
+
["bar", "", "http://bar.com/bar"])
|
157
|
+
}.should raise_error(/'' is bound/)
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "extract_declared_namespace_bindings" do
|
163
|
+
it "should extract a hash of declared namespace bindings from a Hash of attributes" do
|
164
|
+
Namespace.extract_declared_namespace_bindings({"xmlns"=>"http://default.com/default", "xmlns:foo"=>"http://foo.com/foo", "foo"=>"bar"}).should ==
|
165
|
+
{""=>"http://default.com/default", "foo"=>"http://foo.com/foo"}
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "extract_explicit_namespace_bindings" do
|
170
|
+
it "should extract a hash of explicit namespace bindings from expanded tags" do
|
171
|
+
Namespace.extract_explicit_namespace_bindings(["bar", "foo", "http://foo.com/foo"],
|
172
|
+
{["baz", "bar", "http://bar.com/bar"]=>"baz",
|
173
|
+
["boo", "", "http://default.com/default"]=>"boo"}).should ==
|
174
|
+
{"foo"=>"http://foo.com/foo", "bar"=>"http://bar.com/bar", ""=>"http://default.com/default"}
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should raise an error if extracted namespaces clash" do
|
178
|
+
lambda{
|
179
|
+
Namespace.extract_explicit_namespace_bindings(["bar", "foo", "http://foo.com/foo"],
|
180
|
+
{["baz", "foo", "http://bar.com/bar"]=>"baz",
|
181
|
+
["boo", "", "http://default.com/default"]=>"boo"})
|
182
|
+
}.should raise_error(/bindings clash/)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "undeclared_namespace_bindings" do
|
187
|
+
it "should determine which explicit namespaces are not declared in context" do
|
188
|
+
Namespace.undeclared_namespace_bindings([{""=>"http://default.com/default", "foo"=>"http://foo.com/foo"}], {""=>"http://default.com/default", "foo"=>"http://foo.com/foo", "bar"=>"http://bar.com/bar"}).should ==
|
189
|
+
{"bar"=>"http://bar.com/bar"}
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should raise an exception if an explicit prefix clashes with a declard prefix" do
|
193
|
+
lambda {
|
194
|
+
Namespace.undeclared_namespace_bindings([{""=>"http://default.com/default", "foo"=>"http://foo.com/foo"}], {""=>"http://foo.com/foo", "foo"=>"http://foo.com/foo", "bar"=>"http://bar.com/bar"})
|
195
|
+
}.should raise_error(/is bound to uri/)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "merge_namespace_bindings" do
|
200
|
+
it "should merge two sets of namespace bindings" do
|
201
|
+
Namespace.merge_namespace_bindings({""=>"http://default.com/default",
|
202
|
+
"boo"=>"http://boo.com/boo"},
|
203
|
+
{"foo"=>"http://foo.com/foo",
|
204
|
+
"bar"=>"http://bar.com/bar"}).should ==
|
205
|
+
{""=>"http://default.com/default",
|
206
|
+
"boo"=>"http://boo.com/boo",
|
207
|
+
"foo"=>"http://foo.com/foo",
|
208
|
+
"bar"=>"http://bar.com/bar"}
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should raise an error if there are binding clashes" do
|
212
|
+
lambda {
|
213
|
+
Namespace.merge_namespace_bindings({""=>"http://default.com/default",
|
214
|
+
"boo"=>"http://boo.com/boo"},
|
215
|
+
{""=>"http://foo.com/foo",
|
216
|
+
"bar"=>"http://bar.com/bar"})
|
217
|
+
}.should raise_error(/bindings clash/)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "exploded_namespace_declarations" do
|
222
|
+
it "should produce unqalified namespaces declarations" do
|
223
|
+
Namespace.exploded_namespace_declarations({""=>"http://default.com/default", "foo"=>"http://foo.com/foo"}).should ==
|
224
|
+
{"xmlns"=>"http://default.com/default", ["foo", "xmlns"]=>"http://foo.com/foo"}
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "namespace_bindings_declarations" do
|
229
|
+
it "should extract declared and explicit bindings and additional declarations" do
|
230
|
+
Namespace.namespace_bindings_declarations([{"foo"=>"http://foo.com/foo"}],
|
231
|
+
[:bar, "foo", "http://foo.com/foo"],
|
232
|
+
{ [:b, "bar", "http://bar.com/bar"]=>"barbar",
|
233
|
+
[:c, "baz", "http://baz.com/baz"]=>"bazbaz",
|
234
|
+
[:d, "foo"]=>"booboo"}).should ==
|
235
|
+
[{ "baz"=>"http://baz.com/baz",
|
236
|
+
"bar"=>"http://bar.com/bar"},
|
237
|
+
{ ["baz", "xmlns"]=>"http://baz.com/baz",
|
238
|
+
["bar", "xmlns"]=>"http://bar.com/bar"}]
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should extract explicit default namespace bindings" do
|
242
|
+
Namespace.namespace_bindings_declarations([{"foo"=>"http://foo.com/foo"}],
|
243
|
+
[:bar, "", "http://default.com/default"],
|
244
|
+
{ [:d, "foo"]=>"booboo"}).should ==
|
245
|
+
[{ ""=>"http://default.com/default"},
|
246
|
+
{ "xmlns"=>"http://default.com/default"}]
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|