shale 0.3.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/README.md +398 -41
- data/exe/shaleb +108 -36
- data/lib/shale/adapter/nokogiri/document.rb +97 -0
- data/lib/shale/adapter/nokogiri/node.rb +100 -0
- data/lib/shale/adapter/nokogiri.rb +11 -151
- data/lib/shale/adapter/ox/document.rb +90 -0
- data/lib/shale/adapter/ox/node.rb +97 -0
- data/lib/shale/adapter/ox.rb +9 -134
- data/lib/shale/adapter/rexml/document.rb +98 -0
- data/lib/shale/adapter/rexml/node.rb +99 -0
- data/lib/shale/adapter/rexml.rb +9 -150
- data/lib/shale/adapter/toml_rb.rb +34 -0
- data/lib/shale/attribute.rb +6 -0
- data/lib/shale/error.rb +56 -0
- data/lib/shale/mapper.rb +67 -13
- data/lib/shale/mapping/descriptor/xml.rb +10 -1
- data/lib/shale/mapping/dict.rb +18 -0
- data/lib/shale/mapping/xml.rb +40 -5
- data/lib/shale/schema/compiler/boolean.rb +21 -0
- data/lib/shale/schema/compiler/complex.rb +88 -0
- data/lib/shale/schema/compiler/date.rb +21 -0
- data/lib/shale/schema/compiler/float.rb +21 -0
- data/lib/shale/schema/compiler/integer.rb +21 -0
- data/lib/shale/schema/compiler/property.rb +70 -0
- data/lib/shale/schema/compiler/string.rb +21 -0
- data/lib/shale/schema/compiler/time.rb +21 -0
- data/lib/shale/schema/compiler/value.rb +21 -0
- data/lib/shale/schema/compiler/xml_complex.rb +50 -0
- data/lib/shale/schema/compiler/xml_property.rb +73 -0
- data/lib/shale/schema/json_compiler.rb +331 -0
- data/lib/shale/schema/{json → json_generator}/base.rb +2 -2
- data/lib/shale/schema/{json → json_generator}/boolean.rb +1 -1
- data/lib/shale/schema/{json → json_generator}/collection.rb +2 -2
- data/lib/shale/schema/{json → json_generator}/date.rb +1 -1
- data/lib/shale/schema/{json → json_generator}/float.rb +1 -1
- data/lib/shale/schema/{json → json_generator}/integer.rb +1 -1
- data/lib/shale/schema/{json → json_generator}/object.rb +5 -2
- data/lib/shale/schema/{json → json_generator}/ref.rb +1 -1
- data/lib/shale/schema/{json → json_generator}/schema.rb +6 -4
- data/lib/shale/schema/{json → json_generator}/string.rb +1 -1
- data/lib/shale/schema/{json → json_generator}/time.rb +1 -1
- data/lib/shale/schema/json_generator/value.rb +23 -0
- data/lib/shale/schema/{json.rb → json_generator.rb} +36 -36
- data/lib/shale/schema/xml_compiler.rb +919 -0
- data/lib/shale/schema/{xml → xml_generator}/attribute.rb +1 -1
- data/lib/shale/schema/{xml → xml_generator}/complex_type.rb +5 -2
- data/lib/shale/schema/{xml → xml_generator}/element.rb +1 -1
- data/lib/shale/schema/{xml → xml_generator}/import.rb +1 -1
- data/lib/shale/schema/{xml → xml_generator}/ref_attribute.rb +1 -1
- data/lib/shale/schema/{xml → xml_generator}/ref_element.rb +1 -1
- data/lib/shale/schema/{xml → xml_generator}/schema.rb +5 -5
- data/lib/shale/schema/{xml → xml_generator}/typed_attribute.rb +1 -1
- data/lib/shale/schema/{xml → xml_generator}/typed_element.rb +1 -1
- data/lib/shale/schema/{xml.rb → xml_generator.rb} +25 -26
- data/lib/shale/schema.rb +44 -5
- data/lib/shale/type/{composite.rb → complex.rb} +156 -51
- data/lib/shale/type/value.rb +31 -2
- data/lib/shale/utils.rb +42 -7
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +22 -19
- data/shale.gemspec +3 -3
- metadata +50 -29
data/exe/shaleb
CHANGED
@@ -1,14 +1,32 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'fileutils'
|
4
5
|
require 'optparse'
|
5
6
|
|
6
|
-
|
7
|
+
def require_local_or_global(path)
|
8
|
+
base_path = File.expand_path('../lib', __dir__)
|
7
9
|
|
8
|
-
if File.exist?(base_path)
|
9
|
-
|
10
|
-
else
|
11
|
-
|
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
|
12
30
|
end
|
13
31
|
|
14
32
|
params = {}
|
@@ -16,11 +34,17 @@ params = {}
|
|
16
34
|
ARGV << '-h' if ARGV.empty?
|
17
35
|
|
18
36
|
OptionParser.new do |opts|
|
19
|
-
opts.banner =
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
37
|
+
opts.banner = <<~BANNER
|
38
|
+
Usage: shaleb [options]
|
39
|
+
example generate schema from Shale model: shaleb -g -i data_model.rb -c MyRoot
|
40
|
+
example generate Shale model from schema: shaleb -c -i schema1.json,schema2.json -c MyRoot
|
41
|
+
BANNER
|
42
|
+
|
43
|
+
opts.on('-g', '--generate', 'generate schema from Shale model')
|
44
|
+
opts.on('-c', '--compile', 'compile schema into Shale model')
|
45
|
+
opts.on('-i INPUT', '--input', Array, 'Input file')
|
46
|
+
opts.on('-o OUTPUT', '--output', 'Output (defaults to STDOUT)')
|
47
|
+
opts.on('-r ROOT', '--root ROOT', 'Shale model class name')
|
24
48
|
opts.on('-f FORMAT', '--format FORMAT', 'Schema format: JSON (default), XML')
|
25
49
|
opts.on('-p', '--pretty', 'Pretty print generated schema')
|
26
50
|
|
@@ -30,46 +54,94 @@ OptionParser.new do |opts|
|
|
30
54
|
end
|
31
55
|
end.parse!(into: params)
|
32
56
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
57
|
+
if params[:compile]
|
58
|
+
unless params[:input]
|
59
|
+
puts 'Input file is required: shaleb -c -i schema1.json,schema2.json'
|
60
|
+
exit
|
61
|
+
end
|
39
62
|
|
40
|
-
|
41
|
-
|
42
|
-
exit
|
43
|
-
end
|
63
|
+
schemas = params[:input].map do |file|
|
64
|
+
path = File.expand_path(file, Dir.pwd)
|
44
65
|
|
45
|
-
|
66
|
+
if File.exist?(path)
|
67
|
+
File.read(path)
|
68
|
+
else
|
69
|
+
puts "File '#{path}' does not exist"
|
70
|
+
exit
|
71
|
+
end
|
72
|
+
end
|
46
73
|
|
47
|
-
|
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
|
48
80
|
|
49
|
-
if params[:format] == 'xml'
|
50
81
|
if params[:output]
|
51
|
-
|
52
|
-
|
82
|
+
dir = File.expand_path(params[:output], Dir.pwd)
|
83
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
53
84
|
|
54
|
-
|
55
|
-
File.
|
85
|
+
models.each do |name, model|
|
86
|
+
output_path = File.join(dir, "#{name}.rb")
|
87
|
+
File.write(output_path, model)
|
56
88
|
end
|
57
89
|
else
|
58
|
-
|
59
|
-
|
60
|
-
output = schemas.map do |name, xml|
|
61
|
-
"<!-- #{name} -->\n#{xml}\n"
|
90
|
+
output = models.map do |name, model|
|
91
|
+
"# --- #{name}.rb ---\n#{model}\n"
|
62
92
|
end.join("\n")
|
63
93
|
|
64
94
|
puts output
|
65
95
|
end
|
66
96
|
else
|
67
|
-
|
97
|
+
unless params[:input]
|
98
|
+
puts 'Input file is required: shaleb -i model.rb -r MyClass'
|
99
|
+
exit
|
100
|
+
end
|
68
101
|
|
69
|
-
|
70
|
-
|
71
|
-
|
102
|
+
input_path = File.expand_path(params[:input][0], Dir.pwd)
|
103
|
+
|
104
|
+
unless File.exist?(input_path)
|
105
|
+
puts "File '#{input_path}' does not exist"
|
106
|
+
exit
|
107
|
+
end
|
108
|
+
|
109
|
+
unless params[:root]
|
110
|
+
puts 'Model class is required: shaleb -i model.rb -r MyClass'
|
111
|
+
exit
|
112
|
+
end
|
113
|
+
|
114
|
+
require input_path
|
115
|
+
|
116
|
+
klass = Object.const_get(params[:root])
|
117
|
+
|
118
|
+
if params[:format] == 'xml'
|
119
|
+
load_xml_parser
|
120
|
+
|
121
|
+
if params[:output]
|
122
|
+
base_name = File.basename(params[:output], File.extname(params[:output]))
|
123
|
+
schemas = Shale::Schema.to_xml(klass, base_name, pretty: params[:pretty])
|
124
|
+
|
125
|
+
schemas.map do |name, xml|
|
126
|
+
File.write(File.expand_path(name, Dir.pwd), xml)
|
127
|
+
end
|
128
|
+
else
|
129
|
+
schemas = Shale::Schema.to_xml(klass, pretty: params[:pretty])
|
130
|
+
|
131
|
+
output = schemas.map do |name, xml|
|
132
|
+
"<!-- #{name} -->\n#{xml}\n"
|
133
|
+
end.join("\n")
|
134
|
+
|
135
|
+
puts output
|
136
|
+
end
|
72
137
|
else
|
73
|
-
|
138
|
+
schema = Shale::Schema.to_json(klass, pretty: params[:pretty])
|
139
|
+
|
140
|
+
if params[:output]
|
141
|
+
output_path = File.expand_path(params[:output], Dir.pwd)
|
142
|
+
File.write(output_path, schema)
|
143
|
+
else
|
144
|
+
puts schema
|
145
|
+
end
|
74
146
|
end
|
75
147
|
end
|
@@ -0,0 +1,97 @@
|
|
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
|
+
# Create CDATA node and add it to parent
|
45
|
+
#
|
46
|
+
# @param [String] text
|
47
|
+
# @param [::Nokogiri::XML::Element] parent
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
def create_cdata(text, parent)
|
51
|
+
parent.add_child(::Nokogiri::XML::CDATA.new(@doc, text))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Add XML namespace to document
|
55
|
+
#
|
56
|
+
# @param [String] prefix
|
57
|
+
# @param [String] namespace
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
def add_namespace(prefix, namespace)
|
61
|
+
@namespaces[prefix] = namespace if prefix && namespace
|
62
|
+
end
|
63
|
+
|
64
|
+
# Add attribute to Nokogiri element
|
65
|
+
#
|
66
|
+
# @param [::Nokogiri::XML::Element] element Nokogiri element
|
67
|
+
# @param [String] name Name of the XML attribute
|
68
|
+
# @param [String] value Value of the XML attribute
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
def add_attribute(element, name, value)
|
72
|
+
element[name] = value
|
73
|
+
end
|
74
|
+
|
75
|
+
# Add child element to Nokogiri element
|
76
|
+
#
|
77
|
+
# @param [::Nokogiri::XML::Element] element Nokogiri parent element
|
78
|
+
# @param [::Nokogiri::XML::Element] child Nokogiri child element
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
def add_element(element, child)
|
82
|
+
element.add_child(child)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Add text node to Nokogiri element
|
86
|
+
#
|
87
|
+
# @param [::Nokogiri::XML::Element] element Nokogiri element
|
88
|
+
# @param [String] text Text to add
|
89
|
+
#
|
90
|
+
# @api private
|
91
|
+
def add_text(element, text)
|
92
|
+
element.content = text
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
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 { |e| e.text? || e.cdata? }
|
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
|
-
# @
|
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,90 @@
|
|
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
|
+
# Create CDATA node and add it to parent
|
36
|
+
#
|
37
|
+
# @param [String] text
|
38
|
+
# @param [::Ox::Element] parent
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
def create_cdata(text, parent)
|
42
|
+
parent << ::Ox::CData.new(text)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Add XML namespace to document
|
46
|
+
#
|
47
|
+
# Ox doesn't support XML namespaces so this method does nothing.
|
48
|
+
#
|
49
|
+
# @param [String] prefix
|
50
|
+
# @param [String] namespace
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
def add_namespace(prefix, namespace)
|
54
|
+
# :noop:
|
55
|
+
end
|
56
|
+
|
57
|
+
# Add attribute to Ox element
|
58
|
+
#
|
59
|
+
# @param [::Ox::Element] element Ox element
|
60
|
+
# @param [String] name Name of the XML attribute
|
61
|
+
# @param [String] value Value of the XML attribute
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
def add_attribute(element, name, value)
|
65
|
+
element[name] = value
|
66
|
+
end
|
67
|
+
|
68
|
+
# Add child element to Ox element
|
69
|
+
#
|
70
|
+
# @param [::Ox::Element] element Ox parent element
|
71
|
+
# @param [::Ox::Element] child Ox child element
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def add_element(element, child)
|
75
|
+
element << child
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add text node to Ox element
|
79
|
+
#
|
80
|
+
# @param [::Ox::Element] element Ox element
|
81
|
+
# @param [String] text Text to add
|
82
|
+
#
|
83
|
+
# @api private
|
84
|
+
def add_text(element, text)
|
85
|
+
element << text
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|