multi_xml 0.6.0 → 0.9.1
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 +5 -5
- data/.mutant.yml +21 -0
- data/.rspec +2 -0
- data/.rubocop.yml +65 -0
- data/CHANGELOG.md +62 -0
- data/Gemfile +26 -0
- data/LICENSE.md +1 -1
- data/README.md +181 -57
- data/Rakefile +68 -0
- data/Steepfile +29 -0
- data/benchmark/overall_parser_benchmark.rb +5 -0
- data/benchmark.rb +1002 -0
- data/lib/multi_xml/concurrency.rb +31 -0
- data/lib/multi_xml/constants.rb +179 -0
- data/lib/multi_xml/deprecated.rb +35 -0
- data/lib/multi_xml/errors.rb +147 -0
- data/lib/multi_xml/file_like.rb +62 -0
- data/lib/multi_xml/helpers.rb +228 -0
- data/lib/multi_xml/options.rb +63 -0
- data/lib/multi_xml/options_normalization.rb +40 -0
- data/lib/multi_xml/parse_support.rb +113 -0
- data/lib/multi_xml/parser.rb +47 -0
- data/lib/multi_xml/parser_resolution.rb +150 -0
- data/lib/multi_xml/parsers/dom_parser.rb +190 -0
- data/lib/multi_xml/parsers/libxml.rb +57 -17
- data/lib/multi_xml/parsers/libxml_sax.rb +188 -0
- data/lib/multi_xml/parsers/nokogiri.rb +60 -19
- data/lib/multi_xml/parsers/nokogiri_sax.rb +130 -0
- data/lib/multi_xml/parsers/oga.rb +116 -49
- data/lib/multi_xml/parsers/ox.rb +191 -66
- data/lib/multi_xml/parsers/rexml.rb +169 -75
- data/lib/multi_xml/parsers/sax_handler.rb +169 -0
- data/lib/multi_xml/version.rb +6 -44
- data/lib/multi_xml.rb +187 -284
- data/sig/multi_xml.rbs +304 -0
- metadata +55 -23
- data/lib/multi_xml/parsers/libxml2_parser.rb +0 -72
- data/multi_xml.gemspec +0 -19
data/sig/multi_xml.rbs
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Type signatures for MultiXML
|
|
2
|
+
|
|
3
|
+
# Recursive type alias for parsed XML values
|
|
4
|
+
# XML parsing produces nested structures of hashes, arrays, and primitive values
|
|
5
|
+
type MultiXML::xmlValue = String
|
|
6
|
+
| Integer
|
|
7
|
+
| Float
|
|
8
|
+
| bool
|
|
9
|
+
| Symbol
|
|
10
|
+
| Time
|
|
11
|
+
| Date
|
|
12
|
+
| BigDecimal
|
|
13
|
+
| StringIO
|
|
14
|
+
| nil
|
|
15
|
+
| Array[MultiXML::xmlValue]
|
|
16
|
+
| Hash[String, MultiXML::xmlValue]
|
|
17
|
+
| Hash[Symbol, MultiXML::xmlValue]
|
|
18
|
+
|
|
19
|
+
# Type for hash with string keys used internally during parsing
|
|
20
|
+
type MultiXML::xmlHash = Hash[String, MultiXML::xmlValue]
|
|
21
|
+
|
|
22
|
+
# Interface for parser modules
|
|
23
|
+
interface MultiXML::_Parser
|
|
24
|
+
def parse: ((IO | StringIO) io) -> MultiXML::xmlHash?
|
|
25
|
+
| ((IO | StringIO) io, ?namespaces: Symbol) -> MultiXML::xmlHash?
|
|
26
|
+
def parse_error: () -> singleton(Exception)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module MultiXML
|
|
30
|
+
extend Options
|
|
31
|
+
|
|
32
|
+
type parse_options_input = Hash[Symbol, untyped] | ^() -> Hash[Symbol, untyped] | ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
33
|
+
|
|
34
|
+
VERSION: Gem::Version
|
|
35
|
+
|
|
36
|
+
TEXT_CONTENT_KEY: String
|
|
37
|
+
|
|
38
|
+
RUBY_TYPE_TO_XML: Hash[String, String]
|
|
39
|
+
|
|
40
|
+
DISALLOWED_TYPES: Array[String]
|
|
41
|
+
|
|
42
|
+
FALSE_BOOLEAN_VALUES: Set[String]
|
|
43
|
+
|
|
44
|
+
NAMESPACE_MODES: Array[Symbol]
|
|
45
|
+
|
|
46
|
+
DEFAULT_OPTIONS: Hash[Symbol, bool | Array[String] | Symbol]
|
|
47
|
+
|
|
48
|
+
# Array of [library_name, parser_symbol] pairs
|
|
49
|
+
PARSER_PREFERENCE: Array[Array[String | Symbol]]
|
|
50
|
+
|
|
51
|
+
PARSE_DATETIME: ^(String) -> Time
|
|
52
|
+
|
|
53
|
+
ISO_WEEK_DATE: Regexp
|
|
54
|
+
|
|
55
|
+
# Lambda for creating file-like StringIO from base64 content
|
|
56
|
+
# Uses untyped for content because unpack1 returns various types
|
|
57
|
+
# Uses untyped for entity because hash values are xmlValue but we access specific String keys
|
|
58
|
+
FILE_CONVERTER: ^(untyped, untyped) -> StringIO
|
|
59
|
+
|
|
60
|
+
# Type converters keyed by XML type attribute string
|
|
61
|
+
# Uses untyped key because hash["type"] returns xmlValue, and Hash#[] with non-String returns nil
|
|
62
|
+
TYPE_CONVERTERS: Hash[untyped, Proc | Method]
|
|
63
|
+
|
|
64
|
+
DEPRECATION_WARNINGS_SHOWN: Set[Symbol]
|
|
65
|
+
|
|
66
|
+
self.@parser: Module
|
|
67
|
+
|
|
68
|
+
extend Helpers
|
|
69
|
+
|
|
70
|
+
module Concurrency
|
|
71
|
+
MUTEXES: Hash[Symbol, Thread::Mutex]
|
|
72
|
+
|
|
73
|
+
def self.synchronize: [T] (Symbol name) { () -> T } -> T
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
module Options
|
|
77
|
+
EMPTY_OPTIONS: Hash[Symbol, untyped]
|
|
78
|
+
|
|
79
|
+
def parse_options=: (parse_options_input options) -> parse_options_input
|
|
80
|
+
|
|
81
|
+
def parse_options: (*untyped args) -> Hash[Symbol, untyped]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
module Parser
|
|
85
|
+
def parse_error: () -> Class
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
module ParserResolution
|
|
89
|
+
LOADED_PARSER_CHECKS: Hash[Symbol, Symbol]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
module ParseSupport
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Emit a deprecation warning at most once per process
|
|
96
|
+
def self.warn_deprecation_once: (Symbol key, String message) -> void
|
|
97
|
+
|
|
98
|
+
# Public API: Get the current XML parser module
|
|
99
|
+
def self.parser: () -> Module
|
|
100
|
+
|
|
101
|
+
# Public API: Set the XML parser to use
|
|
102
|
+
def self.parser=: (Symbol | String | Module new_parser) -> Module
|
|
103
|
+
|
|
104
|
+
# Public API: Parse XML into a Ruby Hash
|
|
105
|
+
# Uses untyped for options because values vary by key (:parser, :symbolize_keys, :disallowed_types, :typecast_xml_value)
|
|
106
|
+
def self.parse: (String | StringIO xml, ?Hash[Symbol, untyped] options) -> xmlHash
|
|
107
|
+
|
|
108
|
+
def self.parse_iso_week_datetime: (String string) -> Time
|
|
109
|
+
# Public API: Execute a block with a temporarily-swapped parser
|
|
110
|
+
def self.with_parser: [T] (Symbol | String | Module new_parser) { () -> T } -> T
|
|
111
|
+
# Deprecated alias for `parse`
|
|
112
|
+
def self.load: (String | StringIO xml, ?Hash[Symbol, untyped] options) -> xmlHash
|
|
113
|
+
private
|
|
114
|
+
|
|
115
|
+
# Resolve a parser specification (Symbol, String, or Module) to a parser
|
|
116
|
+
def self.resolve_parser: (Symbol | String | Module spec) -> Module
|
|
117
|
+
|
|
118
|
+
# Validate that a parser satisfies the contract
|
|
119
|
+
def self.validate_parser!: (Module parser) -> Module
|
|
120
|
+
|
|
121
|
+
# Load a parser module by name
|
|
122
|
+
def self.load_parser: (Symbol | String name) -> Module
|
|
123
|
+
|
|
124
|
+
# Convert snake_case to CamelCase
|
|
125
|
+
def self.camelize: (String name) -> String
|
|
126
|
+
|
|
127
|
+
# Detect the best available parser
|
|
128
|
+
def self.detect_parser: () -> (Symbol | String)
|
|
129
|
+
|
|
130
|
+
# Find an already-loaded parser library
|
|
131
|
+
def self.find_loaded_parser: () -> Symbol?
|
|
132
|
+
|
|
133
|
+
# Try to find an available parser by requiring libraries
|
|
134
|
+
def self.find_available_parser: () -> (String | Symbol | nil)
|
|
135
|
+
|
|
136
|
+
# Attempt to require a library, returning success/failure
|
|
137
|
+
# Kernel#require accepts String; library may be Symbol from PARSER_PREFERENCE (coerced at runtime)
|
|
138
|
+
def self.try_require: (untyped library) -> bool
|
|
139
|
+
|
|
140
|
+
# Raise NoParserError - never returns
|
|
141
|
+
def self.raise_no_parser_error: () -> bot
|
|
142
|
+
|
|
143
|
+
# Convert String to StringIO, pass through IO-like objects
|
|
144
|
+
# Uses respond_to?(:read) duck typing - returns input unchanged if IO-like
|
|
145
|
+
def self.normalize_input: (String | StringIO xml) -> untyped
|
|
146
|
+
|
|
147
|
+
# Parse with error handling and key normalization
|
|
148
|
+
# xml_parser implements _Parser interface; original_input uses respond_to? duck typing
|
|
149
|
+
def self.parse_with_error_handling: ((IO | StringIO) io, untyped original_input, untyped xml_parser, Symbol namespaces) -> xmlHash
|
|
150
|
+
|
|
151
|
+
# Dispatch to parsers that may or may not accept `namespaces:`
|
|
152
|
+
def self.parse_with_namespaces_compatibility: ((IO | StringIO) io, untyped xml_parser, Symbol namespaces) -> xmlHash?
|
|
153
|
+
|
|
154
|
+
# Validate the :namespaces option value
|
|
155
|
+
def self.validate_namespaces_mode: (untyped mode) -> Symbol
|
|
156
|
+
|
|
157
|
+
# Resolve which parser this parse call should use, honoring the :parser option
|
|
158
|
+
def self.resolve_parse_parser: (Hash[Symbol, untyped] options) -> Module
|
|
159
|
+
|
|
160
|
+
# Check whether a parser accepts the `namespaces:` keyword
|
|
161
|
+
def self.parser_supports_namespaces_keyword?: (untyped xml_parser) -> bool
|
|
162
|
+
|
|
163
|
+
# Apply typecasting and key-symbolization as configured
|
|
164
|
+
def self.apply_postprocessing: (xmlHash result, Hash[Symbol, untyped] options) -> xmlHash
|
|
165
|
+
|
|
166
|
+
module OptionsNormalization
|
|
167
|
+
# Translate the deprecated :symbolize_keys option to :symbolize_names
|
|
168
|
+
def self.normalize_symbolize_option: (Hash[Symbol, untyped] options) -> Hash[Symbol, untyped]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Define a deprecated alias that delegates to a new method name
|
|
172
|
+
def self.deprecate_alias: (Symbol name, Symbol replacement) -> Symbol
|
|
173
|
+
|
|
174
|
+
module Helpers
|
|
175
|
+
# Recursively convert all hash keys to symbols
|
|
176
|
+
# Uses case/when type dispatch - Steep can't track flow narrowing
|
|
177
|
+
def self?.symbolize_keys: (untyped data) -> untyped
|
|
178
|
+
|
|
179
|
+
# Recursively convert dashes in hash keys to underscores
|
|
180
|
+
# Uses case/when type dispatch - Steep can't track flow narrowing
|
|
181
|
+
def self?.undasherize_keys: (untyped data) -> untyped
|
|
182
|
+
|
|
183
|
+
# Recursively typecast XML values based on type attributes
|
|
184
|
+
# Uses case/when type dispatch - Steep can't track flow narrowing
|
|
185
|
+
def self?.typecast_xml_value: (untyped value, ?Array[String] disallowed_types) -> xmlValue
|
|
186
|
+
|
|
187
|
+
# Typecast array elements and unwrap single-element arrays
|
|
188
|
+
def self?.typecast_array: (Array[xmlValue] array, Array[String] disallowed_types) -> xmlValue
|
|
189
|
+
|
|
190
|
+
# Typecast a hash based on its type attribute
|
|
191
|
+
def self?.typecast_hash: (xmlHash hash, Array[String] disallowed_types) -> xmlValue
|
|
192
|
+
|
|
193
|
+
# Check if a type is in the disallowed list
|
|
194
|
+
# Uses is_a?(Hash) guard then include? - Steep can't narrow xmlValue to String
|
|
195
|
+
def self?.disallowed_type?: (untyped type, Array[String] disallowed_types) -> boolish
|
|
196
|
+
|
|
197
|
+
# Convert a hash based on its type and content
|
|
198
|
+
def self?.convert_hash: (xmlHash hash, xmlValue type, Array[String] disallowed_types) -> xmlValue
|
|
199
|
+
|
|
200
|
+
# Typecast all child values in a hash
|
|
201
|
+
def self?.typecast_children: (xmlHash hash, Array[String] disallowed_types) -> (xmlHash | StringIO)
|
|
202
|
+
|
|
203
|
+
# Extract array entries from element with type="array"
|
|
204
|
+
def self?.extract_array_entries: (xmlHash hash, Array[String] disallowed_types) -> Array[xmlValue]
|
|
205
|
+
|
|
206
|
+
# Find array or hash entries in a hash, excluding the type key
|
|
207
|
+
# Returns xmlValue subset (Array or Hash) - uses is_a? that Steep can't narrow
|
|
208
|
+
def self?.find_array_entries: (xmlHash hash) -> untyped
|
|
209
|
+
|
|
210
|
+
# Wrap hash in array if needed and typecast all entries
|
|
211
|
+
def self?.wrap_and_typecast: (Array[xmlValue] | xmlHash entries, Array[String] disallowed_types) -> Array[xmlValue]
|
|
212
|
+
|
|
213
|
+
# Convert text content using type converters
|
|
214
|
+
# hash["type"] is xmlValue, used as Hash key - Steep requires String
|
|
215
|
+
def self?.convert_text_content: (xmlHash hash) -> xmlValue
|
|
216
|
+
|
|
217
|
+
# Unwrap value if hash has no other significant keys
|
|
218
|
+
def self?.unwrap_if_simple: (xmlHash hash, xmlValue value) -> (xmlValue | xmlHash)
|
|
219
|
+
|
|
220
|
+
# Check if a hash represents an empty value
|
|
221
|
+
def self?.empty_value?: (xmlHash hash, xmlValue type) -> bool
|
|
222
|
+
|
|
223
|
+
private
|
|
224
|
+
|
|
225
|
+
# Recursively transform hash keys using a block
|
|
226
|
+
# Block receives key (String) and returns transformed key
|
|
227
|
+
# Uses untyped because &:to_sym Proc type narrowing not supported by Steep
|
|
228
|
+
def self?.transform_keys: (untyped data) { (untyped) -> untyped } -> untyped
|
|
229
|
+
|
|
230
|
+
# Unwrap a file object from the result hash if present
|
|
231
|
+
def self?.unwrap_file_if_present: (xmlHash result) -> (xmlHash | StringIO)
|
|
232
|
+
|
|
233
|
+
# Apply a type converter to content
|
|
234
|
+
# Content is xmlValue (from hash.fetch) but typically String in practice
|
|
235
|
+
def self?.apply_converter: (xmlHash hash, untyped content, Proc | Method converter) -> xmlValue
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
module FileLike
|
|
239
|
+
DEFAULT_FILENAME: String
|
|
240
|
+
|
|
241
|
+
DEFAULT_CONTENT_TYPE: String
|
|
242
|
+
|
|
243
|
+
@original_filename: String?
|
|
244
|
+
|
|
245
|
+
@content_type: String?
|
|
246
|
+
|
|
247
|
+
attr_writer original_filename: String?
|
|
248
|
+
|
|
249
|
+
attr_writer content_type: String?
|
|
250
|
+
|
|
251
|
+
def original_filename: () -> String
|
|
252
|
+
|
|
253
|
+
def content_type: () -> String
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Represents a StringIO that has been extended with FileLike
|
|
257
|
+
# Used for file type conversions in XML parsing
|
|
258
|
+
class FileIO < StringIO
|
|
259
|
+
include FileLike
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
class ParseError < StandardError
|
|
263
|
+
@xml: String?
|
|
264
|
+
|
|
265
|
+
@cause: Exception?
|
|
266
|
+
|
|
267
|
+
attr_reader xml: String?
|
|
268
|
+
|
|
269
|
+
attr_reader cause: Exception?
|
|
270
|
+
|
|
271
|
+
# Message can be String (normal) or Exception (from parser errors), or nil for default
|
|
272
|
+
def initialize: (?(String | Exception | nil) message, ?xml: String?, ?cause: Exception?) -> void
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
class NoParserError < StandardError
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
class ParserLoadError < ArgumentError
|
|
279
|
+
def initialize: (?(String | nil) message, ?cause: Exception?) -> void
|
|
280
|
+
|
|
281
|
+
def self.build: (Exception original_exception) -> ParserLoadError
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
class DisallowedTypeError < StandardError
|
|
285
|
+
@type: String
|
|
286
|
+
|
|
287
|
+
attr_reader type: String
|
|
288
|
+
|
|
289
|
+
def initialize: (String type) -> void
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Parsers module - parser implementations depend on optional external gems
|
|
293
|
+
module Parsers
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Backward-compatible alias for the legacy MultiXml constant name
|
|
298
|
+
module MultiXml
|
|
299
|
+
def self.method_missing: (Symbol name, *untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
|
|
300
|
+
|
|
301
|
+
def self.respond_to_missing?: ((Symbol | String) name, bool include_private) -> bool
|
|
302
|
+
|
|
303
|
+
def self.const_missing: (Symbol name) -> untyped
|
|
304
|
+
end
|
metadata
CHANGED
|
@@ -1,54 +1,88 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: multi_xml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
- Erik
|
|
8
|
-
|
|
9
|
-
bindir: bin
|
|
7
|
+
- Erik Berlin
|
|
8
|
+
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
13
|
+
name: bigdecimal
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - "
|
|
16
|
+
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1
|
|
20
|
-
|
|
18
|
+
version: '3.1'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '5'
|
|
22
|
+
type: :runtime
|
|
21
23
|
prerelease: false
|
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
25
|
requirements:
|
|
24
|
-
- - "
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '3.1'
|
|
29
|
+
- - "<"
|
|
25
30
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
version: '5'
|
|
32
|
+
email:
|
|
33
|
+
- sferik@gmail.com
|
|
29
34
|
executables: []
|
|
30
35
|
extensions: []
|
|
31
36
|
extra_rdoc_files: []
|
|
32
37
|
files:
|
|
38
|
+
- ".mutant.yml"
|
|
39
|
+
- ".rspec"
|
|
40
|
+
- ".rubocop.yml"
|
|
33
41
|
- ".yardopts"
|
|
34
42
|
- CHANGELOG.md
|
|
35
43
|
- CONTRIBUTING.md
|
|
44
|
+
- Gemfile
|
|
36
45
|
- LICENSE.md
|
|
37
46
|
- README.md
|
|
47
|
+
- Rakefile
|
|
48
|
+
- Steepfile
|
|
49
|
+
- benchmark.rb
|
|
50
|
+
- benchmark/overall_parser_benchmark.rb
|
|
38
51
|
- lib/multi_xml.rb
|
|
52
|
+
- lib/multi_xml/concurrency.rb
|
|
53
|
+
- lib/multi_xml/constants.rb
|
|
54
|
+
- lib/multi_xml/deprecated.rb
|
|
55
|
+
- lib/multi_xml/errors.rb
|
|
56
|
+
- lib/multi_xml/file_like.rb
|
|
57
|
+
- lib/multi_xml/helpers.rb
|
|
58
|
+
- lib/multi_xml/options.rb
|
|
59
|
+
- lib/multi_xml/options_normalization.rb
|
|
60
|
+
- lib/multi_xml/parse_support.rb
|
|
61
|
+
- lib/multi_xml/parser.rb
|
|
62
|
+
- lib/multi_xml/parser_resolution.rb
|
|
63
|
+
- lib/multi_xml/parsers/dom_parser.rb
|
|
39
64
|
- lib/multi_xml/parsers/libxml.rb
|
|
40
|
-
- lib/multi_xml/parsers/
|
|
65
|
+
- lib/multi_xml/parsers/libxml_sax.rb
|
|
41
66
|
- lib/multi_xml/parsers/nokogiri.rb
|
|
67
|
+
- lib/multi_xml/parsers/nokogiri_sax.rb
|
|
42
68
|
- lib/multi_xml/parsers/oga.rb
|
|
43
69
|
- lib/multi_xml/parsers/ox.rb
|
|
44
70
|
- lib/multi_xml/parsers/rexml.rb
|
|
71
|
+
- lib/multi_xml/parsers/sax_handler.rb
|
|
45
72
|
- lib/multi_xml/version.rb
|
|
46
|
-
- multi_xml.
|
|
73
|
+
- sig/multi_xml.rbs
|
|
47
74
|
homepage: https://github.com/sferik/multi_xml
|
|
48
75
|
licenses:
|
|
49
76
|
- MIT
|
|
50
|
-
metadata:
|
|
51
|
-
|
|
77
|
+
metadata:
|
|
78
|
+
allowed_push_host: https://rubygems.org
|
|
79
|
+
bug_tracker_uri: https://github.com/sferik/multi_xml/issues
|
|
80
|
+
changelog_uri: https://github.com/sferik/multi_xml/blob/master/CHANGELOG.md
|
|
81
|
+
documentation_uri: https://rubydoc.info/gems/multi_xml/
|
|
82
|
+
funding_uri: https://github.com/sponsors/sferik
|
|
83
|
+
homepage_uri: https://github.com/sferik/multi_xml
|
|
84
|
+
rubygems_mfa_required: 'true'
|
|
85
|
+
source_code_uri: https://github.com/sferik/multi_xml
|
|
52
86
|
rdoc_options: []
|
|
53
87
|
require_paths:
|
|
54
88
|
- lib
|
|
@@ -56,16 +90,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
56
90
|
requirements:
|
|
57
91
|
- - ">="
|
|
58
92
|
- !ruby/object:Gem::Version
|
|
59
|
-
version: '
|
|
93
|
+
version: '3.2'
|
|
60
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
95
|
requirements:
|
|
62
96
|
- - ">="
|
|
63
97
|
- !ruby/object:Gem::Version
|
|
64
|
-
version:
|
|
98
|
+
version: '0'
|
|
65
99
|
requirements: []
|
|
66
|
-
|
|
67
|
-
rubygems_version: 2.5.2
|
|
68
|
-
signing_key:
|
|
100
|
+
rubygems_version: 4.0.11
|
|
69
101
|
specification_version: 4
|
|
70
|
-
summary:
|
|
102
|
+
summary: Provides swappable XML backends utilizing LibXML, Nokogiri, Ox, or REXML.
|
|
71
103
|
test_files: []
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
module MultiXml
|
|
2
|
-
module Parsers
|
|
3
|
-
module Libxml2Parser #:nodoc:
|
|
4
|
-
# Convert XML document to hash
|
|
5
|
-
#
|
|
6
|
-
# node::
|
|
7
|
-
# The XML node object to convert to a hash.
|
|
8
|
-
#
|
|
9
|
-
# hash::
|
|
10
|
-
# Hash to merge the converted element into.
|
|
11
|
-
def node_to_hash(node, hash = {}) # rubocop:disable AbcSize, CyclomaticComplexity, MethodLength, PerceivedComplexity
|
|
12
|
-
node_hash = {MultiXml::CONTENT_ROOT => ''}
|
|
13
|
-
|
|
14
|
-
name = node_name(node)
|
|
15
|
-
|
|
16
|
-
# Insert node hash into parent hash correctly.
|
|
17
|
-
case hash[name]
|
|
18
|
-
when Array
|
|
19
|
-
hash[name] << node_hash
|
|
20
|
-
when Hash
|
|
21
|
-
hash[name] = [hash[name], node_hash]
|
|
22
|
-
when NilClass
|
|
23
|
-
hash[name] = node_hash
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Handle child elements
|
|
27
|
-
each_child(node) do |c|
|
|
28
|
-
if c.element?
|
|
29
|
-
node_to_hash(c, node_hash)
|
|
30
|
-
elsif c.text? || c.cdata?
|
|
31
|
-
node_hash[MultiXml::CONTENT_ROOT] << c.content
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Remove content node if it is empty
|
|
36
|
-
if node_hash[MultiXml::CONTENT_ROOT].strip.empty?
|
|
37
|
-
node_hash.delete(MultiXml::CONTENT_ROOT)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Handle attributes
|
|
41
|
-
each_attr(node) do |a|
|
|
42
|
-
key = node_name(a)
|
|
43
|
-
v = node_hash[key]
|
|
44
|
-
node_hash[key] = (v ? [a.value, v] : a.value)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
hash
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Parse an XML Document IO into a simple hash.
|
|
51
|
-
# xml::
|
|
52
|
-
# XML Document IO to parse
|
|
53
|
-
def parse(_)
|
|
54
|
-
raise(NotImplementedError.new("inheritor should define #{__method__}"))
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
def each_child(*)
|
|
60
|
-
raise(NotImplementedError.new("inheritor should define #{__method__}"))
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def each_attr(*)
|
|
64
|
-
raise(NotImplementedError.new("inheritor should define #{__method__}"))
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def node_name(*)
|
|
68
|
-
raise(NotImplementedError.new("inheritor should define #{__method__}"))
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
data/multi_xml.gemspec
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
-
require 'multi_xml/version'
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.add_development_dependency 'bundler', '~> 1.0'
|
|
8
|
-
spec.author = 'Erik Michaels-Ober'
|
|
9
|
-
spec.description = 'Provides swappable XML backends utilizing LibXML, Nokogiri, Ox, or REXML.'
|
|
10
|
-
spec.email = 'sferik@gmail.com'
|
|
11
|
-
spec.files = %w(.yardopts CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md multi_xml.gemspec) + Dir['lib/**/*.rb']
|
|
12
|
-
spec.homepage = 'https://github.com/sferik/multi_xml'
|
|
13
|
-
spec.licenses = ['MIT']
|
|
14
|
-
spec.name = 'multi_xml'
|
|
15
|
-
spec.require_paths = ['lib']
|
|
16
|
-
spec.required_rubygems_version = '>= 1.3.5'
|
|
17
|
-
spec.summary = 'A generic swappable back-end for XML parsing'
|
|
18
|
-
spec.version = MultiXml::Version
|
|
19
|
-
end
|