rsxml 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +16 -4
- data/VERSION +1 -1
- data/lib/rsxml/namespace.rb +56 -35
- data/lib/rsxml/sexp.rb +18 -27
- data/lib/rsxml/visitor.rb +18 -45
- data/lib/rsxml/xml.rb +21 -31
- data/spec/rsxml/mock_visitor.rb +43 -0
- data/spec/rsxml/namespace_spec.rb +51 -24
- data/spec/rsxml/sexp_spec.rb +12 -3
- data/spec/rsxml/visitor_spec.rb +133 -13
- data/spec/rsxml/xml_spec.rb +28 -5
- data/spec/rsxml_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- metadata +7 -5
data/README.rdoc
CHANGED
@@ -6,7 +6,7 @@ Why would you want to do this ? Well, s-expressions can be == compared natively
|
|
6
6
|
and editors indent them nicely when embedded in code. These features make them very suitable for writing readable
|
7
7
|
XML generation code and readable tests for XML generating code
|
8
8
|
|
9
|
-
Rsxml uses Nokogiri[http://nokogiri.org/] for parsing XML, and Builder[http://builder.rubyforge.org/] to generate it. Rsxml is not intended to be a feature complete XML
|
9
|
+
Rsxml uses Nokogiri[http://nokogiri.org/] for parsing XML, and Builder[http://builder.rubyforge.org/] to generate it. Rsxml is not intended to be a feature complete XML processor : It does not attempt to process PIs, CDATA etc, but it does make it very easy to use and generate straightforward XML documents from Ruby
|
10
10
|
|
11
11
|
Rsxml represents XML documents as s-expressions thus :
|
12
12
|
|
@@ -25,9 +25,9 @@ It is easy to convert XML docuemnts to Rsxml representation and back again :
|
|
25
25
|
|
26
26
|
=== Namespaces
|
27
27
|
|
28
|
-
XML namespaces are dealt with straightforwardly. When an XML document is converted to Rsxml, namespaces are preserved, and you can specify namespaces in an Rsxml structure in two ways
|
28
|
+
XML namespaces are dealt with straightforwardly. When an XML document is converted to Rsxml, namespaces are preserved, and you can specify namespaces in an Rsxml structure in two ways, which can be freely mixed
|
29
29
|
* using QName prefixes and declarative attributes, exactly as with XML
|
30
|
-
* using exploded QNames consisting of <tt>[
|
30
|
+
* using exploded QNames consisting of <tt>[local_part, prefix, uri]</tt> triples and <tt>[local_part, prefix]</tt> pairs
|
31
31
|
|
32
32
|
=== Converting to Rsxml
|
33
33
|
|
@@ -44,7 +44,7 @@ prefixed QNames, just as in XML
|
|
44
44
|
==== <tt>:exploded</tt> style
|
45
45
|
|
46
46
|
In <tt>:exploded</tt> style namespaces are not declared using attributes, and QNames are specified
|
47
|
-
using <tt>[
|
47
|
+
using <tt>[local_part, prefix, uri]</tt> triples
|
48
48
|
|
49
49
|
Rsxml.to_rsxml('<foo:foofoo xmlns:foo="http://foo.com/foo" foo:bar="barbar"/>', :style=>:exploded)
|
50
50
|
=> [["foofoo", "foo", "http://foo.com/foo"], {["bar", "foo", "http://foo.com/foo"]=>"barbar"}]
|
@@ -69,6 +69,18 @@ Fragments can be generated similarly :
|
|
69
69
|
Rsxml.to_xml(["foo:foofoo", {"foo:bar"=>"barbar"}], :ns=>{"foo"=>"http://foo.com/foo"})
|
70
70
|
=> '<foo:foofoo foo:bar="barbar"></foo:foofoo>'
|
71
71
|
|
72
|
+
== Visitors
|
73
|
+
|
74
|
+
<tt>Rsxml.to_rsxml</tt> and <tt>Rsxml.to_xml</tt> are implemented with a simple Visitor pattern over the XML document structure. <tt>Rsxml::Sexp.traverse()</tt> traverses a Rsxml s-expression representation of an XML document and <tt>Rsxml::Xml.traverse()</tt> traverses a Nokogiri Node tree. The Visitor receives a
|
75
|
+
|
76
|
+
text(context, text)
|
77
|
+
|
78
|
+
invocation for each text node, and an
|
79
|
+
|
80
|
+
element(context, name, attrs, ns_decls)
|
81
|
+
|
82
|
+
method invocation for each element. If namespaces are used, element and attribute names in the <tt>element</tt> method invocations are exploded <tt>[local_part, prefix, uri]</tt> triples. The attributes are presented as a <tt>{name=>value}</tt> +Hash+ which contains no namespace-related attributes. Any namespace declarations for the element are provided as the <tt>{prefix=>uri}</tt> +ns_decls+ +Hash+. Namespace prefixes, URIs and declaration attributes are cleanly separated in this API, so it is easy for Visitor implementations to correctly process XML documents with namespaces
|
83
|
+
|
72
84
|
== Install
|
73
85
|
|
74
86
|
gem install rsxml
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/rsxml/namespace.rb
CHANGED
@@ -13,9 +13,9 @@ module Rsxml
|
|
13
13
|
def explode_attr_qnames(ns_stack, attrs)
|
14
14
|
Hash[attrs.map do |name, value|
|
15
15
|
uq_name = explode_qname(ns_stack, name, true)
|
16
|
-
|
16
|
+
local_part, prefix, uri = uq_name
|
17
17
|
if !prefix || prefix==""
|
18
|
-
[
|
18
|
+
[local_part, value]
|
19
19
|
else
|
20
20
|
[uq_name, value]
|
21
21
|
end
|
@@ -39,15 +39,22 @@ module Rsxml
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
# split a QName into [LocalPart, prefix, URI] triple
|
42
|
+
# split a QName into [LocalPart, prefix, URI] triple. fill out
|
43
|
+
# missing uris if necessary, and check QName is well specified
|
43
44
|
def explode_qname(ns_stack, qname, attr=false)
|
44
45
|
if qname.is_a?(Array)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
local_part, prefix, uri = qname
|
47
|
+
if uri
|
48
|
+
raise "invalid name: #{qname.inspect}" if !prefix
|
49
|
+
bound_uri = find_namespace_uri(ns_stack, prefix)
|
50
|
+
raise "namespace conflict: prefix '#{prefix}' refers to '#{uri}' and '#{bound_uri}'" if bound_uri && uri != bound_uri
|
51
|
+
return [local_part, prefix, uri]
|
52
|
+
elsif prefix
|
53
|
+
uri = find_namespace_uri(ns_stack, prefix)
|
54
|
+
raise "namespace prefix not bound: '#{prefix}'" if !uri
|
55
|
+
return [local_part, prefix, uri]
|
49
56
|
else
|
50
|
-
return
|
57
|
+
return local_part
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
@@ -93,24 +100,28 @@ module Rsxml
|
|
93
100
|
uri
|
94
101
|
end
|
95
102
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
103
|
+
# split attributes into non-namespace related attrs and {prefix=>uri} namespace bindings
|
104
|
+
def partition_namespace_decls(attrs)
|
105
|
+
nonns_attrs = []
|
106
|
+
ns_bindings = []
|
107
|
+
attrs.each do |name, value|
|
108
|
+
local_part, prefix = split_qname(name)
|
109
|
+
if prefix && prefix=="xmlns"
|
110
|
+
ns_bindings << [local_part, value]
|
111
|
+
elsif !prefix && local_part=="xmlns"
|
112
|
+
ns_bindings << ["", value]
|
113
|
+
else
|
114
|
+
nonns_attrs << [name, value]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
[Hash[nonns_attrs], Hash[ns_bindings]]
|
107
118
|
end
|
108
119
|
|
109
|
-
# extract a Hash of {prefix=>uri} mappings from exploded QName
|
110
|
-
def extract_explicit_namespace_bindings(
|
111
|
-
|
120
|
+
# extract a Hash of {prefix=>uri} mappings from exploded QName element and attrs
|
121
|
+
def extract_explicit_namespace_bindings(element_name, attrs)
|
122
|
+
element_name_local_part, element_name_prefix, element_name_uri = element_name
|
112
123
|
ns = {}
|
113
|
-
ns[
|
124
|
+
ns[element_name_prefix] = element_name_uri if element_name_prefix && element_name_uri
|
114
125
|
|
115
126
|
attrs.each do |name, value|
|
116
127
|
attr_local_part, attr_prefix, attr_uri = name
|
@@ -125,7 +136,7 @@ module Rsxml
|
|
125
136
|
# figure out which explicit namespaces need declaring
|
126
137
|
#
|
127
138
|
# +ns_stack+ is the stack of namespace bindings
|
128
|
-
# +ns_explicit+ is the explicit refs for a
|
139
|
+
# +ns_explicit+ is the explicit refs for a element
|
129
140
|
def undeclared_namespace_bindings(ns_stack, ns_explicit)
|
130
141
|
Hash[ns_explicit.map do |prefix,uri|
|
131
142
|
[prefix, uri] if !find_namespace_uri(ns_stack, prefix, uri)
|
@@ -145,6 +156,18 @@ module Rsxml
|
|
145
156
|
end]
|
146
157
|
end
|
147
158
|
|
159
|
+
# produces a Hash of compact namespace attributes from a
|
160
|
+
# Hash of namespace bindings
|
161
|
+
def namespace_attributes(ns)
|
162
|
+
Hash[ns.map do |prefix, uri|
|
163
|
+
if prefix==""
|
164
|
+
["xmlns", uri]
|
165
|
+
else
|
166
|
+
[["xmlns", prefix].join(":"), uri]
|
167
|
+
end
|
168
|
+
end]
|
169
|
+
end
|
170
|
+
|
148
171
|
# merges two sets of namespace bindings, raising error on clash
|
149
172
|
def merge_namespace_bindings(ns1, ns2)
|
150
173
|
m = ns1.clone
|
@@ -155,20 +178,18 @@ module Rsxml
|
|
155
178
|
m
|
156
179
|
end
|
157
180
|
|
158
|
-
# given the existing +ns_stack+ of ns bindings, a +
|
159
|
-
# return a pair <tt>[
|
160
|
-
# ns
|
161
|
-
#
|
162
|
-
def
|
163
|
-
ns_declared =
|
164
|
-
|
181
|
+
# given the existing +ns_stack+ of ns bindings, a +element_name+ and it's +attributes+,
|
182
|
+
# return a pair <tt>[non_ns_attrs, ns_bindings]</tt> containing
|
183
|
+
# non-ns related attributes, and namespace bindings for the current element,
|
184
|
+
# both those declared in attributes and declared implicitly through exploded element names
|
185
|
+
def non_ns_attrs_ns_bindings(ns_stack, element_name, attrs)
|
186
|
+
non_ns_attrs, ns_declared = partition_namespace_decls(attrs)
|
187
|
+
|
188
|
+
ns_explicit = extract_explicit_namespace_bindings(element_name, attrs)
|
165
189
|
ns_undeclared = undeclared_namespace_bindings(ns_stack + [ns_declared], ns_explicit)
|
166
190
|
ns_bindings = merge_namespace_bindings(ns_declared, ns_undeclared)
|
167
191
|
|
168
|
-
|
169
|
-
ns_additional_decls = exploded_namespace_declarations(ns_undeclared)
|
170
|
-
|
171
|
-
[ns_bindings, ns_additional_decls]
|
192
|
+
[non_ns_attrs, ns_bindings]
|
172
193
|
end
|
173
194
|
|
174
195
|
end
|
data/lib/rsxml/sexp.rb
CHANGED
@@ -6,34 +6,25 @@ module Rsxml
|
|
6
6
|
# pre-order traversal of the sexp, calling methods on
|
7
7
|
# the visitor with each node
|
8
8
|
def traverse(sexp, visitor, context=Visitor::Context.new)
|
9
|
-
|
9
|
+
element_name, attrs, children = decompose_sexp(sexp)
|
10
10
|
|
11
|
-
|
11
|
+
non_ns_attrs, ns_bindings = Namespace::non_ns_attrs_ns_bindings(context.ns_stack, element_name, attrs)
|
12
12
|
|
13
13
|
context.ns_stack.push(ns_bindings)
|
14
14
|
|
15
|
-
|
16
|
-
eattrs = Namespace::explode_attr_qnames(context.ns_stack,
|
17
|
-
|
18
|
-
eattrs = eattrs.merge(ns_additional_decls)
|
15
|
+
eelement_name = Namespace::explode_qname(context.ns_stack, element_name)
|
16
|
+
eattrs = Namespace::explode_attr_qnames(context.ns_stack, non_ns_attrs)
|
19
17
|
|
20
18
|
begin
|
21
|
-
visitor.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
else
|
28
|
-
visitor.text(context, child)
|
29
|
-
context.processed_node(child)
|
30
|
-
end
|
19
|
+
visitor.element(context, eelement_name, eattrs, ns_bindings) do
|
20
|
+
children.each_with_index do |child, i|
|
21
|
+
if child.is_a?(Array)
|
22
|
+
traverse(child, visitor, context)
|
23
|
+
else
|
24
|
+
visitor.text(context, child)
|
31
25
|
end
|
32
|
-
ensure
|
33
|
-
context.pop_node
|
34
26
|
end
|
35
27
|
end
|
36
|
-
|
37
28
|
ensure
|
38
29
|
context.ns_stack.pop
|
39
30
|
end
|
@@ -41,13 +32,13 @@ module Rsxml
|
|
41
32
|
visitor
|
42
33
|
end
|
43
34
|
|
44
|
-
# decompose a sexp to a [
|
35
|
+
# decompose a sexp to a [element_name, attrs, children] list
|
45
36
|
def decompose_sexp(sexp)
|
46
37
|
raise "invalid rsxml: #{rsxml.inspect}" if sexp.length<1
|
47
38
|
if sexp[0].is_a?(Array)
|
48
|
-
|
39
|
+
element_name = sexp[0]
|
49
40
|
else
|
50
|
-
|
41
|
+
element_name = sexp[0].to_s
|
51
42
|
end
|
52
43
|
if sexp[1].is_a?(Hash)
|
53
44
|
attrs = sexp[1]
|
@@ -56,7 +47,7 @@ module Rsxml
|
|
56
47
|
attrs = {}
|
57
48
|
children = sexp[1..-1]
|
58
49
|
end
|
59
|
-
[
|
50
|
+
[element_name, attrs, children]
|
60
51
|
end
|
61
52
|
|
62
53
|
class ComparisonError < RuntimeError
|
@@ -68,14 +59,14 @@ module Rsxml
|
|
68
59
|
end
|
69
60
|
|
70
61
|
def compare(sexpa, sexpb, path=nil)
|
71
|
-
|
72
|
-
|
62
|
+
element_name_a, attrsa, childrena = decompose_sexp(sexpa)
|
63
|
+
element_name_b, attrsb, childrenb = decompose_sexp(sexpb)
|
73
64
|
|
74
|
-
raise ComparisonError.new("element names differ: '#{
|
65
|
+
raise ComparisonError.new("element names differ: '#{element_name_a}', '#{element_name_b}'", path) if element_name_a != element_name_b
|
75
66
|
raise ComparisonError.new("attributes differ", path) if attrsa != attrsb
|
76
67
|
raise ComparisonError.new("child count differs", path) if childrena.length != childrenb.length
|
77
68
|
|
78
|
-
path = [path,
|
69
|
+
path = [path, element_name_a].compact.join("/")
|
79
70
|
(0...childrena.length).each do |i|
|
80
71
|
if childrena[i].is_a?(Array) && childrenb[i].is_a?(Array)
|
81
72
|
compare(childrena[i], childrenb[i], path)
|
data/lib/rsxml/visitor.rb
CHANGED
@@ -6,30 +6,9 @@ module Rsxml
|
|
6
6
|
|
7
7
|
class Context
|
8
8
|
attr_reader :ns_stack
|
9
|
-
attr_reader :node_stack
|
10
|
-
attr_reader :prev_siblings
|
11
9
|
def initialize(initial_ns_bindings = nil)
|
12
10
|
@ns_stack=[]
|
13
11
|
@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
12
|
end
|
34
13
|
end
|
35
14
|
|
@@ -40,11 +19,13 @@ module Rsxml
|
|
40
19
|
@xml = xml_builder || Builder::XmlMarkup.new
|
41
20
|
end
|
42
21
|
|
43
|
-
def
|
22
|
+
def element(context, name, attrs, ns_decls)
|
44
23
|
qname = Namespace::compact_qname(context.ns_stack, name)
|
45
24
|
qattrs = Namespace::compact_attr_qnames(context.ns_stack, attrs)
|
25
|
+
ns_attrs = Namespace::namespace_attributes(ns_decls)
|
26
|
+
attrs = qattrs.merge(ns_attrs)
|
46
27
|
|
47
|
-
xml.__send__(qname,
|
28
|
+
xml.__send__(qname, attrs) do
|
48
29
|
yield
|
49
30
|
end
|
50
31
|
end
|
@@ -62,50 +43,42 @@ module Rsxml
|
|
62
43
|
attr_reader :sexp
|
63
44
|
attr_reader :cursor_stack
|
64
45
|
attr_reader :opts
|
46
|
+
attr_reader :element_transformer
|
65
47
|
|
66
48
|
# The <tt>:style</tt> option specifies how the Rsxml is to be produced
|
67
|
-
# :xml style is with compact <tt>"prefix:
|
68
|
-
# :exploded style is with <tt>[
|
49
|
+
# :xml style is with compact <tt>"prefix:local_part"</tt> Strings for QNames, and namespace declaration attributes
|
50
|
+
# :exploded style is with <tt>[local_part, prefix, uri]</tt> triples for QNames, and no namespace declaration attributes
|
69
51
|
OPTS = {:style=>[:xml, :exploded]}
|
70
52
|
|
71
|
-
def initialize(opts=nil)
|
72
|
-
@opts = opts
|
73
|
-
opts = Util.check_opts(OPTS, opts)
|
53
|
+
def initialize(opts=nil, &element_transformer)
|
54
|
+
@opts = Util.check_opts(OPTS, opts)
|
74
55
|
@cursor_stack = []
|
75
|
-
@
|
56
|
+
@element_transformer = element_transformer
|
76
57
|
end
|
77
58
|
|
78
59
|
def compact_qname(qname)
|
79
|
-
|
60
|
+
local_part, prefix, uri = qname
|
80
61
|
|
81
|
-
[prefix,
|
62
|
+
[prefix, local_part].map{|s| (!s || s.empty?) ? nil : s}.compact.join(":")
|
82
63
|
end
|
83
64
|
|
84
65
|
def compact_attr_names(attrs)
|
85
66
|
Hash[attrs.map{|qname,value| [compact_qname(qname), value]}]
|
86
67
|
end
|
87
68
|
|
88
|
-
|
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
|
69
|
+
def element(context, element_name, attrs, ns_decls)
|
97
70
|
|
98
|
-
|
71
|
+
element_name, attrs = element_transformer.call(context, element_name, attrs) if element_transformer
|
99
72
|
|
100
73
|
opts[:style] ||= :exploded
|
101
74
|
if opts[:style] == :xml
|
102
|
-
|
75
|
+
element_name = compact_qname(element_name)
|
103
76
|
attrs = compact_attr_names(attrs)
|
104
|
-
|
105
|
-
attrs =
|
77
|
+
ns_attrs = Namespace.namespace_attributes(ns_decls)
|
78
|
+
attrs = attrs.merge(ns_attrs)
|
106
79
|
end
|
107
80
|
|
108
|
-
el = [
|
81
|
+
el = [element_name, (attrs if attrs.size>0)].compact
|
109
82
|
|
110
83
|
if !cursor_stack.last
|
111
84
|
@sexp = el
|
data/lib/rsxml/xml.rb
CHANGED
@@ -36,18 +36,8 @@ module Rsxml
|
|
36
36
|
node = node_uri ? [node_name, node_prefix, node_uri] : node_name
|
37
37
|
end
|
38
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
39
|
# given a <tt>Nokogiri::XML::Element</tt> in +element+ , produce
|
50
|
-
# a <tt>[[
|
40
|
+
# a <tt>[[local_part, prefix, namespace], {[local_part, prefix, namespace]=>value}</tt>
|
51
41
|
# pair of exploded element name and attributes with exploded names
|
52
42
|
def explode_element(element)
|
53
43
|
eelement = explode_node(element)
|
@@ -56,36 +46,36 @@ module Rsxml
|
|
56
46
|
[explode_node(attr), attr.value]
|
57
47
|
end]
|
58
48
|
|
59
|
-
ns_decl_attrs = explode_ns_definitions(element)
|
60
|
-
eattrs = eattrs.merge(ns_decl_attrs)
|
61
|
-
|
62
49
|
[eelement, eattrs]
|
63
50
|
end
|
64
51
|
|
52
|
+
# give a list of <tt>Nokogiri::XML::Namespace</tt> definitions, produce
|
53
|
+
# a Hash <tt>{prefix=>uri}</tt> of namespace bindings
|
54
|
+
def namespace_bindings_from_defs(ns_defs)
|
55
|
+
(ns_defs||[]).reduce({}) do |h,ns_def|
|
56
|
+
h[ns_def.prefix||""] = ns_def.href
|
57
|
+
h
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
65
61
|
# pre-order traversal of the Nokogiri Nodes, calling methods on
|
66
62
|
# the visitor with each Node
|
67
63
|
def traverse(element, visitor, context = Visitor::Context.new)
|
68
|
-
|
69
|
-
|
70
|
-
ns_bindings = Rsxml::Namespace.extract_declared_namespace_bindings(element.namespaces)
|
64
|
+
ns_bindings = namespace_bindings_from_defs(element.namespace_definitions)
|
71
65
|
context.ns_stack.push(ns_bindings)
|
72
66
|
|
67
|
+
eelement, eattrs = explode_element(element)
|
68
|
+
|
73
69
|
begin
|
74
|
-
visitor.
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
context.processed_node(child.content)
|
83
|
-
else
|
84
|
-
Rsxml.log{|logger| logger.warn("unknown Nokogiri Node type: #{child.inspect}")}
|
85
|
-
end
|
70
|
+
visitor.element(context, eelement, eattrs, ns_bindings) do
|
71
|
+
element.children.each do |child|
|
72
|
+
if child.element?
|
73
|
+
traverse(child, visitor, context)
|
74
|
+
elsif child.text?
|
75
|
+
visitor.text(context, child.content)
|
76
|
+
else
|
77
|
+
Rsxml.log{|logger| logger.warn("unknown Nokogiri Node type: #{child.inspect}")}
|
86
78
|
end
|
87
|
-
ensure
|
88
|
-
context.pop_node
|
89
79
|
end
|
90
80
|
end
|
91
81
|
ensure
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Rsxml
|
2
|
+
module Visitor
|
3
|
+
# a mock visitor which can be used to check expectations
|
4
|
+
class MockVisitor
|
5
|
+
attr_reader :expectations
|
6
|
+
|
7
|
+
def initialize(expectations)
|
8
|
+
@expectations = expectations.clone
|
9
|
+
end
|
10
|
+
|
11
|
+
def __format_invocation__(method, args)
|
12
|
+
"#{method}(#{(args||[]).map(&:inspect).join(', ')})"
|
13
|
+
end
|
14
|
+
|
15
|
+
def __check_arg_expectation__(arg_xp, arg)
|
16
|
+
return true if arg_xp == :_
|
17
|
+
return arg_xp.call(arg) if arg_xp.is_a?(Proc)
|
18
|
+
return arg_xp == arg
|
19
|
+
end
|
20
|
+
|
21
|
+
def __check_expectation__(method, args)
|
22
|
+
xp_method, *xp_args = expectations.shift
|
23
|
+
msg = "unexpected invocation: #{__format_invocation__(method, args)}. expected: #{__format_invocation__(xp_method, xp_args)}"
|
24
|
+
raise msg if method!=xp_method || args.length != xp_args.length
|
25
|
+
(0...xp_args.length).each do |i|
|
26
|
+
raise msg if !__check_arg_expectation__(xp_args[i], args[i])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def __finalize__
|
31
|
+
raise "missing invocations: #{expectations.map{|xp_method, *xp_args| __format_invocation__(xp_method, xp_args)}.join('\n')}" if expectations && expectations.length>0
|
32
|
+
end
|
33
|
+
|
34
|
+
# check that there is an expectation for the invoked method, and if
|
35
|
+
# a block is given yield to that block
|
36
|
+
def method_missing(method, *args, &block)
|
37
|
+
__check_expectation__(method, args)
|
38
|
+
block.call if block
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -22,11 +22,26 @@ module Rsxml
|
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "explode_qname" do
|
25
|
-
it "should do nothing to an array with
|
25
|
+
it "should do nothing to an array with an exploded name" do
|
26
26
|
Namespace.explode_qname([], ["bar", "foo", "http://foo.com/foo"]).should ==
|
27
27
|
["bar", "foo", "http://foo.com/foo"]
|
28
|
-
|
29
|
-
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should fill in the uri if a bound prefix with no uri is given" do
|
31
|
+
Namespace.explode_qname([{"foo"=>"http://foo.com/foo"}], ["bar", "foo"]).should ==
|
32
|
+
["bar", "foo", "http://foo.com/foo"]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should raise an exception if an unbound prefix and no uri is given" do
|
36
|
+
lambda{
|
37
|
+
Namespace.explode_qname([], ["bar", "foo"])
|
38
|
+
}.should raise_error(/not bound/)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should raise an execption if a prefix and uri are given which conflict with ns bindings" do
|
42
|
+
lambda{
|
43
|
+
Namespace.explode_qname([{"foo"=>"http://foo.com/foo"}], ["bar", "foo", "http://bar.com/bar"])
|
44
|
+
}.should raise_error
|
30
45
|
end
|
31
46
|
|
32
47
|
it "should return the first element of an array with only the first non-nil element" do
|
@@ -159,15 +174,15 @@ module Rsxml
|
|
159
174
|
|
160
175
|
end
|
161
176
|
|
162
|
-
describe "
|
163
|
-
it "should
|
164
|
-
Namespace.
|
165
|
-
{""=>"http://default.com/default", "foo"=>"http://foo.com/foo"}
|
177
|
+
describe "partition_namespace_decls" do
|
178
|
+
it "should partition attributes into non-namespace attributes and a hash of namespace bindings" do
|
179
|
+
Namespace.partition_namespace_decls({"xmlns"=>"http://default.com/default", "xmlns:foo"=>"http://foo.com/foo", "foo"=>"bar"}).should ==
|
180
|
+
[{"foo"=>"bar"},{""=>"http://default.com/default", "foo"=>"http://foo.com/foo"}]
|
166
181
|
end
|
167
182
|
end
|
168
183
|
|
169
184
|
describe "extract_explicit_namespace_bindings" do
|
170
|
-
it "should extract a hash of explicit namespace bindings from expanded
|
185
|
+
it "should extract a hash of explicit namespace bindings from expanded QNames" do
|
171
186
|
Namespace.extract_explicit_namespace_bindings(["bar", "foo", "http://foo.com/foo"],
|
172
187
|
{["baz", "bar", "http://bar.com/bar"]=>"baz",
|
173
188
|
["boo", "", "http://default.com/default"]=>"boo"}).should ==
|
@@ -225,26 +240,38 @@ module Rsxml
|
|
225
240
|
end
|
226
241
|
end
|
227
242
|
|
228
|
-
describe "
|
229
|
-
it "should
|
230
|
-
Namespace.
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
243
|
+
describe "namespace_attributes" do
|
244
|
+
it "should produce a Hash of namespace declaration attributes" do
|
245
|
+
Namespace.namespace_attributes({""=>"http://default.com/default", "foo"=>"http://foo.com/foo"}).should ==
|
246
|
+
{"xmlns"=>"http://default.com/default", "xmlns:foo"=>"http://foo.com/foo"}
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe "non_ns_attrs_ns_bindings" do
|
251
|
+
it "should extract non-ns attributes and explicit namespace bindings" do
|
252
|
+
Namespace.non_ns_attrs_ns_bindings([{"foo"=>"http://foo.com/foo"}],
|
253
|
+
[:bar, "foo", "http://foo.com/foo"],
|
254
|
+
{ "xmlns:boo"=>"http://boo.com/boo",
|
255
|
+
[:b, "bar", "http://bar.com/bar"]=>"barbar",
|
256
|
+
[:c, "baz", "http://baz.com/baz"]=>"bazbaz",
|
257
|
+
[:d, "foo"]=>"booboo"}).should ==
|
258
|
+
[{[:b, "bar", "http://bar.com/bar"]=>"barbar",
|
259
|
+
[:c, "baz", "http://baz.com/baz"]=>"bazbaz",
|
260
|
+
[:d, "foo"]=>"booboo"},
|
261
|
+
{ "baz"=>"http://baz.com/baz",
|
262
|
+
"bar"=>"http://bar.com/bar",
|
263
|
+
"boo"=>"http://boo.com/boo"}]
|
239
264
|
end
|
240
265
|
|
241
266
|
it "should extract explicit default namespace bindings" do
|
242
|
-
Namespace.
|
243
|
-
|
244
|
-
|
245
|
-
[{ ""=>"
|
246
|
-
{ "
|
267
|
+
Namespace.non_ns_attrs_ns_bindings([{"foo"=>"http://foo.com/foo"}],
|
268
|
+
[:bar, "", "http://default.com/default"],
|
269
|
+
{ [:d, "foo"]=>"booboo"}).should ==
|
270
|
+
[{ [:d, "foo"]=>"booboo"},
|
271
|
+
{ ""=>"http://default.com/default"}]
|
247
272
|
end
|
273
|
+
|
274
|
+
|
248
275
|
end
|
249
276
|
|
250
277
|
end
|
data/spec/rsxml/sexp_spec.rb
CHANGED
@@ -1,13 +1,22 @@
|
|
1
1
|
require File.expand_path("../../spec_helper", __FILE__)
|
2
2
|
|
3
3
|
module Rsxml
|
4
|
-
|
5
|
-
|
6
4
|
describe "traverse" do
|
7
|
-
|
5
|
+
# tests moved to visitor_spec... done in parallel with Xml traverse tests
|
8
6
|
end
|
9
7
|
|
10
8
|
describe "decompose_sexp" do
|
9
|
+
it "should decompose a [element_name] sexp" do
|
10
|
+
Sexp.decompose_sexp(["foo"]).should == ["foo", {}, []]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should decompose a [element_name, attrs] sexp" do
|
14
|
+
Sexp.decompose_sexp(["foo", {"foofoo"=>"a"}]).should == ["foo", {"foofoo"=>"a"}, []]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should decompose a [element_name, attrs, children] sexp" do
|
18
|
+
Sexp.decompose_sexp(["foo", {"foofoo"=>"a"}, ["bar"], ["baz"]]).should == ["foo", {"foofoo"=>"a"}, [["bar"], ["baz"]]]
|
19
|
+
end
|
11
20
|
end
|
12
21
|
|
13
22
|
describe "compare" do
|
data/spec/rsxml/visitor_spec.rb
CHANGED
@@ -1,6 +1,103 @@
|
|
1
1
|
require File.expand_path("../../spec_helper", __FILE__)
|
2
2
|
|
3
3
|
module Rsxml
|
4
|
+
# tests traverse methods on both Xml and Sexp together : they should produce identical visitation
|
5
|
+
# patterns
|
6
|
+
describe "traverse" do
|
7
|
+
def check_traverse(expectations, xml, sexp)
|
8
|
+
xml_visitor = Visitor::MockVisitor.new(expectations)
|
9
|
+
xml_root = Nokogiri::XML(xml).children.first
|
10
|
+
Xml.traverse(xml_root, xml_visitor)
|
11
|
+
xml_visitor.__finalize__
|
12
|
+
|
13
|
+
sexp_visitor = Visitor::MockVisitor.new(expectations)
|
14
|
+
Sexp.traverse(sexp, sexp_visitor)
|
15
|
+
sexp_visitor.__finalize__
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should call the element function on the visitor" do
|
19
|
+
check_traverse([[:element, :_, "foo", {"bar"=>"barbar"}, {}]],
|
20
|
+
'<foo bar="barbar"/>',
|
21
|
+
[:foo, {"bar"=>"barbar"}])
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should call the element function on the visitor with exploded element and attributes qnames" do
|
25
|
+
check_traverse([[:element, :_,
|
26
|
+
["foofoo", "foo", "http://foo.com/foo"],
|
27
|
+
{["bar", "foo", "http://foo.com/foo"]=>"barbar"},
|
28
|
+
{"foo"=>"http://foo.com/foo"}]],
|
29
|
+
'<foo:foofoo foo:bar="barbar" xmlns:foo="http://foo.com/foo"/>',
|
30
|
+
[["foofoo", "foo"], {["bar", "foo", "http://foo.com/foo"]=>"barbar"}])
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should call the test function on the visitor with textual content" do
|
34
|
+
check_traverse([[:element, :_,
|
35
|
+
["foofoo", "foo", "http://foo.com/foo"],
|
36
|
+
{["bar", "foo", "http://foo.com/foo"]=>"barbar"},
|
37
|
+
{"foo"=>"http://foo.com/foo"}],
|
38
|
+
[:text, :_, "boohoo"]],
|
39
|
+
'<foo:foofoo foo:bar="barbar" xmlns:foo="http://foo.com/foo">boohoo</foo:foofoo>',
|
40
|
+
[["foofoo", "foo"], {["bar", "foo", "http://foo.com/foo"]=>"barbar"}, "boohoo"])
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should call the element function in document order for each element in a hierarchic doc" do
|
44
|
+
check_traverse([[:element, :_,
|
45
|
+
["foofoo", "foo", "http://foo.com/foo"],
|
46
|
+
{["bar", "foo", "http://foo.com/foo"]=>"barbar"},
|
47
|
+
{"foo"=>"http://foo.com/foo"}],
|
48
|
+
[:element, :_,
|
49
|
+
["barbar", "foo", "http://foo.com/foo"],
|
50
|
+
{["baz", "foo", "http://foo.com/foo"]=>"bazbaz"},
|
51
|
+
{}]],
|
52
|
+
'<foo:foofoo foo:bar="barbar" xmlns:foo="http://foo.com/foo"><foo:barbar foo:baz="bazbaz"/></foo:foofoo>',
|
53
|
+
[["foofoo", "foo"], {["bar", "foo", "http://foo.com/foo"]=>"barbar"},
|
54
|
+
[["barbar", "foo"], {["baz", "foo"]=>"bazbaz"}]])
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should call the element/text functions in a mixed document in document order" do
|
58
|
+
check_traverse([[:element, :_,
|
59
|
+
["foofoo", "foo", "http://foo.com/foo"],
|
60
|
+
{["bar", "foo", "http://foo.com/foo"]=>"barbar"},
|
61
|
+
{"foo"=>"http://foo.com/foo"}],
|
62
|
+
[:element, :_,
|
63
|
+
["barbar", "foo", "http://foo.com/foo"],
|
64
|
+
{["baz", "foo", "http://foo.com/foo"]=>"bazbaz"},
|
65
|
+
{}],
|
66
|
+
[:text, :_, "sometext"],
|
67
|
+
[:element, :_, "boo", {"hoo"=>"hoohoo"}, {"zoo"=>"http://zoo.com/zoo"}],
|
68
|
+
[:element, :_, ["bozo", "zoo", "http://zoo.com/zoo"], {}, {}]
|
69
|
+
],
|
70
|
+
'<foo:foofoo foo:bar="barbar" xmlns:foo="http://foo.com/foo"><foo:barbar foo:baz="bazbaz"/>sometext<boo hoo="hoohoo" xmlns:zoo="http://zoo.com/zoo"><zoo:bozo/></boo></foo:foofoo>',
|
71
|
+
[["foofoo", "foo"], {["bar", "foo", "http://foo.com/foo"]=>"barbar"},
|
72
|
+
[["barbar", "foo"], {["baz", "foo"]=>"bazbaz"}],
|
73
|
+
"sometext",
|
74
|
+
["boo", {"hoo"=>"hoohoo", "xmlns:zoo"=>"http://zoo.com/zoo"},
|
75
|
+
["zoo:bozo"]]])
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should work the same with compact sexp representations" do
|
79
|
+
check_traverse([[:element, :_,
|
80
|
+
["foofoo", "foo", "http://foo.com/foo"],
|
81
|
+
{["bar", "foo", "http://foo.com/foo"]=>"barbar"},
|
82
|
+
{"foo"=>"http://foo.com/foo"}],
|
83
|
+
[:element, :_,
|
84
|
+
["barbar", "foo", "http://foo.com/foo"],
|
85
|
+
{["baz", "foo", "http://foo.com/foo"]=>"bazbaz"},
|
86
|
+
{}],
|
87
|
+
[:text, :_, "sometext"],
|
88
|
+
[:element, :_, "boo", {"hoo"=>"hoohoo"}, {"zoo"=>"http://zoo.com/zoo"}],
|
89
|
+
[:element, :_, ["bozo", "zoo", "http://zoo.com/zoo"], {}, {}]
|
90
|
+
],
|
91
|
+
'<foo:foofoo foo:bar="barbar" xmlns:foo="http://foo.com/foo"><foo:barbar foo:baz="bazbaz"/>sometext<boo hoo="hoohoo" xmlns:zoo="http://zoo.com/zoo"><zoo:bozo/></boo></foo:foofoo>',
|
92
|
+
["foo:foofoo", {"foo:bar"=>"barbar", "xmlns:foo"=>"http://foo.com/foo"},
|
93
|
+
["foo:barbar", {"foo:baz"=>"bazbaz"}],
|
94
|
+
"sometext",
|
95
|
+
["boo", {"hoo"=>"hoohoo", "xmlns:zoo"=>"http://zoo.com/zoo"},
|
96
|
+
["zoo:bozo"]]])
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
4
101
|
describe Visitor::WriteXmlVisitor do
|
5
102
|
it "should write single element xml" do
|
6
103
|
Sexp::traverse(["item"], Visitor::WriteXmlVisitor.new).to_s.should == "<item></item>"
|
@@ -29,17 +126,6 @@ module Rsxml
|
|
29
126
|
end
|
30
127
|
|
31
128
|
describe Visitor::BuildRsxmlVisitor do
|
32
|
-
describe "strip_namespace_decls" do
|
33
|
-
it "should remove default and prefixed namespace decls from exploded attributes" do
|
34
|
-
Visitor::BuildRsxmlVisitor.new.strip_namespace_decls({"xmlns"=>"http://default.com/default",
|
35
|
-
["foo", "xmlns"]=>"http://foo.com/foo",
|
36
|
-
["bar", "foo", "http://foo.com/foo"]=>"barbar",
|
37
|
-
"baz"=>"bazbaz"}).should ==
|
38
|
-
{["bar", "foo", "http://foo.com/foo"]=>"barbar",
|
39
|
-
"baz"=>"bazbaz"}
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
129
|
describe "compact_qname" do
|
44
130
|
it "should compact exploded qnames" do
|
45
131
|
Visitor::BuildRsxmlVisitor.new.compact_qname(["foo", "bar", "http://bar.com/bar"]).should ==
|
@@ -56,8 +142,8 @@ module Rsxml
|
|
56
142
|
end
|
57
143
|
end
|
58
144
|
|
59
|
-
describe "
|
60
|
-
it "should append the rsxml
|
145
|
+
describe "element" do
|
146
|
+
it "should append the rsxml element to the cursor element and yield" do
|
61
147
|
end
|
62
148
|
end
|
63
149
|
|
@@ -77,6 +163,40 @@ module Rsxml
|
|
77
163
|
rsxml = Rsxml::Xml.traverse(root, Visitor::BuildRsxmlVisitor.new).sexp
|
78
164
|
rsxml.should == ["foo", {"bar"=>"10", "baz"=>"20"}]
|
79
165
|
end
|
166
|
+
|
167
|
+
describe "element_transformer" do
|
168
|
+
def capitalize_local_part(qname)
|
169
|
+
local_part, prefix, uri = qname
|
170
|
+
if uri
|
171
|
+
[local_part.capitalize, prefix, uri]
|
172
|
+
else
|
173
|
+
local_part.capitalize
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should call a element_transformer block to transform element_names and attrs" do
|
178
|
+
root = Nokogiri::XML('<foo bar="10" baz="20"></foo>').children.first
|
179
|
+
rsxml = Rsxml::Xml.traverse(root, Visitor::BuildRsxmlVisitor.new do |context,element_name,attrs|
|
180
|
+
celement_name = capitalize_local_part(element_name)
|
181
|
+
cattrs = Hash[attrs.map{|n,v| [capitalize_local_part(n), v]}]
|
182
|
+
[celement_name, cattrs]
|
183
|
+
end ).sexp
|
184
|
+
|
185
|
+
rsxml.should ==
|
186
|
+
["Foo", {"Bar"=>"10", "Baz"=>"20"}]
|
187
|
+
|
188
|
+
root = Nokogiri::XML('<a:foo bar="10" baz="20" xmlns:a="http://a.com/a"></a:foo>').children.first
|
189
|
+
rsxml = Rsxml::Xml.traverse(root, Visitor::BuildRsxmlVisitor.new(:style=>:exploded) do |context,element_name,attrs|
|
190
|
+
celement_name = capitalize_local_part(element_name)
|
191
|
+
cattrs = Hash[attrs.map{|n,v| [capitalize_local_part(n), v]}]
|
192
|
+
[celement_name, cattrs]
|
193
|
+
end ).sexp
|
194
|
+
|
195
|
+
rsxml.should ==
|
196
|
+
[["Foo", "a", "http://a.com/a"], {"Bar"=>"10", "Baz"=>"20"}]
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
80
200
|
end
|
81
201
|
|
82
202
|
end
|
data/spec/rsxml/xml_spec.rb
CHANGED
@@ -7,6 +7,7 @@ module Rsxml
|
|
7
7
|
|
8
8
|
it "should wrap a fragment in a document with namespace declarations if there are ns prefixes" do
|
9
9
|
end
|
10
|
+
|
10
11
|
end
|
11
12
|
|
12
13
|
describe "unwrap_fragment" do
|
@@ -18,6 +19,14 @@ module Rsxml
|
|
18
19
|
|
19
20
|
it "should throw an exception if it unwraps and there is more than one child" do
|
20
21
|
end
|
22
|
+
|
23
|
+
it "should return a node with no namespace definitions" do
|
24
|
+
root = Xml.unwrap_fragment(Nokogiri::XML(Xml.wrap_fragment("<foo:bar/>", {"foo"=>"http://foo.com/foo"})).children.first)
|
25
|
+
root.namespace_definitions.should == []
|
26
|
+
root.name.should == "bar"
|
27
|
+
root.namespace.prefix.should == "foo"
|
28
|
+
root.namespace.href.should == "http://foo.com/foo"
|
29
|
+
end
|
21
30
|
end
|
22
31
|
|
23
32
|
describe "explode_node" do
|
@@ -28,7 +37,7 @@ module Rsxml
|
|
28
37
|
Xml.explode_node(node).should == "foo"
|
29
38
|
end
|
30
39
|
|
31
|
-
it "should return the [
|
40
|
+
it "should return the [local_part, prefix, uri] triple if there is a namespace" do
|
32
41
|
node = Object.new
|
33
42
|
stub(node).name{"foo"}
|
34
43
|
namespace = Object.new
|
@@ -38,7 +47,7 @@ module Rsxml
|
|
38
47
|
Xml.explode_node(node).should == ["foo", "bar", "http://bar.com/bar"]
|
39
48
|
end
|
40
49
|
|
41
|
-
it "should return a [
|
50
|
+
it "should return a [local_part, "", uri] triple if there is a default namespace" do
|
42
51
|
node = Object.new
|
43
52
|
stub(node).name{"foo"}
|
44
53
|
namespace = Object.new
|
@@ -56,13 +65,27 @@ module Rsxml
|
|
56
65
|
eelement, eattrs = Rsxml::Xml.explode_element(root)
|
57
66
|
eelement.should == ["bar", "foo", "http://foo.com/foo"]
|
58
67
|
eattrs.should == {"a"=>"aa",
|
59
|
-
["b", "foo", "http://foo.com/foo"]=>"bb"
|
60
|
-
|
61
|
-
|
68
|
+
["b", "foo", "http://foo.com/foo"]=>"bb"}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "namespace_bindings_from_defs" do
|
73
|
+
it "should produce a hash of {prefix=>uri} bindings from a list of Nokogiri::XML::Namespace" do
|
74
|
+
default_def = Object.new
|
75
|
+
mock(default_def).prefix{nil}
|
76
|
+
mock(default_def).href{"http://default.com/default"}
|
77
|
+
|
78
|
+
foo_def = Object.new
|
79
|
+
mock(foo_def).prefix{"foo"}
|
80
|
+
mock(foo_def).href{"http://foo.com/foo"}
|
81
|
+
|
82
|
+
Xml.namespace_bindings_from_defs([default_def, foo_def]).should ==
|
83
|
+
{"foo"=>"http://foo.com/foo", ""=>"http://default.com/default"}
|
62
84
|
end
|
63
85
|
end
|
64
86
|
|
65
87
|
describe "traverse" do
|
88
|
+
# tests moved to visitor_spec... done in parallel with Sexp traverse tests
|
66
89
|
end
|
67
90
|
|
68
91
|
end
|
data/spec/rsxml_spec.rb
CHANGED
@@ -183,7 +183,7 @@ describe Rsxml do
|
|
183
183
|
rsxml.should == org_no_ns
|
184
184
|
end
|
185
185
|
|
186
|
-
it "should return exploded namespaces if :
|
186
|
+
it "should return exploded namespaces if :style=>:exploded when parsing a fragment" do
|
187
187
|
xml = '<foofoo foo:bar="1" foo:baz="baz"></foofoo>'
|
188
188
|
rsxml = Rsxml.to_rsxml(xml, :ns=>{:foo=>"http://foo.com/foo", ""=>"http://baz.com/baz"}, :style=>:exploded)
|
189
189
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rsxml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Trampoline Systems Ltd
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-27 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -118,6 +118,7 @@ files:
|
|
118
118
|
- lib/rsxml/util.rb
|
119
119
|
- lib/rsxml/visitor.rb
|
120
120
|
- lib/rsxml/xml.rb
|
121
|
+
- spec/rsxml/mock_visitor.rb
|
121
122
|
- spec/rsxml/namespace_spec.rb
|
122
123
|
- spec/rsxml/sexp_spec.rb
|
123
124
|
- spec/rsxml/util_spec.rb
|
@@ -160,6 +161,7 @@ signing_key:
|
|
160
161
|
specification_version: 3
|
161
162
|
summary: an s-expression representation of XML documents in Ruby
|
162
163
|
test_files:
|
164
|
+
- spec/rsxml/mock_visitor.rb
|
163
165
|
- spec/rsxml/namespace_spec.rb
|
164
166
|
- spec/rsxml/sexp_spec.rb
|
165
167
|
- spec/rsxml/util_spec.rb
|