shale 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +93 -7
  4. data/exe/shaleb +30 -6
  5. data/lib/shale/adapter/nokogiri/document.rb +87 -0
  6. data/lib/shale/adapter/nokogiri/node.rb +100 -0
  7. data/lib/shale/adapter/nokogiri.rb +11 -151
  8. data/lib/shale/adapter/ox/document.rb +80 -0
  9. data/lib/shale/adapter/ox/node.rb +88 -0
  10. data/lib/shale/adapter/ox.rb +9 -134
  11. data/lib/shale/adapter/rexml/document.rb +88 -0
  12. data/lib/shale/adapter/rexml/node.rb +99 -0
  13. data/lib/shale/adapter/rexml.rb +9 -150
  14. data/lib/shale/error.rb +35 -2
  15. data/lib/shale/mapper.rb +2 -2
  16. data/lib/shale/schema/{json_compiler → compiler}/boolean.rb +1 -1
  17. data/lib/shale/schema/{json_compiler/object.rb → compiler/complex.rb} +11 -8
  18. data/lib/shale/schema/{json_compiler → compiler}/date.rb +1 -1
  19. data/lib/shale/schema/{json_compiler → compiler}/float.rb +1 -1
  20. data/lib/shale/schema/{json_compiler → compiler}/integer.rb +1 -1
  21. data/lib/shale/schema/{json_compiler → compiler}/property.rb +6 -6
  22. data/lib/shale/schema/{json_compiler → compiler}/string.rb +1 -1
  23. data/lib/shale/schema/{json_compiler → compiler}/time.rb +1 -1
  24. data/lib/shale/schema/compiler/value.rb +21 -0
  25. data/lib/shale/schema/compiler/xml_complex.rb +50 -0
  26. data/lib/shale/schema/compiler/xml_property.rb +73 -0
  27. data/lib/shale/schema/json_compiler.rb +32 -34
  28. data/lib/shale/schema/json_generator.rb +3 -3
  29. data/lib/shale/schema/xml_compiler.rb +919 -0
  30. data/lib/shale/schema/xml_generator.rb +7 -7
  31. data/lib/shale/schema.rb +16 -0
  32. data/lib/shale/type/{composite.rb → complex.rb} +20 -2
  33. data/lib/shale/utils.rb +42 -7
  34. data/lib/shale/version.rb +1 -1
  35. data/lib/shale.rb +8 -19
  36. data/shale.gemspec +1 -1
  37. metadata +23 -15
  38. data/lib/shale/schema/json_compiler/utils.rb +0 -52
  39. data/lib/shale/schema/json_compiler/value.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26877841702bfce542b42206f519ffd1b03e2f0d3db1e70a42e37836ff0f3bff
4
- data.tar.gz: 23fddba7256bc38b5d64309cf56833f47fd636ed0e9f6ec61f2a076764dad2bb
3
+ metadata.gz: aaa3043e612d332fab30ff87ecab722e3812e7769eba982db27c38f74c205ce1
4
+ data.tar.gz: bb5cdb963bce5756c48edb37d28bddc40a816901e87b4714ea512f07f8ec4c28
5
5
  SHA512:
6
- metadata.gz: e98bd0bbb20fbbaf4a8bdbfb5e2f83ba5d7bae78ad66a8597a1fe28c0c13d9799bc3ade785105ea7261147f55590ff530e85c31da459fe8c9171ee5b68f02977
7
- data.tar.gz: 54be0efe36f4d330c551f1bd8994a36b360ecec3696aafe12382408a0656e50a181b91ff54ec9f39758908d15fcf51eafc4810540cd1aeb00bda7b552382bc80
6
+ metadata.gz: ed1f1ffc88cabb5f9403ff957c02efc4565aee73b9a8a1fd2297ff13bfbb6bdf0e94664b865f8d2d812ddd66fe97d154e34982eea3318ba01c6d16b4a6922c70
7
+ data.tar.gz: d41392de36bcace9efee12a869f49beffba235ae09e09f33c6973159b96320e3f657a6edd4d634e53da430f8127e74fa1025fa2f5c75dad2e7568abe6a0794ce
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [0.5.0] - 2022-06-28
2
+
3
+ ### Added
4
+ - Allow to generate Shale model from XML Schema
5
+
6
+ ### Changed
7
+ - Shale doesn't defaults to REXML anymore - XML adapter needs to be set explicitly
8
+ - Rename "JSONSchemaError" to "SchemaError"
9
+ - Rename "Composite" type to "Complex"
10
+ - Drop support for Ruby 2.6
11
+
1
12
  ## [0.4.0] - 2022-05-30
2
13
 
3
14
  ### Added
data/README.md CHANGED
@@ -4,18 +4,20 @@ Shale is a Ruby object mapper and serializer for JSON, YAML and XML.
4
4
  It allows you to parse JSON, YAML and XML data and convert it into Ruby data structures,
5
5
  as well as serialize data structures into JSON, YAML or XML.
6
6
 
7
+ Documentation with interactive examples is available at [Shale website](https://www.shalerb.org)
8
+
7
9
  ## Features
8
10
 
9
11
  * Convert JSON, YAML and XML to Ruby data model
10
12
  * Convert Ruby data model to JSON, YAML and XML
11
13
  * Generate JSON and XML Schema from Ruby models
12
- * Compile JSON Schema into Ruby models
14
+ * Compile JSON and XML Schema into Ruby models
13
15
  * Out of the box support for JSON, YAML, Nokogiri, REXML and Ox parsers
14
16
  * Support for custom adapters
15
17
 
16
18
  ## Installation
17
19
 
18
- Shale supports Ruby (MRI) 2.6+
20
+ Shale supports Ruby (MRI) 2.7+
19
21
 
20
22
  Add this line to your application's Gemfile:
21
23
 
@@ -60,11 +62,10 @@ $ gem install shale
60
62
  * [Generating JSON Schema](#generating-json-schema)
61
63
  * [Compiling JSON Schema into Shale model](#compiling-json-schema-into-shale-model)
62
64
  * [Generating XML Schema](#generating-xml-schema)
65
+ * [Compiling XML Schema into Shale model](#compiling-xml-schema-into-shale-model)
63
66
 
64
67
  ## Usage
65
68
 
66
- Documentation with interactive examples is available at [Shale website](https://www.shalerb.org)
67
-
68
69
  ### Simple use case
69
70
 
70
71
  ```ruby
@@ -230,6 +231,15 @@ person.to_hash
230
231
 
231
232
  ### Converting XML to object
232
233
 
234
+ To use XML with Shale you have to set adapter you want to use.
235
+ Shale comes with adapters for REXML, Nokogiri and OX parsers.
236
+ For details see [Adapters](#adapters) section.
237
+
238
+ ```ruby
239
+ require 'shale/adapter/rexml'
240
+ Shale.xml_adapter = Shale::Adapter::REXML
241
+ ```
242
+
233
243
  ```ruby
234
244
  person = Person.from_xml(<<~DATA)
235
245
  <person>
@@ -588,8 +598,7 @@ end
588
598
  ### Adapters
589
599
 
590
600
  Shale uses adapters for parsing and generating documents.
591
- By default Ruby's standard JSON parser is used for handling JSON documents, YAML for YAML and
592
- REXML for XML.
601
+ By default Ruby's standard JSON and YAML parsers are used for handling JSON and YAML documents.
593
602
 
594
603
  You can change it by providing your own adapter. For JSON and YAML, adapter must implement
595
604
  `.load` and `.dump` class methods.
@@ -602,6 +611,7 @@ Shale.json_adapter = MultiJson
602
611
  Shale.yaml_adapter = MyYamlAdapter
603
612
  ```
604
613
 
614
+ To handle XML documents you have to explicitly set XML adapter.
605
615
  Shale provides adapters for most popular Ruby XML parsers:
606
616
 
607
617
  :warning: **Ox doesn't support XML namespaces**
@@ -609,7 +619,7 @@ Shale provides adapters for most popular Ruby XML parsers:
609
619
  ```ruby
610
620
  require 'shale'
611
621
 
612
- # REXML is used by default:
622
+ # if you want to use REXML:
613
623
 
614
624
  require 'shale/adapter/rexml'
615
625
  Shale.xml_adapter = Shale::Adapter::REXML
@@ -842,6 +852,82 @@ end
842
852
  Shale::Schema::XMLGenerator.register_xml_type(MyEmailType, 'myEmailXMLType')
843
853
  ```
844
854
 
855
+ ### Compiling XML Schema into Shale model
856
+
857
+ To generate Shale data model from XML Schema use:
858
+
859
+ ```ruby
860
+ require 'shale/schema'
861
+
862
+ schema = <<~SCHEMA
863
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
864
+ <xs:element name="Person" type="Person" />
865
+
866
+ <xs:complexType name="Person">
867
+ <xs:sequence>
868
+ <xs:element name="FirstName" type="xs:string" />
869
+ <xs:element name="LastName" type="xs:string" />
870
+ <xs:element name="Address" type="Address" />
871
+ </xs:sequence>
872
+ </xs:complexType>
873
+
874
+ <xs:complexType name="Address">
875
+ <xs:sequence>
876
+ <xs:element name="Street" type="xs:string" />
877
+ <xs:element name="City" type="xs:string" />
878
+ </xs:sequence>
879
+ </xs:complexType>
880
+ </xs:schema>
881
+ SCHEMA
882
+
883
+ Shale::Schema.from_xml([schema])
884
+
885
+ # =>
886
+ #
887
+ # {
888
+ # "address" => "
889
+ # require 'shale'
890
+ #
891
+ # class Address < Shale::Mapper
892
+ # attribute :street, Shale::Type::String
893
+ # attribute :city, Shale::Type::String
894
+ #
895
+ # xml do
896
+ # root 'Address'
897
+ #
898
+ # map_element 'Street', to: :street
899
+ # map_element 'City', to: :city
900
+ # end
901
+ # end
902
+ # ",
903
+ # "person" => "
904
+ # require 'shale'
905
+ #
906
+ # require_relative 'address'
907
+ #
908
+ # class Person < Shale::Mapper
909
+ # attribute :first_name, Shale::Type::String
910
+ # attribute :last_name, Shale::Type::String
911
+ # attribute :address, Address
912
+ #
913
+ # xml do
914
+ # root 'Person'
915
+ #
916
+ # map_element 'FirstName', to: :first_name
917
+ # map_element 'LastName', to: :last_name
918
+ # map_element 'Address', to: :address
919
+ # end
920
+ # end
921
+ # "
922
+ # }
923
+ ```
924
+
925
+ You can also use a command line tool to do it:
926
+
927
+ ```
928
+ $ shaleb -c -f xml -i schema.xml
929
+ ```
930
+
845
931
  ## Contributing
846
932
 
847
933
  Bug reports and pull requests are welcome on GitHub at https://github.com/kgiszczak/shale.
data/exe/shaleb CHANGED
@@ -4,12 +4,29 @@
4
4
  require 'fileutils'
5
5
  require 'optparse'
6
6
 
7
- base_path = File.expand_path('../lib', __dir__)
7
+ def require_local_or_global(path)
8
+ base_path = File.expand_path('../lib', __dir__)
8
9
 
9
- if File.exist?(base_path)
10
- require_relative '../lib/shale/schema'
11
- else
12
- require 'shale/schema'
10
+ if File.exist?(base_path)
11
+ require_relative "../lib/#{path}"
12
+ else
13
+ require path
14
+ end
15
+ end
16
+
17
+ require_local_or_global('shale/schema')
18
+
19
+ def load_xml_parser
20
+ require_local_or_global('shale/adapter/nokogiri')
21
+ Shale.xml_adapter = Shale::Adapter::Nokogiri
22
+ rescue LoadError
23
+ begin
24
+ require_local_or_global('shale/adapter/rexml')
25
+ Shale.xml_adapter = Shale::Adapter::REXML
26
+ rescue LoadError
27
+ puts "Can't load XML parser. Make sure Nokogiri or REXML is installed on your system!"
28
+ exit
29
+ end
13
30
  end
14
31
 
15
32
  params = {}
@@ -54,7 +71,12 @@ if params[:compile]
54
71
  end
55
72
  end
56
73
 
57
- models = Shale::Schema.from_json(schemas, root_name: params[:root])
74
+ if params[:format] == 'xml'
75
+ load_xml_parser
76
+ models = Shale::Schema.from_xml(schemas)
77
+ else
78
+ models = Shale::Schema.from_json(schemas, root_name: params[:root])
79
+ end
58
80
 
59
81
  if params[:output]
60
82
  dir = File.expand_path(params[:output], Dir.pwd)
@@ -94,6 +116,8 @@ else
94
116
  klass = Object.const_get(params[:root])
95
117
 
96
118
  if params[:format] == 'xml'
119
+ load_xml_parser
120
+
97
121
  if params[:output]
98
122
  base_name = File.basename(params[:output], File.extname(params[:output]))
99
123
  schemas = Shale::Schema.to_xml(klass, base_name, pretty: params[:pretty])
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Adapter
5
+ module Nokogiri
6
+ # Wrapper around Nokogiri API
7
+ #
8
+ # @api private
9
+ class Document
10
+ # Initialize object
11
+ #
12
+ # @api private
13
+ def initialize
14
+ @doc = ::Nokogiri::XML::Document.new
15
+ @namespaces = {}
16
+ end
17
+
18
+ # Return Nokogiri document
19
+ #
20
+ # @return [::Nokogiri::XML::Document]
21
+ #
22
+ # @api private
23
+ def doc
24
+ if @doc.root
25
+ @namespaces.each do |prefix, namespace|
26
+ @doc.root.add_namespace(prefix, namespace)
27
+ end
28
+ end
29
+
30
+ @doc
31
+ end
32
+
33
+ # Create Nokogiri element
34
+ #
35
+ # @param [String] name Name of the XML element
36
+ #
37
+ # @return [::Nokogiri::XML::Element]
38
+ #
39
+ # @api private
40
+ def create_element(name)
41
+ ::Nokogiri::XML::Element.new(name, @doc)
42
+ end
43
+
44
+ # Add XML namespace to document
45
+ #
46
+ # @param [String] prefix
47
+ # @param [String] namespace
48
+ #
49
+ # @api private
50
+ def add_namespace(prefix, namespace)
51
+ @namespaces[prefix] = namespace if prefix && namespace
52
+ end
53
+
54
+ # Add attribute to Nokogiri element
55
+ #
56
+ # @param [::Nokogiri::XML::Element] element Nokogiri element
57
+ # @param [String] name Name of the XML attribute
58
+ # @param [String] value Value of the XML attribute
59
+ #
60
+ # @api private
61
+ def add_attribute(element, name, value)
62
+ element[name] = value
63
+ end
64
+
65
+ # Add child element to Nokogiri element
66
+ #
67
+ # @param [::Nokogiri::XML::Element] element Nokogiri parent element
68
+ # @param [::Nokogiri::XML::Element] child Nokogiri child element
69
+ #
70
+ # @api private
71
+ def add_element(element, child)
72
+ element.add_child(child)
73
+ end
74
+
75
+ # Add text node to Nokogiri element
76
+ #
77
+ # @param [::Nokogiri::XML::Element] element Nokogiri element
78
+ # @param [String] text Text to add
79
+ #
80
+ # @api private
81
+ def add_text(element, text)
82
+ element.content = text
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Adapter
5
+ module Nokogiri
6
+ # Wrapper around Nokogiri::XML::Node API
7
+ #
8
+ # @api private
9
+ class Node
10
+ # Initialize object with Nokogiri node
11
+ #
12
+ # @param [::Nokogiri::XML::Node] node Nokogiri node
13
+ #
14
+ # @api private
15
+ def initialize(node)
16
+ @node = node
17
+ end
18
+
19
+ # Return namespaces defined on document
20
+ #
21
+ # @return [Hash<String, String>]
22
+ #
23
+ # @example
24
+ # node.namespaces # => { 'foo' => 'http://foo.com', 'bar' => 'http://bar.com' }
25
+ #
26
+ # @api private
27
+ def namespaces
28
+ @node.namespaces.transform_keys { |e| e.sub('xmlns:', '') }
29
+ end
30
+
31
+ # Return name of the node in the format of
32
+ # namespace:name when the node is namespaced or just name when it's not
33
+ #
34
+ # @return [String]
35
+ #
36
+ # @example without namespace
37
+ # node.name # => Bar
38
+ #
39
+ # @example with namespace
40
+ # node.name # => http://foo:Bar
41
+ #
42
+ # @api private
43
+ def name
44
+ [@node.namespace&.href, @node.name].compact.join(':')
45
+ end
46
+
47
+ # Return all attributes associated with the node
48
+ #
49
+ # @return [Hash]
50
+ #
51
+ # @api private
52
+ def attributes
53
+ @node.attribute_nodes.each_with_object({}) do |node, hash|
54
+ name = [node.namespace&.href, node.name].compact.join(':')
55
+ hash[name] = node.value
56
+ end
57
+ end
58
+
59
+ # Return node's parent
60
+ #
61
+ # @return [Shale::Adapter::Nokogiri::Node, nil]
62
+ #
63
+ # @api private
64
+ def parent
65
+ if @node.respond_to?(:parent) && @node.parent && @node.parent.name != 'document'
66
+ self.class.new(@node.parent)
67
+ end
68
+ end
69
+
70
+ # Return node's element children
71
+ #
72
+ # @return [Array<Shale::Adapter::Nokogiri::Node>]
73
+ #
74
+ # @api private
75
+ def children
76
+ @node
77
+ .children
78
+ .to_a
79
+ .filter(&:element?)
80
+ .map { |e| self.class.new(e) }
81
+ end
82
+
83
+ # Return first text child of a node
84
+ #
85
+ # @return [String]
86
+ #
87
+ # @api private
88
+ def text
89
+ first = @node
90
+ .children
91
+ .to_a
92
+ .filter(&:text?)
93
+ .first
94
+
95
+ first&.text
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -2,6 +2,10 @@
2
2
 
3
3
  require 'nokogiri'
4
4
 
5
+ require_relative '../error'
6
+ require_relative 'nokogiri/document'
7
+ require_relative 'nokogiri/node'
8
+
5
9
  module Shale
6
10
  module Adapter
7
11
  # Nokogiri adapter
@@ -12,7 +16,9 @@ module Shale
12
16
  #
13
17
  # @param [String] xml XML document
14
18
  #
15
- # @return [::Nokogiri::XML::Document]
19
+ # @raise [ParseError] when XML document has errors
20
+ #
21
+ # @return [Shale::Adapter::Nokogiri::Node]
16
22
  #
17
23
  # @api private
18
24
  def self.load(xml)
@@ -20,6 +26,10 @@ module Shale
20
26
  config.noblanks
21
27
  end
22
28
 
29
+ unless doc.errors.empty?
30
+ raise ParseError, "Document is invalid: #{doc.errors}"
31
+ end
32
+
23
33
  Node.new(doc.root)
24
34
  end
25
35
 
@@ -57,156 +67,6 @@ module Shale
57
67
  def self.create_document
58
68
  Document.new
59
69
  end
60
-
61
- # Wrapper around Nokogiri API
62
- #
63
- # @api private
64
- class Document
65
- # Initialize object
66
- #
67
- # @api private
68
- def initialize
69
- @doc = ::Nokogiri::XML::Document.new
70
- @namespaces = {}
71
- end
72
-
73
- # Return Nokogiri document
74
- #
75
- # @return [::Nokogiri::XML::Document]
76
- #
77
- # @api private
78
- def doc
79
- if @doc.root
80
- @namespaces.each do |prefix, namespace|
81
- @doc.root.add_namespace(prefix, namespace)
82
- end
83
- end
84
-
85
- @doc
86
- end
87
-
88
- # Create Nokogiri element
89
- #
90
- # @param [String] name Name of the XML element
91
- #
92
- # @return [::Nokogiri::XML::Element]
93
- #
94
- # @api private
95
- def create_element(name)
96
- ::Nokogiri::XML::Element.new(name, @doc)
97
- end
98
-
99
- # Add XML namespace to document
100
- #
101
- # @param [String] prefix
102
- # @param [String] namespace
103
- #
104
- # @api private
105
- def add_namespace(prefix, namespace)
106
- @namespaces[prefix] = namespace if prefix && namespace
107
- end
108
-
109
- # Add attribute to Nokogiri element
110
- #
111
- # @param [::Nokogiri::XML::Element] element Nokogiri element
112
- # @param [String] name Name of the XML attribute
113
- # @param [String] value Value of the XML attribute
114
- #
115
- # @api private
116
- def add_attribute(element, name, value)
117
- element[name] = value
118
- end
119
-
120
- # Add child element to Nokogiri element
121
- #
122
- # @param [::Nokogiri::XML::Element] element Nokogiri parent element
123
- # @param [::Nokogiri::XML::Element] child Nokogiri child element
124
- #
125
- # @api private
126
- def add_element(element, child)
127
- element.add_child(child)
128
- end
129
-
130
- # Add text node to Nokogiri element
131
- #
132
- # @param [::Nokogiri::XML::Element] element Nokogiri element
133
- # @param [String] text Text to add
134
- #
135
- # @api private
136
- def add_text(element, text)
137
- element.content = text
138
- end
139
- end
140
-
141
- # Wrapper around Nokogiri::XML::Node API
142
- #
143
- # @api private
144
- class Node
145
- # Initialize object with Nokogiri node
146
- #
147
- # @param [::Nokogiri::XML::Node] node Nokogiri node
148
- #
149
- # @api private
150
- def initialize(node)
151
- @node = node
152
- end
153
-
154
- # Return name of the node in the format of
155
- # namespace:name when the node is namespaced or just name when it's not
156
- #
157
- # @return [String]
158
- #
159
- # @example without namespace
160
- # node.name # => Bar
161
- #
162
- # @example with namespace
163
- # node.name # => http://foo:Bar
164
- #
165
- # @api private
166
- def name
167
- [@node.namespace&.href, @node.name].compact.join(':')
168
- end
169
-
170
- # Return all attributes associated with the node
171
- #
172
- # @return [Hash]
173
- #
174
- # @api private
175
- def attributes
176
- @node.attribute_nodes.each_with_object({}) do |node, hash|
177
- name = [node.namespace&.href, node.name].compact.join(':')
178
- hash[name] = node.value
179
- end
180
- end
181
-
182
- # Return node's element children
183
- #
184
- # @return [Array<Shale::Adapter::Nokogiri::Node>]
185
- #
186
- # @api private
187
- def children
188
- @node
189
- .children
190
- .to_a
191
- .filter(&:element?)
192
- .map { |e| self.class.new(e) }
193
- end
194
-
195
- # Return first text child of a node
196
- #
197
- # @return [String]
198
- #
199
- # @api private
200
- def text
201
- first = @node
202
- .children
203
- .to_a
204
- .filter(&:text?)
205
- .first
206
-
207
- first&.text
208
- end
209
- end
210
70
  end
211
71
  end
212
72
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Adapter
5
+ module Ox
6
+ # Wrapper around Ox API
7
+ #
8
+ # @api private
9
+ class Document
10
+ # Return Ox document
11
+ #
12
+ # @return [::Ox::Document]
13
+ #
14
+ # @api private
15
+ attr_reader :doc
16
+
17
+ # Initialize object
18
+ #
19
+ # @api private
20
+ def initialize
21
+ @doc = ::Ox::Document.new
22
+ end
23
+
24
+ # Create Ox element
25
+ #
26
+ # @param [String] name Name of the XML element
27
+ #
28
+ # @return [::Ox::Element]
29
+ #
30
+ # @api private
31
+ def create_element(name)
32
+ ::Ox::Element.new(name)
33
+ end
34
+
35
+ # Add XML namespace to document
36
+ #
37
+ # Ox doesn't support XML namespaces so this method does nothing.
38
+ #
39
+ # @param [String] prefix
40
+ # @param [String] namespace
41
+ #
42
+ # @api private
43
+ def add_namespace(prefix, namespace)
44
+ # :noop:
45
+ end
46
+
47
+ # Add attribute to Ox element
48
+ #
49
+ # @param [::Ox::Element] element Ox element
50
+ # @param [String] name Name of the XML attribute
51
+ # @param [String] value Value of the XML attribute
52
+ #
53
+ # @api private
54
+ def add_attribute(element, name, value)
55
+ element[name] = value
56
+ end
57
+
58
+ # Add child element to Ox element
59
+ #
60
+ # @param [::Ox::Element] element Ox parent element
61
+ # @param [::Ox::Element] child Ox child element
62
+ #
63
+ # @api private
64
+ def add_element(element, child)
65
+ element << child
66
+ end
67
+
68
+ # Add text node to Ox element
69
+ #
70
+ # @param [::Ox::Element] element Ox element
71
+ # @param [String] text Text to add
72
+ #
73
+ # @api private
74
+ def add_text(element, text)
75
+ element << text
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end