xml2json-rb 0.1.1 → 0.3.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/Cargo.lock +1 -1
- data/ext/xml2json/Cargo.toml +1 -1
- data/ext/xml2json/src/lib.rs +200 -34
- data/lib/xml2json/version.rb +1 -1
- data/lib/xml2json/xml2json.so +0 -0
- data/lib/xml2json.rb +17 -2
- data/sig/xml2_json/json.rbs +2 -1
- data/sig/xml2_json/xml/encoding.rbs +7 -0
- data/sig/xml2_json/xml/version.rbs +8 -0
- data/sig/xml2_json/xml.rbs +2 -1
- metadata +10 -105
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7300901db2b5b148d589efdc043ba16afe065c4848300ae4fe13606e372c9e8f
|
4
|
+
data.tar.gz: bcfa9f9a7017c4d5c62f538b1abe07bd4c996d8a650e412798d43e7c18871e15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2719f4a3cc080a3b26c1c2e4e06fb351af1f6a71d882f2a192171a55b63caf66c4d2b143744239ea6842ef6cecfa00b4d0b45065660264d012dd281f716efe9b
|
7
|
+
data.tar.gz: 973a6c931eba9a847bcb48be1834e6c63a5c6f64538d199380b7405e4ca64d3ad316a4041490db7bf59623e24f299335ee68697f9ea304ab9f245b490eff1029
|
data/Cargo.lock
CHANGED
data/ext/xml2json/Cargo.toml
CHANGED
data/ext/xml2json/src/lib.rs
CHANGED
@@ -1,47 +1,207 @@
|
|
1
|
-
use magnus::{define_module, function, prelude::*, Error};
|
2
|
-
use
|
1
|
+
use magnus::{define_module, function, prelude::*, Error, Value};
|
2
|
+
use magnus::scan_args::{scan_args};
|
3
|
+
use xml2json_rs::{XmlBuilder, JsonBuilder, JsonConfig, XmlConfig, Declaration, Version, Encoding, Indentation};
|
3
4
|
|
4
5
|
// fn hello(subject: String) -> String {
|
5
6
|
// format!("Hello from Rust, {}!", subject)
|
6
7
|
// }
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
#[macro_export]
|
10
|
+
macro_rules! set_arg {
|
11
|
+
($config:expr, $opts_hash:expr, $arg:ident, $arg_type:ident) => (
|
12
|
+
let arg_value = $opts_hash.lookup::<_, Option<$arg_type>>(magnus::Symbol::new(stringify!($arg)))?;
|
13
|
+
if arg_value.is_some() {
|
14
|
+
$config.$arg(arg_value.unwrap());
|
15
|
+
}
|
16
|
+
);
|
17
|
+
}
|
11
18
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
// self
|
16
|
-
// }
|
17
|
-
//
|
18
|
-
// fn build(self, json_s: String) -> Result<String, Error> {
|
19
|
-
// build_xml_impl(json_s, Some(self))
|
20
|
-
// }
|
21
|
-
// }
|
19
|
+
fn map_xml2json_err(error: xml2json_rs::X2JError) -> Error {
|
20
|
+
Error::new(magnus::exception::runtime_error(), error.details())
|
21
|
+
}
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
fn build_xml(args: &[Value]) -> Result<String, Error> {
|
24
|
+
build_xml_impl(args, false)
|
25
|
+
}
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
fn build_pretty_xml(args: &[Value]) -> Result<String, Error> {
|
28
|
+
build_xml_impl(args, true)
|
29
|
+
}
|
30
|
+
|
31
|
+
fn build_xml_impl(args: &[Value], build_pretty: bool) -> Result<String, Error> {
|
32
|
+
let args = scan_args::<_, _, (), (), _, ()>(args)?;
|
33
|
+
let (json_s, ): (String, ) = args.required;
|
34
|
+
let (opts, ): (Option<magnus::RHash>, ) = args.optional;
|
35
|
+
let _: () = args.keywords;
|
36
|
+
|
37
|
+
let mut xml_builder: XmlBuilder;
|
38
|
+
if opts.is_some() { // yep, even if it's an empty hash
|
39
|
+
// println!("{}", opts.unwrap().to_string());
|
40
|
+
let opts_hash = opts.unwrap();
|
41
|
+
let mut config = XmlConfig::new();
|
42
|
+
set_arg!(config, opts_hash, root_name, String);
|
43
|
+
set_arg!(config, opts_hash, attrkey, String);
|
44
|
+
set_arg!(config, opts_hash, charkey, String);
|
45
|
+
|
46
|
+
let decl_version = opts_hash.lookup::<_, Option<Value>>(magnus::Symbol::new("version"))?;
|
47
|
+
let decl_encoding = opts_hash.lookup::<_, Option<Value>>(magnus::Symbol::new("encoding"))?;
|
48
|
+
let decl_standalone = opts_hash.lookup::<_, Option<bool>>(magnus::Symbol::new("standalone"))?;
|
49
|
+
if decl_version.is_some()
|
50
|
+
|| decl_encoding.is_some()
|
51
|
+
|| decl_standalone.is_some()
|
52
|
+
{ // something is specified
|
53
|
+
// I didn't find a way to get defaults without copying them
|
54
|
+
let decl_version_val;
|
55
|
+
if decl_version.is_some() {
|
56
|
+
let decl_version_str = unsafe { decl_version.unwrap().to_s() }?.into_owned();
|
57
|
+
decl_version_val = Version::try_from(decl_version_str.as_str())
|
58
|
+
.map_err(map_xml2json_err)?;
|
59
|
+
} else { decl_version_val = Version::XML10; }
|
60
|
+
let decl_encoding_val;
|
61
|
+
if decl_encoding.is_some() {
|
62
|
+
let decl_encoding_str = unsafe { decl_encoding.unwrap().to_s() }?.into_owned();
|
63
|
+
decl_encoding_val = Some(Encoding::try_from(decl_encoding_str.as_str())
|
64
|
+
.map_err(map_xml2json_err)?);
|
65
|
+
} else { decl_encoding_val = None; }
|
66
|
+
|
67
|
+
let decl = Declaration::new(
|
68
|
+
decl_version_val,
|
69
|
+
decl_encoding_val,
|
70
|
+
decl_standalone,
|
71
|
+
);
|
72
|
+
config.decl(decl);
|
73
|
+
}
|
74
|
+
|
75
|
+
let indent = opts_hash.lookup::<_, Option<bool>>(magnus::Symbol::new("indent"))?;
|
76
|
+
if indent.unwrap_or(true) {
|
77
|
+
let indent_char = opts_hash.lookup::<_, Option<char>>(magnus::Symbol::new("indent_char"))?;
|
78
|
+
let indent_size = opts_hash.lookup::<_, Option<usize>>(magnus::Symbol::new("indent_size"))?;
|
79
|
+
if indent_char.is_some()
|
80
|
+
|| indent_size.is_some()
|
81
|
+
{
|
82
|
+
let indent_char_val: u8;
|
83
|
+
if indent_char.is_some() {
|
84
|
+
indent_char_val = u8::try_from(indent_char.unwrap()).map_err(|error| Error::new(magnus::exception::type_error(), error.to_string()))?;
|
85
|
+
} else { indent_char_val = b' '; }
|
86
|
+
config.rendering(Indentation::new(
|
87
|
+
indent_char_val,
|
88
|
+
indent_size.unwrap_or(2),
|
89
|
+
));
|
90
|
+
} else if indent.unwrap_or(build_pretty) {
|
91
|
+
// because Indentation::default is not the same as not calling config.rendering at all;
|
92
|
+
config.rendering(Indentation::default());
|
93
|
+
}
|
94
|
+
}
|
95
|
+
xml_builder = config.finalize();
|
96
|
+
} else if build_pretty {
|
97
|
+
xml_builder = XmlConfig::new().rendering(Indentation::default()).finalize();
|
98
|
+
} else { xml_builder = XmlBuilder::default(); }
|
33
99
|
|
34
|
-
fn build_xml(json_s: String) -> Result<String, Error> {
|
35
|
-
let mut xml_builder = XmlBuilder::default();
|
36
100
|
xml_builder.build_from_json_string(&json_s).or_else(|error| {
|
37
|
-
Err(
|
101
|
+
Err(map_xml2json_err(error))
|
38
102
|
})
|
39
103
|
}
|
40
104
|
|
41
|
-
fn build_json(
|
42
|
-
|
43
|
-
|
44
|
-
|
105
|
+
fn build_json(args: &[Value]) -> Result<String, Error> {
|
106
|
+
build_json_impl(args, false)
|
107
|
+
}
|
108
|
+
|
109
|
+
fn build_pretty_json(args: &[Value]) -> Result<String, Error> {
|
110
|
+
build_json_impl(args, true)
|
111
|
+
}
|
112
|
+
|
113
|
+
fn build_json_impl(args: &[Value], mut build_pretty: bool) -> Result<String, Error> {
|
114
|
+
// https://docs.rs/magnus/latest/magnus/scan_args/fn.scan_args.html
|
115
|
+
let args = scan_args::<_, _, (), (), _, ()>(args)?;
|
116
|
+
let (xml, ): (String, ) = args.required;
|
117
|
+
let (opts, ): (Option<magnus::RHash>, ) = args.optional;
|
118
|
+
// let _: () = args.optional;
|
119
|
+
let _: () = args.keywords;
|
120
|
+
|
121
|
+
// Impossible, too long
|
122
|
+
// let kw = get_kwargs::<_, (), (
|
123
|
+
// Option<String>, // charkey
|
124
|
+
// Option<String>, // attrkey
|
125
|
+
// Option<String>, // empty_tag
|
126
|
+
// Option<bool>, // explicit_root
|
127
|
+
// Option<bool>, // trim
|
128
|
+
// Option<bool>, // ignore_attrs
|
129
|
+
// Option<bool>, // merge_attrs
|
130
|
+
// Option<bool>, // normalize_text
|
131
|
+
// Option<bool>, // lowercase_tags
|
132
|
+
// Option<bool>, // explicit_array
|
133
|
+
// Option<bool>, // explicit_charkey
|
134
|
+
// ), ()>(args.keywords, &[], &[
|
135
|
+
// "charkey",
|
136
|
+
// "attrkey",
|
137
|
+
// "empty_tag",
|
138
|
+
// "explicit_root",
|
139
|
+
// "trim",
|
140
|
+
// "ignore_attrs",
|
141
|
+
// "merge_attrs",
|
142
|
+
// "normalize_text",
|
143
|
+
// "lowercase_tags",
|
144
|
+
// "explicit_array",
|
145
|
+
// "explicit_charkey",
|
146
|
+
// ])?;
|
147
|
+
// let (
|
148
|
+
// charkey,
|
149
|
+
// attrkey,
|
150
|
+
// empty_tag,
|
151
|
+
// explicit_root,
|
152
|
+
// trim,
|
153
|
+
// ignore_attrs,
|
154
|
+
// merge_attrs,
|
155
|
+
// normalize_text,
|
156
|
+
// lowercase_tags,
|
157
|
+
// explicit_array,
|
158
|
+
// explicit_charkey,
|
159
|
+
// ) = kw.optional;
|
160
|
+
// if charkey.is_some()
|
161
|
+
// || attrkey.is_some()
|
162
|
+
// || empty_tag.is_some()
|
163
|
+
// || explicit_root.is_some()
|
164
|
+
// || trim.is_some()
|
165
|
+
// || ignore_attrs.is_some()
|
166
|
+
// || merge_attrs.is_some()
|
167
|
+
// || normalize_text.is_some()
|
168
|
+
// || lowercase_tags.is_some()
|
169
|
+
// || explicit_array.is_some()
|
170
|
+
// || explicit_charkey.is_some()
|
171
|
+
// {
|
172
|
+
// println!("any")
|
173
|
+
// } else { println!("none") }
|
174
|
+
|
175
|
+
let json_builder: JsonBuilder;
|
176
|
+
if opts.is_some() { // yep, even if it's an empty hash
|
177
|
+
// println!("{}", opts.unwrap().to_string());
|
178
|
+
let opts_hash = opts.unwrap();
|
179
|
+
let mut config = JsonConfig::new();
|
180
|
+
set_arg!(config, opts_hash, charkey, String);
|
181
|
+
set_arg!(config, opts_hash, attrkey, String);
|
182
|
+
set_arg!(config, opts_hash, empty_tag, String);
|
183
|
+
set_arg!(config, opts_hash, explicit_root, bool);
|
184
|
+
set_arg!(config, opts_hash, trim, bool);
|
185
|
+
set_arg!(config, opts_hash, ignore_attrs, bool);
|
186
|
+
set_arg!(config, opts_hash, merge_attrs, bool);
|
187
|
+
set_arg!(config, opts_hash, normalize_text, bool);
|
188
|
+
set_arg!(config, opts_hash, lowercase_tags, bool);
|
189
|
+
set_arg!(config, opts_hash, explicit_array, bool);
|
190
|
+
set_arg!(config, opts_hash, explicit_charkey, bool);
|
191
|
+
json_builder = config.finalize();
|
192
|
+
|
193
|
+
let indent = opts_hash.lookup::<_, Option<bool>>(magnus::Symbol::new("indent"))?;
|
194
|
+
if indent.is_some() {
|
195
|
+
build_pretty = indent.unwrap();
|
196
|
+
}
|
197
|
+
} else { json_builder = JsonBuilder::default(); }
|
198
|
+
|
199
|
+
if build_pretty {
|
200
|
+
json_builder.build_pretty_string_from_xml(&xml)
|
201
|
+
} else {
|
202
|
+
json_builder.build_string_from_xml(&xml)
|
203
|
+
}.or_else(|error| {
|
204
|
+
Err(map_xml2json_err(error))
|
45
205
|
})
|
46
206
|
}
|
47
207
|
|
@@ -51,9 +211,15 @@ fn init() -> Result<(), Error> {
|
|
51
211
|
// module.define_singleton_method("hello", function!(hello, 1))?;
|
52
212
|
// It's not possible to wrap XmlBuilder
|
53
213
|
let xml = module.define_module("Xml")?;
|
54
|
-
xml.
|
55
|
-
|
214
|
+
let xml_version = xml.define_module("Version")?;
|
215
|
+
xml_version.const_set("XML10", Version::XML10.to_string())?;
|
216
|
+
xml_version.const_set("XML11", Version::XML11.to_string())?;
|
217
|
+
let xml_encoding = xml.define_module("Encoding")?;
|
218
|
+
xml_encoding.const_set("UTF8", Encoding::UTF8.to_string())?;
|
219
|
+
xml.define_singleton_method("build", function!(build_xml, -1))?;
|
220
|
+
xml.define_singleton_method("build_pretty", function!(build_pretty_xml, -1))?;
|
56
221
|
let json = module.define_module("Json")?;
|
57
|
-
json.define_singleton_method("build", function!(build_json, 1))?;
|
222
|
+
json.define_singleton_method("build", function!(build_json, -1))?;
|
223
|
+
json.define_singleton_method("build_pretty", function!(build_pretty_json, -1))?;
|
58
224
|
Ok(())
|
59
225
|
}
|
data/lib/xml2json/version.rb
CHANGED
data/lib/xml2json/xml2json.so
CHANGED
Binary file
|
data/lib/xml2json.rb
CHANGED
@@ -7,15 +7,30 @@ require_relative "xml2json/xml2json"
|
|
7
7
|
module Xml2Json
|
8
8
|
# @!parse [ruby]
|
9
9
|
# module Xml
|
10
|
+
# module Version
|
11
|
+
# XML10 = "1.0"
|
12
|
+
# XML11 = "1.1"
|
13
|
+
# end
|
14
|
+
# module Encoding
|
15
|
+
# UTF8 = "UTF-8"
|
16
|
+
# end
|
17
|
+
#
|
10
18
|
# # @param json_s [String, #to_str] JSON string
|
19
|
+
# # @param opts [Hash<Symbol, Object>] config params
|
20
|
+
# # @see https://docs.rs/xml2json-rs/1.0.1/xml2json_rs/struct.XmlConfig.html rust doc
|
11
21
|
# # @return [String] XML string
|
12
22
|
# # @raise [RuntimeError] if the input string is invalid
|
13
|
-
# def self.build(json_s); end
|
23
|
+
# def self.build(json_s, opts: nil); end
|
24
|
+
# def self.build_pretty(json_s, opts: nil); end
|
14
25
|
# end
|
26
|
+
#
|
15
27
|
# module Json
|
16
28
|
# # @param xml [String, #to_str] XML string
|
29
|
+
# # @param opts [Hash<Symbol, Object>] config params
|
30
|
+
# # @see https://docs.rs/xml2json-rs/1.0.1/xml2json_rs/struct.JsonConfig.html rust doc
|
17
31
|
# # @return [String] JSON string
|
18
32
|
# # @raise [RuntimeError] if the input string is invalid
|
19
|
-
# def self.build(xml); end
|
33
|
+
# def self.build(xml, opts: nil); end
|
34
|
+
# def self.build_pretty(xml, opts: nil); end
|
20
35
|
# end
|
21
36
|
end
|
data/sig/xml2_json/json.rbs
CHANGED
data/sig/xml2_json/xml.rbs
CHANGED
metadata
CHANGED
@@ -1,113 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xml2json-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- uvlad7
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: yard-rustdoc
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: pry
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: pry-byebug
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: yard
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rack
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rackup
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: puma
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
11
|
+
date: 2023-10-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
111
13
|
description: This gem helps to convert xml strings to json and vise versa
|
112
14
|
email:
|
113
15
|
- uvlad7@gmail.com
|
@@ -126,6 +28,8 @@ files:
|
|
126
28
|
- lib/xml2json/xml2json.so
|
127
29
|
- sig/xml2_json/json.rbs
|
128
30
|
- sig/xml2_json/xml.rbs
|
31
|
+
- sig/xml2_json/xml/encoding.rbs
|
32
|
+
- sig/xml2_json/xml/version.rbs
|
129
33
|
- sig/xml2json.rbs
|
130
34
|
homepage: https://github.com/uvlad7/xml2json-rb
|
131
35
|
licenses:
|
@@ -134,8 +38,9 @@ metadata:
|
|
134
38
|
homepage_uri: https://github.com/uvlad7/xml2json-rb
|
135
39
|
source_code_uri: https://github.com/uvlad7/xml2json-rb
|
136
40
|
changelog_uri: https://github.com/uvlad7/xml2json-rb/blob/main/CHANGELOG.md
|
137
|
-
documentation_uri: https://rubydoc.info/gems/xml2json-rb/0.
|
138
|
-
|
41
|
+
documentation_uri: https://rubydoc.info/gems/xml2json-rb/0.3.0
|
42
|
+
rubygems_mfa_required: 'true'
|
43
|
+
post_install_message:
|
139
44
|
rdoc_options: []
|
140
45
|
require_paths:
|
141
46
|
- lib
|
@@ -151,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
56
|
version: 3.3.11
|
152
57
|
requirements: []
|
153
58
|
rubygems_version: 3.4.10
|
154
|
-
signing_key:
|
59
|
+
signing_key:
|
155
60
|
specification_version: 4
|
156
61
|
summary: Ruby wrapper for xml2json-rs
|
157
62
|
test_files: []
|