xmlable 0.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +245 -0
- data/lib/xmlable/attribute.rb +16 -0
- data/lib/xmlable/builder.rb +189 -0
- data/lib/xmlable/document.rb +16 -0
- data/lib/xmlable/element.rb +19 -0
- data/lib/xmlable/exports/base.rb +78 -0
- data/lib/xmlable/exports/json_exporter.rb +208 -0
- data/lib/xmlable/exports/xml_exporter.rb +179 -0
- data/lib/xmlable/exports.rb +11 -0
- data/lib/xmlable/handlers/attribute.rb +41 -0
- data/lib/xmlable/handlers/attribute_none.rb +10 -0
- data/lib/xmlable/handlers/base.rb +103 -0
- data/lib/xmlable/handlers/document.rb +33 -0
- data/lib/xmlable/handlers/element.rb +89 -0
- data/lib/xmlable/handlers/element_none.rb +10 -0
- data/lib/xmlable/handlers/elements.rb +15 -0
- data/lib/xmlable/handlers/mixins/described.rb +19 -0
- data/lib/xmlable/handlers/mixins/namespace.rb +40 -0
- data/lib/xmlable/handlers/mixins/tag.rb +24 -0
- data/lib/xmlable/handlers/namespace.rb +26 -0
- data/lib/xmlable/handlers/root.rb +9 -0
- data/lib/xmlable/handlers/root_none.rb +10 -0
- data/lib/xmlable/handlers/storage.rb +104 -0
- data/lib/xmlable/handlers.rb +23 -0
- data/lib/xmlable/mixins/attributes_storage.rb +195 -0
- data/lib/xmlable/mixins/bare_value.rb +41 -0
- data/lib/xmlable/mixins/castable.rb +93 -0
- data/lib/xmlable/mixins/container.rb +71 -0
- data/lib/xmlable/mixins/content_storage.rb +138 -0
- data/lib/xmlable/mixins/document_storage.rb +136 -0
- data/lib/xmlable/mixins/elements_storage.rb +219 -0
- data/lib/xmlable/mixins/export.rb +45 -0
- data/lib/xmlable/mixins/instantiable.rb +47 -0
- data/lib/xmlable/mixins/namespace_definitions_storage.rb +105 -0
- data/lib/xmlable/mixins/object.rb +95 -0
- data/lib/xmlable/mixins/options_storage.rb +39 -0
- data/lib/xmlable/mixins/root_storage.rb +162 -0
- data/lib/xmlable/mixins/standalone_attribute.rb +34 -0
- data/lib/xmlable/mixins/standalone_element.rb +47 -0
- data/lib/xmlable/mixins/value_storage.rb +84 -0
- data/lib/xmlable/mixins/wrapper.rb +37 -0
- data/lib/xmlable/mixins.rb +25 -0
- data/lib/xmlable/options/nokogiri_export.rb +19 -0
- data/lib/xmlable/options/storage.rb +97 -0
- data/lib/xmlable/options.rb +9 -0
- data/lib/xmlable/types.rb +31 -0
- data/lib/xmlable/version.rb +4 -0
- data/lib/xmlable.rb +49 -0
- metadata +149 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Exports
|
3
|
+
#
|
4
|
+
# JSONExporter class exports object into JSON format
|
5
|
+
#
|
6
|
+
class JSONExporter < Base
|
7
|
+
#
|
8
|
+
# Export into JSON format
|
9
|
+
#
|
10
|
+
# @return [Hash]
|
11
|
+
#
|
12
|
+
def export
|
13
|
+
opts = node_nested_options(@element.__node)
|
14
|
+
export_object(@element, opts)
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Is object empty?
|
19
|
+
#
|
20
|
+
# @param [XMLable::Mixins::Object] el
|
21
|
+
#
|
22
|
+
# @return [Boolean]
|
23
|
+
#
|
24
|
+
def empty?(el)
|
25
|
+
el.__empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Is object described by user?
|
30
|
+
#
|
31
|
+
# @param [XMLable::Handlers::Base, XMLable::Mixins::Object]
|
32
|
+
#
|
33
|
+
# @return [Boolean]
|
34
|
+
#
|
35
|
+
#
|
36
|
+
def described?(obj)
|
37
|
+
handler = obj.is_a?(XMLable::Handlers::Base) ? obj : obj.__handler
|
38
|
+
handler.described?
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Get object's key
|
43
|
+
#
|
44
|
+
# @param [XMLable::Handlers::Base, XMLable::Mixins::Object]
|
45
|
+
#
|
46
|
+
# @return [String]
|
47
|
+
#
|
48
|
+
def key(obj, opts)
|
49
|
+
handler = obj.is_a?(XMLable::Handlers::Base) ? obj : obj.__handler
|
50
|
+
handler.method_name
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Get object's handlers
|
55
|
+
#
|
56
|
+
# @param [XMLable::Mixins::Object] el
|
57
|
+
# @param [XMLable::Options::Storage] opts
|
58
|
+
#
|
59
|
+
# @return [Array<XMLable::Handler::Base>]
|
60
|
+
#
|
61
|
+
def object_handlers(el, opts)
|
62
|
+
handlers = []
|
63
|
+
if el.respond_to?(:__attributes_handlers)
|
64
|
+
el.__attributes_handlers.storage.each do |h|
|
65
|
+
next if opts.drop_undescribed_attributes? && !described?(h)
|
66
|
+
handlers << h
|
67
|
+
end
|
68
|
+
end
|
69
|
+
if el.respond_to?(:__elements_handlers)
|
70
|
+
el.__elements_handlers.storage.each do |h|
|
71
|
+
next if opts.drop_undescribed_elements? && !described?(h)
|
72
|
+
handlers << h
|
73
|
+
end
|
74
|
+
end
|
75
|
+
handlers
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Export group of elements
|
80
|
+
#
|
81
|
+
# @param [XMLable::Mixins::Container<XMLable::Mixins::Object>] els
|
82
|
+
# @param [XMLable::Options::Storage] opts
|
83
|
+
#
|
84
|
+
# @return [Array<Hash>]
|
85
|
+
#
|
86
|
+
def export_elements(els, opts)
|
87
|
+
els.each_with_object([]) do |e, arr|
|
88
|
+
next if opts.drop_empty_elements? && empty?(e)
|
89
|
+
arr << export_object(e, opts)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Export attribute object's value
|
95
|
+
#
|
96
|
+
# @param [XMLable::Mixins::Object] el
|
97
|
+
# @param [XMLable::Options::Storage] opts
|
98
|
+
#
|
99
|
+
# @return [Object]
|
100
|
+
#
|
101
|
+
def export_value(el, opts)
|
102
|
+
el.__export_to_json(el.__object)
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Export element object's content
|
107
|
+
#
|
108
|
+
# @param [XMLable::Mixins::Object] el
|
109
|
+
# @param [XMLable::Options::Storage] opts
|
110
|
+
#
|
111
|
+
# @return [Object]
|
112
|
+
#
|
113
|
+
def export_content(el, opts)
|
114
|
+
el.__export_to_json(el.__object)
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# Get object key
|
119
|
+
#
|
120
|
+
# @param [XMLable::Handlers::Base, XMLable::Mixins::Object]
|
121
|
+
#
|
122
|
+
def key(obj, opts)
|
123
|
+
handler = obj.is_a?(XMLable::Handlers::Base) ? obj : obj.__handler
|
124
|
+
handler.method_name
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
# Export element object
|
129
|
+
#
|
130
|
+
# @param [XMLable::Mixins::Object] el
|
131
|
+
# @param [XMLable::Options::Storage] opts
|
132
|
+
#
|
133
|
+
# @return [Object]
|
134
|
+
#
|
135
|
+
def export_element(el, opts)
|
136
|
+
opts = node_merged_opts(el.__node, opts)
|
137
|
+
handlers = object_handlers(el, opts)
|
138
|
+
content = export_content(el, opts)
|
139
|
+
return content if handlers.size == 0
|
140
|
+
|
141
|
+
ret = export_element_children(el, opts)
|
142
|
+
|
143
|
+
if !content.to_s.empty? || !opts.drop_empty_elements?
|
144
|
+
content_method = el.__content_method
|
145
|
+
if (content_method || !opts.drop_undescribed_elements?) && content_method != false
|
146
|
+
ret["#{content_method || '__content'}"] = content unless content.to_s.empty?
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
ret
|
151
|
+
end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Export element's nested objects
|
155
|
+
#
|
156
|
+
# @param [XMLable::Mixins::Object] el
|
157
|
+
# @param [XMLable::Options::Storage] opts
|
158
|
+
#
|
159
|
+
# @return [Hash]
|
160
|
+
#
|
161
|
+
def export_element_children(el, opts)
|
162
|
+
object_handlers(el, opts).each_with_object({}) do |h, memo|
|
163
|
+
obj = el[h.method_name]
|
164
|
+
if h.is_a?(Handlers::Element)
|
165
|
+
next if opts.drop_empty_elements? && empty?(obj)
|
166
|
+
elsif h.is_a?(Handlers::Attribute)
|
167
|
+
next if opts.drop_empty_attributes? && empty?(obj)
|
168
|
+
end
|
169
|
+
memo[key(h, opts)] = export_object(obj, opts)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# Export root object
|
175
|
+
#
|
176
|
+
# @param [XMLable::Mixins::Object] el
|
177
|
+
# @param [XMLable::Options::Storage] opts
|
178
|
+
#
|
179
|
+
# @return [Hash{String => Object}]
|
180
|
+
#
|
181
|
+
def export_root(el, opts)
|
182
|
+
tag = described?(el.root) ? key(el.root, opts) : el.__node.root.name
|
183
|
+
if !opts.drop_empty_elements? || !empty?(el.root)
|
184
|
+
value = export_object(el.root, opts)
|
185
|
+
end
|
186
|
+
{ tag => value }
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
# Export object
|
191
|
+
#
|
192
|
+
# @param [XMLable::Mixins::Object, XMLable::Mixins::Container] obj
|
193
|
+
# @param [XMLable::Options::Storage] opts
|
194
|
+
#
|
195
|
+
# @return [Object]
|
196
|
+
#
|
197
|
+
def export_object(obj, opts)
|
198
|
+
case obj
|
199
|
+
when Mixins::Container then export_elements(obj, opts)
|
200
|
+
when Mixins::ElementsStorage then export_element(obj, opts)
|
201
|
+
when Mixins::RootStorage then export_root(obj, opts)
|
202
|
+
when Mixins::ValueStorage then export_value(obj, opts)
|
203
|
+
else fail("Don't know how to export #{obj.class.ancestors.inspect}.")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Exports
|
3
|
+
#
|
4
|
+
# XMLExporter class exports the data into XML format
|
5
|
+
#
|
6
|
+
class XMLExporter < Base
|
7
|
+
#
|
8
|
+
# @see XMLable::Exports::Base#initialize
|
9
|
+
#
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@node = @element.__node
|
13
|
+
@document = @node.document? ? @node : @node.document
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Export the data into XML format
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
#
|
21
|
+
def export
|
22
|
+
opts = node_nested_options(@element.__node)
|
23
|
+
builder.tap { |b| export_node(@element.__node, opts.merge(xml: b)) }
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
#
|
29
|
+
# XML builder
|
30
|
+
#
|
31
|
+
# @return [Nokogiri::XML:::Builder]
|
32
|
+
#
|
33
|
+
def builder
|
34
|
+
opts = {}
|
35
|
+
opts[:encoding] = @document.encoding if @document.encoding
|
36
|
+
::Nokogiri::XML::Builder.new(opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Get element's attributes
|
41
|
+
#
|
42
|
+
# @param [Nokogiri::XML::Element] node XML element
|
43
|
+
# @param [XMLable::Options::Storage] opts
|
44
|
+
#
|
45
|
+
# @return [Hash{String => String}]
|
46
|
+
#
|
47
|
+
def node_attributes(node, opts)
|
48
|
+
return {} unless node.respond_to?(:attributes)
|
49
|
+
attrs = node.attributes.values.select do |att|
|
50
|
+
next if opts.drop_undescribed_attributes? && !described?(att)
|
51
|
+
next if opts.drop_empty_attributes? && empty?(att)
|
52
|
+
true
|
53
|
+
end
|
54
|
+
attrs.each_with_object({}) do |a, hash|
|
55
|
+
name = [a.name]
|
56
|
+
name.unshift(a.namespace.prefix) if a.namespace && a.namespace.prefix
|
57
|
+
hash[name.join(':')] = a.value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Get node's namespaces
|
63
|
+
#
|
64
|
+
# @param [Nokogiri::XML::Node] node
|
65
|
+
# @param [XMLable::Options::Storage] opts
|
66
|
+
#
|
67
|
+
# @return [Hash{String => String}]
|
68
|
+
#
|
69
|
+
def node_namespaces(node, opts)
|
70
|
+
return {} unless node.respond_to?(:namespace_definitions)
|
71
|
+
|
72
|
+
node.namespace_definitions.each_with_object({}) do |n, obj|
|
73
|
+
name = ["xmlns", n.prefix].compact.join(":")
|
74
|
+
obj[name] = n.href
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Export XML document
|
80
|
+
#
|
81
|
+
# @param [Nokogiri::XML::Document] doc
|
82
|
+
# @param [XMLable::Options::Storage] opts
|
83
|
+
#
|
84
|
+
def export_document(doc, opts)
|
85
|
+
export_node(doc.root, opts)
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Export XML element
|
90
|
+
#
|
91
|
+
# @param [Nokogiri::XML::Element] node
|
92
|
+
# @param [XMLable::Options::Storage] opts
|
93
|
+
#
|
94
|
+
def export_element(node, opts)
|
95
|
+
opts = node_merged_opts(node, opts)
|
96
|
+
ns = node.namespace
|
97
|
+
if ns && !node_ns_definition(node, ns.prefix)
|
98
|
+
opts[:xml] = opts[:xml][ns.prefix] if ns.prefix
|
99
|
+
end
|
100
|
+
opts[:xml].send("#{node.name}_", element_args(node, opts)) do |xml|
|
101
|
+
if ns && node_ns_definition(node, ns)
|
102
|
+
xml.parent.namespace = node_ns_definition(xml.parent, ns.prefix)
|
103
|
+
end
|
104
|
+
if !opts.drop_empty_elements? || !empty?(node)
|
105
|
+
export_node_children(node, opts.merge(xml: xml))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Get XML element's attributes and namespace definitions
|
112
|
+
#
|
113
|
+
# @param [Nokogiri::XML::Element] node
|
114
|
+
# @param [XMLable::Options::Storage] opts
|
115
|
+
#
|
116
|
+
# @return [Hash{String => String}]
|
117
|
+
#
|
118
|
+
def element_args(node, opts)
|
119
|
+
node_namespaces(node, opts).merge(node_attributes(node, opts))
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Get element's namespace definition
|
124
|
+
#
|
125
|
+
# @param [Nokogiri::XML::Element] node
|
126
|
+
# @param [Nokogiri::XML::Namespace, String] ns
|
127
|
+
#
|
128
|
+
# @return [Nokogiri::XML::Namespace, nil] returns namespace if it's found,
|
129
|
+
# otherwise +nil+
|
130
|
+
#
|
131
|
+
def node_ns_definition(node, ns)
|
132
|
+
prefix = ns.is_a?(Nokogiri::XML::Namespace) ? ns.prefix : ns
|
133
|
+
node.namespace_definitions.find { |n| n.prefix == prefix }
|
134
|
+
end
|
135
|
+
|
136
|
+
#
|
137
|
+
# Export nodes' children
|
138
|
+
#
|
139
|
+
# @param [Nokogiri::XML::Element] node
|
140
|
+
# @param [XMLable::Options::Storage] opts
|
141
|
+
#
|
142
|
+
def export_node_children(node, opts)
|
143
|
+
node.children.each do |child|
|
144
|
+
next if child.is_a?(Nokogiri::XML::Attr)
|
145
|
+
if child.is_a?(Nokogiri::XML::Element)
|
146
|
+
next if opts.drop_empty_elements? && empty?(child)
|
147
|
+
next if opts.drop_undescribed_elements? && !described?(child)
|
148
|
+
end
|
149
|
+
export_node(child, opts)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Export XML text node
|
155
|
+
#
|
156
|
+
# @param [Nokogiri::XML::Text] node
|
157
|
+
# @param [XMLable::Options::Storage] opts
|
158
|
+
#
|
159
|
+
def export_text(node, opts)
|
160
|
+
opts[:xml].text(node.text)
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Export XML node
|
165
|
+
#
|
166
|
+
# @param [Nokogiri::XML::Node] node
|
167
|
+
# @param [XMLable::Options::Storage] opts
|
168
|
+
#
|
169
|
+
def export_node(node, opts)
|
170
|
+
case node
|
171
|
+
when Nokogiri::XML::Document then export_document(node, opts)
|
172
|
+
when Nokogiri::XML::Element then export_element(node, opts)
|
173
|
+
when Nokogiri::XML::Text then export_text(node, opts)
|
174
|
+
else fail "Don't know how to export node: #{node}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
#
|
4
|
+
# Attribute handles XML attributes objects
|
5
|
+
#
|
6
|
+
class Attribute < Base
|
7
|
+
include Mixins::Namespace
|
8
|
+
include Mixins::Described
|
9
|
+
include Mixins::Tag
|
10
|
+
|
11
|
+
#
|
12
|
+
# @see XMLable::Handler::Base#inject_class
|
13
|
+
#
|
14
|
+
def inject_wraped(klass)
|
15
|
+
klass.class_eval do
|
16
|
+
include XMLable::Mixins::ValueStorage
|
17
|
+
include XMLable::Mixins::Instantiable
|
18
|
+
end
|
19
|
+
klass
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# @see XMLable::Handler::Base#proxy
|
24
|
+
#
|
25
|
+
def proxy
|
26
|
+
@proxy ||= type_class.tap { |a| a.class_eval(&@block) if block_settings? }
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Create attribute object from the XML attribute
|
31
|
+
#
|
32
|
+
# @param [Nokogiri::XML::Attr] attribute
|
33
|
+
#
|
34
|
+
# @return [XMLable::Mixins::Object]
|
35
|
+
#
|
36
|
+
def from_xml_attribute(attribute)
|
37
|
+
Builder.build_attribute(attribute, self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
#
|
4
|
+
# Base contains base handlers logic
|
5
|
+
#
|
6
|
+
class Base
|
7
|
+
# @return [Object]
|
8
|
+
attr_reader :type
|
9
|
+
|
10
|
+
# @return [#call] returns block with additional settings
|
11
|
+
attr_reader :block
|
12
|
+
|
13
|
+
#
|
14
|
+
# @param [String, Symbol] name element/attribute name
|
15
|
+
# @param [Hash] opts adtional handler options
|
16
|
+
# @option opts [Object] :tag element/attribute tag name
|
17
|
+
# @option opts [Object] :type element/attribute class object
|
18
|
+
# @option opts [Object] :container elements container
|
19
|
+
#
|
20
|
+
def initialize(name, opts = {}, &block)
|
21
|
+
@name = name.to_s
|
22
|
+
@type = opts.delete(:type) || String
|
23
|
+
@block = block
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Type class for the handler element
|
28
|
+
#
|
29
|
+
# @return [#new] returns class to store elements and attributes
|
30
|
+
#
|
31
|
+
def type_class
|
32
|
+
klass = Builder.proxy_for(@type)
|
33
|
+
wrapped_type? ? inject_wraped(klass) : klass
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Proxy object which holds element data
|
38
|
+
#
|
39
|
+
# @return [#new]
|
40
|
+
#
|
41
|
+
def proxy
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Inject type class with addtional logic
|
47
|
+
#
|
48
|
+
# @param [Class] klass
|
49
|
+
#
|
50
|
+
# @return [Class]
|
51
|
+
#
|
52
|
+
def inject_wraped(klass)
|
53
|
+
end
|
54
|
+
|
55
|
+
def wrapped_type?
|
56
|
+
Builder.wrapped_type?(type)
|
57
|
+
end
|
58
|
+
|
59
|
+
def options?
|
60
|
+
!options.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
def options
|
64
|
+
proxy.__options
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Handler's element method name
|
69
|
+
#
|
70
|
+
# @return [String]
|
71
|
+
#
|
72
|
+
def method_name
|
73
|
+
@name
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Does the handler have additional settins
|
78
|
+
#
|
79
|
+
# @return [Boolean]
|
80
|
+
#
|
81
|
+
def block_settings?
|
82
|
+
@block != nil
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Factory to build a handler
|
87
|
+
#
|
88
|
+
# @return [XMLable::Handlers::Base]
|
89
|
+
#
|
90
|
+
def self.build(*args, &block)
|
91
|
+
name = args.shift.to_s
|
92
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
93
|
+
opts[:type] = args.shift if args.size > 0
|
94
|
+
opts[:container] = args.shift if args.size > 0
|
95
|
+
|
96
|
+
# standalone
|
97
|
+
opts[:tag] = opts[:type].__tag if opts[:type].respond_to?(:__tag)
|
98
|
+
|
99
|
+
new(name, opts, &block)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
#
|
4
|
+
# Document class handles XML document
|
5
|
+
#
|
6
|
+
class Document < Base
|
7
|
+
#
|
8
|
+
# @param [Class] type
|
9
|
+
#
|
10
|
+
def initialize(type)
|
11
|
+
@type = type
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# @see XMLable::Handler::Base#proxy
|
16
|
+
#
|
17
|
+
def proxy
|
18
|
+
@type
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Create document object from the XML document
|
23
|
+
#
|
24
|
+
# @param [Nokogiri::XML::Document] doc
|
25
|
+
#
|
26
|
+
# @return [XMLable::Mixins::Object]
|
27
|
+
#
|
28
|
+
def from_xml_document(doc)
|
29
|
+
Builder.build_document(doc, self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module XMLable
|
2
|
+
module Handlers
|
3
|
+
class Element < Base
|
4
|
+
include Mixins::Namespace
|
5
|
+
include Mixins::Described
|
6
|
+
include Mixins::Tag
|
7
|
+
|
8
|
+
#
|
9
|
+
# @see XMLable::Handler::Base#initialize
|
10
|
+
#
|
11
|
+
def initialize(name, opts = {}, &block)
|
12
|
+
@container_type = opts.delete(:container) || Array
|
13
|
+
super(name, opts, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Proxy class for elements objects
|
18
|
+
#
|
19
|
+
# @return [Class]
|
20
|
+
#
|
21
|
+
def container_proxy
|
22
|
+
@container_proxy ||= Builder.container_proxy_for(@container_type)
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Create elements container for XML element
|
27
|
+
#
|
28
|
+
# @parent [Nokogiri::XML::Element]
|
29
|
+
#
|
30
|
+
# @return [#each]
|
31
|
+
#
|
32
|
+
def container_for_xml_element(parent)
|
33
|
+
container_proxy.new.tap do |c|
|
34
|
+
c.__set_parent_node(parent)
|
35
|
+
c.__set_handler(self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# @see XMLable::Handler::Base#inject_wraped
|
41
|
+
#
|
42
|
+
def inject_wraped(klass)
|
43
|
+
klass.class_eval do
|
44
|
+
include XMLable::Mixins::ContentStorage
|
45
|
+
include XMLable::Mixins::AttributesStorage
|
46
|
+
include XMLable::Mixins::ElementsStorage
|
47
|
+
include XMLable::Mixins::NamespaceDefinitionsStorage
|
48
|
+
include XMLable::Mixins::BareValue
|
49
|
+
include XMLable::Mixins::Instantiable
|
50
|
+
end
|
51
|
+
klass
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# @see XMLable::Handler::Base#proxy
|
56
|
+
#
|
57
|
+
def proxy
|
58
|
+
@proxy ||= type_class.tap do |p|
|
59
|
+
p.__default_namespace = namespace_prefix
|
60
|
+
p.class_eval(&@block) if block_settings?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#def dynamic?
|
65
|
+
#@block != nil
|
66
|
+
#end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Is this handler for multiple elements objects or not?
|
70
|
+
#
|
71
|
+
# @return [Boolean]
|
72
|
+
#
|
73
|
+
def single?
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Create element object from the XML element
|
79
|
+
#
|
80
|
+
# @param [Nokogiri::XML::Element] element
|
81
|
+
#
|
82
|
+
# @return [XMLable::Mixins::Object]
|
83
|
+
#
|
84
|
+
def from_xml_element(element)
|
85
|
+
Builder.build_element(element, self)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|