xmlable 0.0.0.alpha1
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.
- 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
|