multi_xml 0.5.5 → 0.7.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 +7 -0
- data/.rspec +2 -0
- data/.rubocop.yml +54 -0
- data/CHANGELOG.md +12 -0
- data/CONTRIBUTING.md +5 -3
- data/Gemfile +21 -0
- data/LICENSE.md +1 -1
- data/README.md +12 -35
- data/Rakefile +27 -15
- data/lib/multi_xml/parsers/libxml.rb +12 -9
- data/lib/multi_xml/parsers/libxml2_parser.rb +21 -25
- data/lib/multi_xml/parsers/nokogiri.rb +14 -10
- data/lib/multi_xml/parsers/oga.rb +71 -0
- data/lib/multi_xml/parsers/ox.rb +16 -22
- data/lib/multi_xml/parsers/rexml.rb +16 -16
- data/lib/multi_xml/version.rb +1 -1
- data/lib/multi_xml.rb +127 -112
- metadata +37 -69
- data/multi_xml.gemspec +0 -24
- data/spec/helper.rb +0 -17
- data/spec/multi_xml_spec.rb +0 -43
- data/spec/parser_shared_example.rb +0 -694
- data/spec/speed.rb +0 -63
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7bebe7a08139024835279d7ffc78a7d86d0cb9a5ff59787068e044f7c75dc6f9
|
4
|
+
data.tar.gz: a2f579d2e18a266fe9573174de87ac960fcf867081705a2a6feb458bfa573225
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: be4ffea0dd836f1d1d1baf73ffded7de5a79fdc53a5b039b5e7fd0a615a786ca08dc0a7bbf5561266cdade44a9cb3c2382fe6e35a54599876f77ec74ec937d42
|
7
|
+
data.tar.gz: d579ab46f0122a1011704e397062b5d9e648eeaae85a8baa30ac8eda7f3d1cdaa9e57fe1922e6e3e7ac608ef9607033c1547773dbb2eb1fe6785176a3471764d
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-performance
|
3
|
+
- rubocop-rake
|
4
|
+
- rubocop-rspec
|
5
|
+
- standard
|
6
|
+
- standard-performance
|
7
|
+
|
8
|
+
AllCops:
|
9
|
+
NewCops: enable
|
10
|
+
TargetRubyVersion: 3.1
|
11
|
+
|
12
|
+
Layout/ArgumentAlignment:
|
13
|
+
EnforcedStyle: with_fixed_indentation
|
14
|
+
IndentationWidth: 2
|
15
|
+
|
16
|
+
Layout/CaseIndentation:
|
17
|
+
EnforcedStyle: end
|
18
|
+
|
19
|
+
Layout/EndAlignment:
|
20
|
+
EnforcedStyleAlignWith: start_of_line
|
21
|
+
|
22
|
+
Layout/LineLength:
|
23
|
+
Max: 140
|
24
|
+
|
25
|
+
Layout/ParameterAlignment:
|
26
|
+
EnforcedStyle: with_fixed_indentation
|
27
|
+
IndentationWidth: 2
|
28
|
+
|
29
|
+
Layout/SpaceInsideHashLiteralBraces:
|
30
|
+
EnforcedStyle: no_space
|
31
|
+
|
32
|
+
Metrics/ParameterLists:
|
33
|
+
CountKeywordArgs: false
|
34
|
+
|
35
|
+
Style/Alias:
|
36
|
+
EnforcedStyle: prefer_alias_method
|
37
|
+
|
38
|
+
Style/Documentation:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/FrozenStringLiteralComment:
|
42
|
+
EnforcedStyle: never
|
43
|
+
|
44
|
+
Style/OpenStructUse:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
Style/StringLiterals:
|
48
|
+
EnforcedStyle: double_quotes
|
49
|
+
|
50
|
+
Style/StringLiteralsInInterpolation:
|
51
|
+
EnforcedStyle: double_quotes
|
52
|
+
|
53
|
+
Style/TernaryParentheses:
|
54
|
+
EnforcedStyle: require_parentheses
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
0.7.0
|
2
|
+
-----
|
3
|
+
* [Add support for Ruby 3.3](https://github.com/sferik/multi_xml/pull/67)
|
4
|
+
* [Drop support for Ruby 3.0](https://github.com/sferik/multi_xml/commit/eec72c56307fede3a93f1a61553587cb278b0c8a) [and](https://github.com/sferik/multi_xml/commit/6a6dec80a36c30774a5525b45f71d346fb561e69) [earlier](https://github.com/sferik/multi_xml/commit/e7dad37a0a0be8383a26ffe515c575b5b4d04588)
|
5
|
+
* [Don't mutate strings](https://github.com/sferik/multi_xml/commit/71be3fff4afb0277a7e1c47c5f1f4b6106a8eb45)
|
6
|
+
|
7
|
+
0.6.0
|
8
|
+
-----
|
9
|
+
* [Duplexed Streams](https://github.com/sferik/multi_xml/pull/45)
|
10
|
+
* [Support for Oga](https://github.com/sferik/multi_xml/pull/47)
|
11
|
+
* [Integer unification for Ruby 2.4](https://github.com/sferik/multi_xml/pull/54)
|
12
|
+
|
1
13
|
0.5.5
|
2
14
|
-----
|
3
15
|
* [Fix symbolize_keys function](https://github.com/sferik/multi_xml/commit/a4cae3aeb690999287cd30206399abaa5ce1ae81)
|
data/CONTRIBUTING.md
CHANGED
@@ -16,8 +16,10 @@ Here are some ways *you* can contribute:
|
|
16
16
|
* by refactoring code
|
17
17
|
* by resolving [issues][]
|
18
18
|
* by reviewing patches
|
19
|
+
* [financially][gittip]
|
19
20
|
|
20
21
|
[issues]: https://github.com/sferik/multi_xml/issues
|
22
|
+
[gittip]: https://www.gittip.com/sferik/
|
21
23
|
|
22
24
|
## Submitting an Issue
|
23
25
|
We use the [GitHub issue tracker][issues] to track bugs and features. Before
|
@@ -35,12 +37,12 @@ Ideally, a bug report should include a pull request with failing specs.
|
|
35
37
|
3. Add specs for your unimplemented feature or bug fix.
|
36
38
|
4. Run `bundle exec rake spec`. If your specs pass, return to step 3.
|
37
39
|
5. Implement your feature or bug fix.
|
38
|
-
6. Run `bundle exec rake
|
40
|
+
6. Run `bundle exec rake`. If your specs fail, return to step 5.
|
39
41
|
7. Run `open coverage/index.html`. If your changes are not completely covered
|
40
42
|
by your tests, return to step 3.
|
41
43
|
8. Add documentation for your feature or bug fix.
|
42
|
-
9. Run `bundle exec rake
|
43
|
-
back to step 8.
|
44
|
+
9. Run `bundle exec rake verify_measurements`. If your changes are not 100%
|
45
|
+
documented, go back to step 8.
|
44
46
|
10. Add, commit, and push your changes.
|
45
47
|
11. [Submit a pull request.][pr]
|
46
48
|
|
data/Gemfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem "libxml-ruby", require: nil, platforms: :ruby
|
4
|
+
gem "nokogiri", require: nil
|
5
|
+
gem "oga", ">= 2.3", require: nil
|
6
|
+
gem "ox", require: nil, platforms: :ruby
|
7
|
+
gem "rexml", require: nil
|
8
|
+
|
9
|
+
gem "rake", ">= 13.2.1"
|
10
|
+
gem "rspec", ">= 3.12"
|
11
|
+
gem "rubocop", ">= 1.62.1"
|
12
|
+
gem "rubocop-performance", ">= 1.20.2"
|
13
|
+
gem "rubocop-rake", ">= 0.6"
|
14
|
+
gem "rubocop-rspec", ">= 2.24"
|
15
|
+
gem "simplecov", ">= 0.22"
|
16
|
+
gem "standard", ">= 1.35.1"
|
17
|
+
gem "standard-performance", ">= 1.3.1"
|
18
|
+
gem "yard", ">= 0.9.36"
|
19
|
+
gem "yardstick", ">= 0.9.9"
|
20
|
+
|
21
|
+
gemspec
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -1,42 +1,16 @@
|
|
1
1
|
# MultiXML
|
2
2
|
|
3
|
-
[][gem]
|
4
|
-
[][travis]
|
5
|
-
[][gemnasium]
|
6
|
-
[][codeclimate]
|
7
|
-
[][coveralls]
|
8
|
-
|
9
|
-
[gem]: https://rubygems.org/gems/multi_xml
|
10
|
-
[travis]: http://travis-ci.org/sferik/multi_xml
|
11
|
-
[gemnasium]: https://gemnasium.com/sferik/multi_xml
|
12
|
-
[codeclimate]: https://codeclimate.com/github/sferik/multi_xml
|
13
|
-
[coveralls]: https://coveralls.io/r/sferik/multi_xml
|
14
|
-
|
15
3
|
A generic swappable back-end for XML parsing
|
16
4
|
|
17
5
|
## Installation
|
18
6
|
gem install multi_xml
|
19
7
|
|
20
|
-
To ensure the code you're installing hasn't been tampered with, it's
|
21
|
-
recommended that you verify the signature. To do this, you need to add my
|
22
|
-
public key as a trusted certificate (you only need to do this once):
|
23
|
-
|
24
|
-
gem cert --add <(curl -Ls https://raw.github.com/sferik/multi_xml/master/certs/sferik.pem)
|
25
|
-
|
26
|
-
Then, install the gem with the high security trust policy:
|
27
|
-
|
28
|
-
gem install multi_xml -P HighSecurity
|
29
|
-
|
30
8
|
## Documentation
|
31
9
|
[http://rdoc.info/gems/multi_xml][documentation]
|
32
10
|
|
33
11
|
[documentation]: http://rdoc.info/gems/multi_xml
|
34
12
|
|
35
13
|
## Usage Examples
|
36
|
-
Lots of Ruby libraries utilize XML parsing in some form, and everyone has their
|
37
|
-
favorite XML library. In order to best support multiple XML parsers and
|
38
|
-
libraries, `multi_xml` is a general-purpose swappable XML backend library. You
|
39
|
-
use it like so:
|
40
14
|
```ruby
|
41
15
|
require 'multi_xml'
|
42
16
|
|
@@ -55,25 +29,28 @@ MultiXml.parse('<tag>This is the contents</tag>') # Parsed using Nokogiri
|
|
55
29
|
MultiXml.parser = :rexml
|
56
30
|
MultiXml.parser = MultiXml::Parsers::Rexml # Same as above
|
57
31
|
MultiXml.parse('<tag>This is the contents</tag>') # Parsed using REXML
|
32
|
+
|
33
|
+
MultiXml.parser = :oga
|
34
|
+
MultiXml.parser = MultiXml::Parsers::Oga # Same as above
|
35
|
+
MultiXml.parse('<tag>This is the contents</tag>') # Parsed using Oga
|
58
36
|
```
|
59
37
|
The `parser` setter takes either a symbol or a class (to allow for custom XML
|
60
38
|
parsers) that responds to `.parse` at the class level.
|
61
39
|
|
62
40
|
MultiXML tries to have intelligent defaulting. That is, if you have any of the
|
63
|
-
supported parsers already loaded, it will
|
64
|
-
|
41
|
+
supported parsers already loaded, it will use them before attempting to load
|
42
|
+
a new one. When loading, libraries are ordered by speed: first Ox, then LibXML,
|
65
43
|
then Nokogiri, and finally REXML.
|
66
44
|
|
67
45
|
## Supported Ruby Versions
|
68
|
-
This library aims to support and is
|
46
|
+
This library aims to support and is tested against the following Ruby
|
69
47
|
implementations:
|
70
48
|
|
71
|
-
*
|
72
|
-
*
|
73
|
-
*
|
74
|
-
* Ruby 2.0.0
|
49
|
+
* 3.1
|
50
|
+
* 3.2
|
51
|
+
* 3.3
|
75
52
|
|
76
|
-
If something doesn't work on one of these
|
53
|
+
If something doesn't work on one of these versions, it's a bug.
|
77
54
|
|
78
55
|
This library may inadvertently work (or seem to work) on other Ruby
|
79
56
|
implementations, however support will only be provided for the versions listed
|
@@ -92,6 +69,6 @@ MultiXML was inspired by [MultiJSON][].
|
|
92
69
|
[multijson]: https://github.com/intridea/multi_json/
|
93
70
|
|
94
71
|
## Copyright
|
95
|
-
Copyright (c) 2010-
|
72
|
+
Copyright (c) 2010-2024 Erik Berlin. See [LICENSE][] for details.
|
96
73
|
|
97
74
|
[license]: LICENSE.md
|
data/Rakefile
CHANGED
@@ -1,21 +1,33 @@
|
|
1
|
-
require
|
1
|
+
require "bundler"
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
|
-
require
|
4
|
+
require "rspec/core/rake_task"
|
5
5
|
RSpec::Core::RakeTask.new(:spec)
|
6
6
|
|
7
|
-
task :
|
8
|
-
task :default => :spec
|
7
|
+
task test: :spec
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
require "rubocop/rake_task"
|
10
|
+
RuboCop::RakeTask.new
|
11
|
+
|
12
|
+
require "yard"
|
13
|
+
YARD::Rake::YardocTask.new do |task|
|
14
|
+
task.files = ["lib/**/*.rb", "-", "LICENSE.md"]
|
15
|
+
task.options = [
|
16
|
+
"--no-private",
|
17
|
+
"--protected",
|
18
|
+
"--output-dir", "doc/yard",
|
19
|
+
"--markup", "markdown"
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
require "yardstick/rake/measurement"
|
24
|
+
Yardstick::Rake::Measurement.new do |measurement|
|
25
|
+
measurement.output = "measurement/report.txt"
|
21
26
|
end
|
27
|
+
|
28
|
+
require "yardstick/rake/verify"
|
29
|
+
Yardstick::Rake::Verify.new do |verify|
|
30
|
+
verify.threshold = 48.8
|
31
|
+
end
|
32
|
+
|
33
|
+
task default: %i[spec rubocop verify_measurements]
|
@@ -1,25 +1,28 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "libxml" unless defined?(LibXML)
|
2
|
+
require "multi_xml/parsers/libxml2_parser"
|
3
3
|
|
4
4
|
module MultiXml
|
5
5
|
module Parsers
|
6
|
-
module Libxml
|
6
|
+
module Libxml # :nodoc:
|
7
7
|
include Libxml2Parser
|
8
|
-
|
9
8
|
extend self
|
10
9
|
|
11
|
-
def parse_error
|
10
|
+
def parse_error
|
11
|
+
::LibXML::XML::Error
|
12
|
+
end
|
12
13
|
|
13
14
|
def parse(xml)
|
14
15
|
node_to_hash(LibXML::XML::Parser.io(xml).parse.root)
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
private
|
19
|
+
|
20
|
+
def each_child(node, &)
|
21
|
+
node.each_child(&)
|
19
22
|
end
|
20
23
|
|
21
|
-
def each_attr(node, &
|
22
|
-
node.each_attr(&
|
24
|
+
def each_attr(node, &)
|
25
|
+
node.each_attr(&)
|
23
26
|
end
|
24
27
|
|
25
28
|
def node_name(node)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module MultiXml
|
2
2
|
module Parsers
|
3
|
-
module Libxml2Parser
|
3
|
+
module Libxml2Parser # :nodoc:
|
4
4
|
# Convert XML document to hash
|
5
5
|
#
|
6
6
|
# node::
|
@@ -8,16 +8,19 @@ module MultiXml
|
|
8
8
|
#
|
9
9
|
# hash::
|
10
10
|
# Hash to merge the converted element into.
|
11
|
-
def node_to_hash(node, hash={})
|
12
|
-
node_hash = {MultiXml::CONTENT_ROOT =>
|
11
|
+
def node_to_hash(node, hash = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
12
|
+
node_hash = {MultiXml::CONTENT_ROOT => ""}
|
13
13
|
|
14
14
|
name = node_name(node)
|
15
15
|
|
16
16
|
# Insert node hash into parent hash correctly.
|
17
17
|
case hash[name]
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
21
24
|
end
|
22
25
|
|
23
26
|
# Handle child elements
|
@@ -25,24 +28,18 @@ module MultiXml
|
|
25
28
|
if c.element?
|
26
29
|
node_to_hash(c, node_hash)
|
27
30
|
elsif c.text? || c.cdata?
|
28
|
-
node_hash[MultiXml::CONTENT_ROOT]
|
31
|
+
node_hash[MultiXml::CONTENT_ROOT] += c.content
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
32
35
|
# Remove content node if it is empty
|
33
|
-
if node_hash[MultiXml::CONTENT_ROOT].strip.empty?
|
34
|
-
node_hash.delete(MultiXml::CONTENT_ROOT)
|
35
|
-
end
|
36
|
+
node_hash.delete(MultiXml::CONTENT_ROOT) if node_hash[MultiXml::CONTENT_ROOT].strip.empty?
|
36
37
|
|
37
38
|
# Handle attributes
|
38
39
|
each_attr(node) do |a|
|
39
40
|
key = node_name(a)
|
40
|
-
|
41
|
-
node_hash[key] =
|
42
|
-
[a.value, v]
|
43
|
-
else
|
44
|
-
a.value
|
45
|
-
end
|
41
|
+
v = node_hash[key]
|
42
|
+
node_hash[key] = ((v) ? [a.value, v] : a.value)
|
46
43
|
end
|
47
44
|
|
48
45
|
hash
|
@@ -51,23 +48,22 @@ module MultiXml
|
|
51
48
|
# Parse an XML Document IO into a simple hash.
|
52
49
|
# xml::
|
53
50
|
# XML Document IO to parse
|
54
|
-
def parse(
|
55
|
-
raise
|
51
|
+
def parse(_)
|
52
|
+
raise(NotImplementedError, "inheritor should define #{__method__}")
|
56
53
|
end
|
57
54
|
|
58
|
-
# :stopdoc:
|
59
55
|
private
|
60
56
|
|
61
|
-
def each_child(*
|
62
|
-
raise
|
57
|
+
def each_child(*)
|
58
|
+
raise(NotImplementedError, "inheritor should define #{__method__}")
|
63
59
|
end
|
64
60
|
|
65
|
-
def each_attr(*
|
66
|
-
raise
|
61
|
+
def each_attr(*)
|
62
|
+
raise(NotImplementedError, "inheritor should define #{__method__}")
|
67
63
|
end
|
68
64
|
|
69
|
-
def node_name(*
|
70
|
-
raise
|
65
|
+
def node_name(*)
|
66
|
+
raise(NotImplementedError, "inheritor should define #{__method__}")
|
71
67
|
end
|
72
68
|
end
|
73
69
|
end
|
@@ -1,27 +1,31 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "nokogiri" unless defined?(Nokogiri)
|
2
|
+
require "multi_xml/parsers/libxml2_parser"
|
3
3
|
|
4
4
|
module MultiXml
|
5
5
|
module Parsers
|
6
|
-
module Nokogiri
|
6
|
+
module Nokogiri # :nodoc:
|
7
7
|
include Libxml2Parser
|
8
|
-
|
9
8
|
extend self
|
10
9
|
|
11
|
-
def parse_error
|
10
|
+
def parse_error
|
11
|
+
::Nokogiri::XML::SyntaxError
|
12
|
+
end
|
12
13
|
|
13
14
|
def parse(xml)
|
14
15
|
doc = ::Nokogiri::XML(xml)
|
15
|
-
raise
|
16
|
+
raise(doc.errors.first) unless doc.errors.empty?
|
17
|
+
|
16
18
|
node_to_hash(doc.root)
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
+
private
|
22
|
+
|
23
|
+
def each_child(node, &)
|
24
|
+
node.children.each(&)
|
21
25
|
end
|
22
26
|
|
23
|
-
def each_attr(node, &
|
24
|
-
node.attribute_nodes.each(&
|
27
|
+
def each_attr(node, &)
|
28
|
+
node.attribute_nodes.each(&)
|
25
29
|
end
|
26
30
|
|
27
31
|
def node_name(node)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "oga" unless defined?(Oga)
|
2
|
+
require "multi_xml/parsers/libxml2_parser"
|
3
|
+
|
4
|
+
module MultiXml
|
5
|
+
module Parsers
|
6
|
+
module Oga # :nodoc:
|
7
|
+
include Libxml2Parser
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def parse_error
|
11
|
+
LL::ParserError
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(io)
|
15
|
+
document = ::Oga.parse_xml(io)
|
16
|
+
node_to_hash(document.children[0])
|
17
|
+
end
|
18
|
+
|
19
|
+
def node_to_hash(node, hash = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
20
|
+
node_hash = {MultiXml::CONTENT_ROOT => ""}
|
21
|
+
|
22
|
+
name = node_name(node)
|
23
|
+
|
24
|
+
# Insert node hash into parent hash correctly.
|
25
|
+
case hash[name]
|
26
|
+
when Array
|
27
|
+
hash[name] << node_hash
|
28
|
+
when Hash
|
29
|
+
hash[name] = [hash[name], node_hash]
|
30
|
+
when NilClass
|
31
|
+
hash[name] = node_hash
|
32
|
+
end
|
33
|
+
|
34
|
+
# Handle child elements
|
35
|
+
each_child(node) do |c|
|
36
|
+
if c.is_a?(::Oga::XML::Element)
|
37
|
+
node_to_hash(c, node_hash)
|
38
|
+
elsif c.is_a?(::Oga::XML::Text) || c.is_a?(::Oga::XML::Cdata)
|
39
|
+
node_hash[MultiXml::CONTENT_ROOT] += c.text
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Remove content node if it is empty
|
44
|
+
node_hash.delete(MultiXml::CONTENT_ROOT) if node_hash[MultiXml::CONTENT_ROOT].strip.empty?
|
45
|
+
|
46
|
+
# Handle attributes
|
47
|
+
each_attr(node) do |a|
|
48
|
+
key = node_name(a)
|
49
|
+
v = node_hash[key]
|
50
|
+
node_hash[key] = ((v) ? [a.value, v] : a.value)
|
51
|
+
end
|
52
|
+
|
53
|
+
hash
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def each_child(node, &)
|
59
|
+
node.children.each(&)
|
60
|
+
end
|
61
|
+
|
62
|
+
def each_attr(node, &)
|
63
|
+
node.attributes.each(&)
|
64
|
+
end
|
65
|
+
|
66
|
+
def node_name(node)
|
67
|
+
node.name
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/multi_xml/parsers/ox.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "ox" unless defined?(Ox)
|
2
2
|
|
3
3
|
# Each MultiXml parser is expected to parse an XML document into a Hash. The
|
4
4
|
# conversion rules are:
|
@@ -20,9 +20,8 @@ require 'ox' unless defined?(Ox)
|
|
20
20
|
|
21
21
|
module MultiXml
|
22
22
|
module Parsers
|
23
|
-
module Ox
|
24
|
-
|
25
|
-
extend self
|
23
|
+
module Ox # :nodoc:
|
24
|
+
module_function
|
26
25
|
|
27
26
|
def parse_error
|
28
27
|
Exception
|
@@ -30,14 +29,14 @@ module MultiXml
|
|
30
29
|
|
31
30
|
def parse(io)
|
32
31
|
handler = Handler.new
|
33
|
-
::Ox.sax_parse(handler, io, :
|
32
|
+
::Ox.sax_parse(handler, io, convert_special: true, skip: :skip_return)
|
34
33
|
handler.doc
|
35
34
|
end
|
36
35
|
|
37
36
|
class Handler
|
38
37
|
attr_accessor :stack
|
39
38
|
|
40
|
-
def initialize
|
39
|
+
def initialize
|
41
40
|
@stack = []
|
42
41
|
end
|
43
42
|
|
@@ -46,9 +45,7 @@ module MultiXml
|
|
46
45
|
end
|
47
46
|
|
48
47
|
def attr(name, value)
|
49
|
-
unless @stack.empty?
|
50
|
-
append(name, value)
|
51
|
-
end
|
48
|
+
append(name, value) unless @stack.empty?
|
52
49
|
end
|
53
50
|
|
54
51
|
def text(value)
|
@@ -60,26 +57,24 @@ module MultiXml
|
|
60
57
|
end
|
61
58
|
|
62
59
|
def start_element(name)
|
63
|
-
if @stack.empty?
|
64
|
-
|
65
|
-
end
|
66
|
-
h = Hash.new
|
60
|
+
@stack.push({}) if @stack.empty?
|
61
|
+
h = {}
|
67
62
|
append(name, h)
|
68
63
|
@stack.push(h)
|
69
64
|
end
|
70
65
|
|
71
|
-
def end_element(
|
72
|
-
@stack.pop
|
66
|
+
def end_element(_)
|
67
|
+
@stack.pop
|
73
68
|
end
|
74
69
|
|
75
70
|
def error(message, line, column)
|
76
|
-
raise
|
71
|
+
raise(StandardError, "#{message} at #{line}:#{column}")
|
77
72
|
end
|
78
73
|
|
79
74
|
def append(key, value)
|
80
75
|
key = key.to_s
|
81
76
|
h = @stack.last
|
82
|
-
if h.
|
77
|
+
if h.key?(key)
|
83
78
|
v = h[key]
|
84
79
|
if v.is_a?(Array)
|
85
80
|
v << value
|
@@ -90,8 +85,7 @@ module MultiXml
|
|
90
85
|
h[key] = value
|
91
86
|
end
|
92
87
|
end
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end # MultiXml
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|