fast-xml 1.0.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/LICENSE +21 -0
- data/README.md +164 -0
- data/ext/fastxml/extconf.rb +17 -0
- data/ext/fastxml/fastxml.c +67 -0
- data/ext/fastxml/fastxml.h +14 -0
- data/ext/fastxml/xh.c +338 -0
- data/ext/fastxml/xh.h +58 -0
- data/ext/fastxml/xh_buffer.c +40 -0
- data/ext/fastxml/xh_buffer.h +38 -0
- data/ext/fastxml/xh_buffer_helper.h +97 -0
- data/ext/fastxml/xh_config.h +74 -0
- data/ext/fastxml/xh_core.h +53 -0
- data/ext/fastxml/xh_encoder.c +193 -0
- data/ext/fastxml/xh_encoder.h +56 -0
- data/ext/fastxml/xh_h2x.c +62 -0
- data/ext/fastxml/xh_h2x.h +93 -0
- data/ext/fastxml/xh_h2x_native.c +89 -0
- data/ext/fastxml/xh_h2x_native_attr.c +161 -0
- data/ext/fastxml/xh_log.c +31 -0
- data/ext/fastxml/xh_log.h +100 -0
- data/ext/fastxml/xh_param.c +77 -0
- data/ext/fastxml/xh_param.h +56 -0
- data/ext/fastxml/xh_ruby_buffer.c +51 -0
- data/ext/fastxml/xh_ruby_buffer.h +30 -0
- data/ext/fastxml/xh_sort.c +40 -0
- data/ext/fastxml/xh_sort.h +20 -0
- data/ext/fastxml/xh_stack.c +19 -0
- data/ext/fastxml/xh_stack.h +41 -0
- data/ext/fastxml/xh_string.h +105 -0
- data/ext/fastxml/xh_writer.c +94 -0
- data/ext/fastxml/xh_writer.h +49 -0
- data/ext/fastxml/xh_xml.h +453 -0
- data/lib/fastxml.rb +59 -0
- data/lib/fastxml/error.rb +7 -0
- data/lib/fastxml/version.rb +3 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d5c3255eaacfe69128a428f67ab670d680e05bf2
|
4
|
+
data.tar.gz: 65b1e5898db7b64bd1b58ec0b23fedb1c3692a1c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8a290a9676f388f342c63e2fdef2d2445f2db91df0d58b13cb64515f019c6595ce18cfef7466c2b932de527dca1230ef690280ec1ef7598ce6a25e9038a8d727
|
7
|
+
data.tar.gz: b0c95264bf47245e3d53e28844cee4fffe468b365098a45881f0869be4c01f9533ba9420527fc24c7ef8359303a3ee0779efae06d1a18073bde7336fc104a684
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Yuriy Ustushenko
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# FastXML
|
2
|
+
|
3
|
+
Fast Ruby Hash to XML and XML to Ruby Hash converter written in pure C.
|
4
|
+
|
5
|
+
[](http://travis-ci.org/yoreek/fastxml)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'fastxml'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install fast-xml
|
22
|
+
|
23
|
+
## Release Notes
|
24
|
+
|
25
|
+
See [CHANGELOG.md](CHANGELOG.md)
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'fastxml'
|
31
|
+
|
32
|
+
# convert hash to XML
|
33
|
+
FastXML.hash2xml({ tag1: { tag2: 'content' } }, indent: 2)
|
34
|
+
# =>
|
35
|
+
# <?xml version="1.0" encoding="utf-8"?>
|
36
|
+
# <root>
|
37
|
+
# <tag1>
|
38
|
+
# <tag2>content</tag2>
|
39
|
+
# </tag1>
|
40
|
+
# </root>
|
41
|
+
|
42
|
+
# use enumerator
|
43
|
+
FastXML.hash2xml({ enumerator: 3.times }, indent: 2)
|
44
|
+
# =>
|
45
|
+
# <?xml version="1.0" encoding="utf-8"?>
|
46
|
+
# <root>
|
47
|
+
# <enumerator>0</enumerator>
|
48
|
+
# <enumerator>1</enumerator>
|
49
|
+
# <enumerator>2</enumerator>
|
50
|
+
# </root>
|
51
|
+
|
52
|
+
# output to file handle
|
53
|
+
# fh = StringIO.new
|
54
|
+
FastXML.hash2xml({ enumerator: 3.times }, indent: 2, output: fh)
|
55
|
+
fh.string
|
56
|
+
# =>
|
57
|
+
# <?xml version="1.0" encoding="utf-8"?>
|
58
|
+
# <root>
|
59
|
+
# <enumerator>0</enumerator>
|
60
|
+
# <enumerator>1</enumerator>
|
61
|
+
# <enumerator>2</enumerator>
|
62
|
+
# </root>
|
63
|
+
|
64
|
+
```
|
65
|
+
|
66
|
+
## Options
|
67
|
+
|
68
|
+
The following options are available to pass to FastXML.hash2xml(hash, options = {}).
|
69
|
+
|
70
|
+
* **:root** => 'root'
|
71
|
+
* Root node name.
|
72
|
+
|
73
|
+
* **:version** => '1.0'
|
74
|
+
* XML document version
|
75
|
+
|
76
|
+
* **:encoding** => 'utf-8'
|
77
|
+
* XML input/output encoding
|
78
|
+
|
79
|
+
* **:indent** => 0
|
80
|
+
* if indent great than "0", XML output should be indented according to
|
81
|
+
its hierarchic structure. This value determines the number of
|
82
|
+
spaces.
|
83
|
+
|
84
|
+
* if indent is "0", XML output will all be on one line.
|
85
|
+
|
86
|
+
* **:output** => nil
|
87
|
+
* XML output method
|
88
|
+
|
89
|
+
* if output is nil, XML document dumped into string.
|
90
|
+
|
91
|
+
* if output is filehandle, XML document writes directly to a filehandle or a
|
92
|
+
stream.
|
93
|
+
|
94
|
+
* **:canonical** => false
|
95
|
+
* if canonical is "true", converter will be write hashes sorted by key.
|
96
|
+
|
97
|
+
* if canonical is "false", order of the element will be pseudo-randomly.
|
98
|
+
|
99
|
+
* **:use_attr** => false
|
100
|
+
* if use_attr is "true", converter will be use the attributes.
|
101
|
+
|
102
|
+
* if use_attr is "fale", converter will be use tags only.
|
103
|
+
|
104
|
+
* **:content** => nil
|
105
|
+
* if defined that the key name for the text content(used only if
|
106
|
+
use_attr = true).
|
107
|
+
|
108
|
+
* **:force_array** => nil
|
109
|
+
* This option is similar to "ForceArray" from [XMl::Simple module]:
|
110
|
+
(https://metacpan.org/pod/XML::Simple#ForceArray-1-in---important).
|
111
|
+
|
112
|
+
* **:force_content** => nil
|
113
|
+
* This option is similar to "ForceContent" from [XMl::Simple module]:
|
114
|
+
(https://metacpan.org/pod/XML::Simple#ForceContent-1-in---seldom-used).
|
115
|
+
|
116
|
+
* **:merge_text** => false
|
117
|
+
* Setting this option to "true" will cause merge adjacent text nodes.
|
118
|
+
|
119
|
+
* **:xml_decl** => true
|
120
|
+
* if xml_decl is "true", output will start with the XML declaration
|
121
|
+
'<?xml version="1.0" encoding="utf-8"?>'.
|
122
|
+
|
123
|
+
* if xml_decl is "false", XML declaration will not be output.
|
124
|
+
|
125
|
+
* **:trim** => false
|
126
|
+
* Trim leading and trailing whitespace from text nodes.
|
127
|
+
|
128
|
+
* **:utf8** => true
|
129
|
+
* Turn on utf8 flag for strings if enabled.
|
130
|
+
|
131
|
+
* **:max_depth** => 1024
|
132
|
+
* Maximum recursion depth.
|
133
|
+
|
134
|
+
* **:buf_size** => 4096
|
135
|
+
* Buffer size for reading end encoding data.
|
136
|
+
|
137
|
+
* **:keep_root** => false
|
138
|
+
* Keep root element.
|
139
|
+
|
140
|
+
## Configuration
|
141
|
+
```
|
142
|
+
FastXML.configure do |config|
|
143
|
+
config.trim = true
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
## Benchmarks
|
148
|
+
|
149
|
+
Performance benchmark in comparison with some popular gems:
|
150
|
+
|
151
|
+
```
|
152
|
+
Converting Hash to XML:
|
153
|
+
user system total real
|
154
|
+
activesupport(rexml) 11.020000 0.000000 11.020000 ( 11.058084)
|
155
|
+
activesupport(libxml) 10.690000 0.000000 10.690000 ( 10.731521)
|
156
|
+
activesupport(nokogiri) 10.730000 0.010000 10.740000 ( 10.769866)
|
157
|
+
xmlsimple 1.470000 0.000000 1.470000 ( 1.477457)
|
158
|
+
fastxml 0.010000 0.000000 0.010000 ( 0.018434)
|
159
|
+
```
|
160
|
+
|
161
|
+
## License
|
162
|
+
|
163
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
164
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
extension_name = 'fastxml'
|
4
|
+
dir_config(extension_name)
|
5
|
+
|
6
|
+
puts ">>>>> Creating Makefile for #{RUBY_DESCRIPTION} <<<<<"
|
7
|
+
|
8
|
+
OPTS = Hash[
|
9
|
+
ARGV.map { |a| a =~ /^--with-(.+)(?:=(.*))?$/ ? [$1.to_sym, $2 || true] : nil }.compact
|
10
|
+
].freeze
|
11
|
+
|
12
|
+
if OPTS[:debug]
|
13
|
+
$CPPFLAGS += ' -g -Wall -Werror -Wextra -pedantic -std=c99 -DWITH_DEBUG -O0'
|
14
|
+
$CPPFLAGS += ' -DWITH_TRACE' if OPTS[:trace]
|
15
|
+
end
|
16
|
+
|
17
|
+
create_makefile(extension_name)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#include "fastxml.h"
|
2
|
+
|
3
|
+
#include "xh_config.h"
|
4
|
+
#include "xh_core.h"
|
5
|
+
|
6
|
+
void Init_fastxml();
|
7
|
+
|
8
|
+
VALUE xh_module;
|
9
|
+
VALUE xh_parse_error_class;
|
10
|
+
ID xh_id_next;
|
11
|
+
|
12
|
+
typedef struct {
|
13
|
+
int argc;
|
14
|
+
VALUE *argv;
|
15
|
+
xh_h2x_ctx_t *ctx;
|
16
|
+
} xh_h2x_arg_t;
|
17
|
+
|
18
|
+
static VALUE
|
19
|
+
hash2xml_exec(VALUE a) {
|
20
|
+
xh_h2x_arg_t *arg = (xh_h2x_arg_t *) a;
|
21
|
+
|
22
|
+
xh_h2x_init_ctx(arg->ctx, arg->argc, arg->argv);
|
23
|
+
|
24
|
+
return xh_h2x(arg->ctx);
|
25
|
+
}
|
26
|
+
|
27
|
+
static VALUE
|
28
|
+
hash2xml(int argc, VALUE *argv, VALUE self) {
|
29
|
+
xh_h2x_ctx_t ctx;
|
30
|
+
VALUE result;
|
31
|
+
int state;
|
32
|
+
xh_h2x_arg_t arg;
|
33
|
+
|
34
|
+
arg.argc = argc;
|
35
|
+
arg.argv = argv;
|
36
|
+
arg.ctx = &ctx;
|
37
|
+
|
38
|
+
result = rb_protect(hash2xml_exec, (VALUE) &arg, &state);
|
39
|
+
|
40
|
+
if (state) {
|
41
|
+
xh_h2x_destroy_ctx(&ctx);
|
42
|
+
rb_exc_raise(rb_errinfo());
|
43
|
+
}
|
44
|
+
|
45
|
+
if (ctx.opts.output != Qnil) result = Qnil;
|
46
|
+
|
47
|
+
xh_h2x_destroy_ctx(&ctx);
|
48
|
+
|
49
|
+
return result;
|
50
|
+
}
|
51
|
+
|
52
|
+
static VALUE
|
53
|
+
xml2hash(int argc, VALUE *argv, VALUE self) {
|
54
|
+
VALUE obj = Qnil;
|
55
|
+
|
56
|
+
return obj;
|
57
|
+
}
|
58
|
+
|
59
|
+
void Init_fastxml(void) {
|
60
|
+
xh_module = rb_define_module("FastXML");
|
61
|
+
xh_parse_error_class = rb_const_get_at(xh_module, rb_intern("ParseError"));
|
62
|
+
|
63
|
+
rb_define_module_function(xh_module, "hash2xml", hash2xml, -1);
|
64
|
+
rb_define_module_function(xh_module, "xml2hash", xml2hash, -1);
|
65
|
+
|
66
|
+
xh_id_next = rb_intern("next");
|
67
|
+
}
|
data/ext/fastxml/xh.c
ADDED
@@ -0,0 +1,338 @@
|
|
1
|
+
#include "xh_config.h"
|
2
|
+
#include "xh_core.h"
|
3
|
+
|
4
|
+
xh_bool_t
|
5
|
+
xh_init_opts(xh_opts_t *opts)
|
6
|
+
{
|
7
|
+
xh_char_t method[XH_PARAM_LEN];
|
8
|
+
|
9
|
+
XH_PARAM_READ_INIT
|
10
|
+
|
11
|
+
/* native options */
|
12
|
+
XH_PARAM_READ_STRING (opts->root, "@root");
|
13
|
+
XH_PARAM_READ_STRING (opts->version, "@version");
|
14
|
+
XH_PARAM_READ_STRING (opts->encoding, "@encoding");
|
15
|
+
XH_PARAM_READ_INT (opts->indent, "@indent");
|
16
|
+
XH_PARAM_READ_BOOL (opts->canonical, "@canonical");
|
17
|
+
XH_PARAM_READ_STRING (opts->content, "@content");
|
18
|
+
XH_PARAM_READ_BOOL (opts->utf8, "@utf8");
|
19
|
+
XH_PARAM_READ_BOOL (opts->xml_decl, "@xml_decl");
|
20
|
+
XH_PARAM_READ_BOOL (opts->keep_root, "@keep_root");
|
21
|
+
#ifdef XH_HAVE_DOM
|
22
|
+
XH_PARAM_READ_BOOL (opts->doc, "@doc");
|
23
|
+
#endif
|
24
|
+
XH_PARAM_READ_INT (opts->max_depth, "@max_depth");
|
25
|
+
XH_PARAM_READ_INT (opts->buf_size, "@buf_size");
|
26
|
+
XH_PARAM_READ_PATTERN(opts->force_array, "@force_array");
|
27
|
+
XH_PARAM_READ_BOOL (opts->force_content, "@force_content");
|
28
|
+
XH_PARAM_READ_BOOL (opts->merge_text, "@merge_text");
|
29
|
+
|
30
|
+
/* XML::Hash::LX options */
|
31
|
+
XH_PARAM_READ_STRING (opts->attr, "@attr");
|
32
|
+
opts->attr_len = xh_strlen(opts->attr);
|
33
|
+
XH_PARAM_READ_STRING (opts->text, "@text");
|
34
|
+
XH_PARAM_READ_BOOL (opts->trim, "@trim");
|
35
|
+
XH_PARAM_READ_STRING (opts->cdata, "@cdata");
|
36
|
+
XH_PARAM_READ_STRING (opts->comm, "@comm");
|
37
|
+
|
38
|
+
/* method */
|
39
|
+
XH_PARAM_READ_STRING (method, "@method");
|
40
|
+
XH_PARAM_READ_BOOL (opts->use_attr, "@use_attr");
|
41
|
+
if (xh_strcmp(method, XH_CHAR_CAST "LX") == 0) {
|
42
|
+
opts->method = XH_METHOD_LX;
|
43
|
+
}
|
44
|
+
else {
|
45
|
+
opts->method = XH_METHOD_NATIVE;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* output, NULL - to string */
|
49
|
+
XH_PARAM_READ_REF (opts->output, "@output");
|
50
|
+
|
51
|
+
return TRUE;
|
52
|
+
}
|
53
|
+
|
54
|
+
xh_opts_t *
|
55
|
+
xh_create_opts(void)
|
56
|
+
{
|
57
|
+
xh_opts_t *opts;
|
58
|
+
|
59
|
+
if ((opts = malloc(sizeof(xh_opts_t))) == NULL) {
|
60
|
+
return NULL;
|
61
|
+
}
|
62
|
+
memset(opts, 0, sizeof(xh_opts_t));
|
63
|
+
|
64
|
+
if (! xh_init_opts(opts)) {
|
65
|
+
xh_destroy_opts(opts);
|
66
|
+
return NULL;
|
67
|
+
}
|
68
|
+
|
69
|
+
return opts;
|
70
|
+
}
|
71
|
+
|
72
|
+
void
|
73
|
+
xh_destroy_opts(xh_opts_t *opts)
|
74
|
+
{
|
75
|
+
/* nothing */
|
76
|
+
}
|
77
|
+
|
78
|
+
void
|
79
|
+
xh_copy_opts(xh_opts_t *dst, xh_opts_t *src)
|
80
|
+
{
|
81
|
+
memcpy(dst, src, sizeof(xh_opts_t));
|
82
|
+
}
|
83
|
+
|
84
|
+
static int
|
85
|
+
xh_parse_arg(VALUE key, VALUE value, VALUE ctx)
|
86
|
+
{
|
87
|
+
xh_opts_t *opts = (xh_opts_t *) ctx;
|
88
|
+
xh_char_t *keyptr, *valueptr;
|
89
|
+
size_t keylen, valuelen;
|
90
|
+
|
91
|
+
if (SYMBOL_P(key)) {
|
92
|
+
key = rb_sym2str(key);
|
93
|
+
}
|
94
|
+
|
95
|
+
keyptr = XH_CHAR_CAST RSTRING_PTR(key);
|
96
|
+
keylen = RSTRING_LEN(key);
|
97
|
+
|
98
|
+
switch (keylen) {
|
99
|
+
case 2:
|
100
|
+
if (xh_str_equal2(keyptr, 'c', 'b')) {
|
101
|
+
VALUE v = rb_inspect(value);
|
102
|
+
rb_warn("cb: %s\n", StringValueCStr(v));
|
103
|
+
opts->cb = xh_param_assign_cb(value);
|
104
|
+
break;
|
105
|
+
}
|
106
|
+
goto error;
|
107
|
+
#ifdef XH_HAVE_DOM
|
108
|
+
case 3:
|
109
|
+
if (xh_str_equal3(keyptr, 'd', 'o', 'c')) {
|
110
|
+
opts->doc = xh_param_assign_bool(value);
|
111
|
+
break;
|
112
|
+
}
|
113
|
+
goto error;
|
114
|
+
#endif
|
115
|
+
case 4:
|
116
|
+
if (xh_str_equal4(keyptr, 'a', 't', 't', 'r')) {
|
117
|
+
xh_param_assign_string(opts->attr, value);
|
118
|
+
if (opts->attr[0] == '\0') {
|
119
|
+
opts->attr_len = 0;
|
120
|
+
}
|
121
|
+
else {
|
122
|
+
opts->attr_len = xh_strlen(opts->attr);
|
123
|
+
}
|
124
|
+
break;
|
125
|
+
}
|
126
|
+
if (xh_str_equal4(keyptr, 'c', 'o', 'm', 'm')) {
|
127
|
+
xh_param_assign_string(opts->comm, value);
|
128
|
+
break;
|
129
|
+
}
|
130
|
+
if (xh_str_equal4(keyptr, 'r', 'o', 'o', 't')) {
|
131
|
+
xh_param_assign_string(opts->root, value);
|
132
|
+
break;
|
133
|
+
}
|
134
|
+
if (xh_str_equal4(keyptr, 't', 'r', 'i', 'm')) {
|
135
|
+
opts->trim = xh_param_assign_bool(value);
|
136
|
+
break;
|
137
|
+
}
|
138
|
+
if (xh_str_equal4(keyptr, 't', 'e', 'x', 't')) {
|
139
|
+
xh_param_assign_string(opts->text, value);
|
140
|
+
break;
|
141
|
+
}
|
142
|
+
if (xh_str_equal4(keyptr, 'u', 't', 'f', '8')) {
|
143
|
+
opts->utf8 = xh_param_assign_bool(value);
|
144
|
+
break;
|
145
|
+
}
|
146
|
+
goto error;
|
147
|
+
case 5:
|
148
|
+
if (xh_str_equal5(keyptr, 'c', 'd', 'a', 't', 'a')) {
|
149
|
+
xh_param_assign_string(opts->cdata, value);
|
150
|
+
break;
|
151
|
+
}
|
152
|
+
goto error;
|
153
|
+
case 6:
|
154
|
+
if (xh_str_equal6(keyptr, 'i', 'n', 'd', 'e', 'n', 't')) {
|
155
|
+
xh_param_assign_int(keyptr, &opts->indent, value);
|
156
|
+
break;
|
157
|
+
}
|
158
|
+
if (xh_str_equal6(keyptr, 'm', 'e', 't', 'h', 'o', 'd')) {
|
159
|
+
if (value == Qnil) {
|
160
|
+
rb_raise(rb_eArgError, "Parameter '%s' is undefined", StringValueCStr(key));
|
161
|
+
}
|
162
|
+
valueptr = XH_CHAR_CAST RSTRING_PTR(value);
|
163
|
+
valuelen = RSTRING_LEN(value);
|
164
|
+
switch (valuelen) {
|
165
|
+
case 6:
|
166
|
+
if (xh_str_equal6(valueptr, 'N', 'A', 'T', 'I', 'V', 'E')) {
|
167
|
+
opts->method = XH_METHOD_NATIVE;
|
168
|
+
break;
|
169
|
+
}
|
170
|
+
goto error_value;
|
171
|
+
case 2:
|
172
|
+
if (valueptr[0] == 'L' && valueptr[1] == 'X') {
|
173
|
+
opts->method = XH_METHOD_LX;
|
174
|
+
break;
|
175
|
+
}
|
176
|
+
goto error_value;
|
177
|
+
default:
|
178
|
+
goto error_value;
|
179
|
+
}
|
180
|
+
break;
|
181
|
+
}
|
182
|
+
if (xh_str_equal6(keyptr, 'o', 'u', 't', 'p', 'u', 't')) {
|
183
|
+
if ( RTEST(value) ) {
|
184
|
+
opts->output = value;
|
185
|
+
}
|
186
|
+
else {
|
187
|
+
opts->output = Qnil;
|
188
|
+
}
|
189
|
+
break;
|
190
|
+
}
|
191
|
+
if (xh_str_equal6(keyptr, 'f', 'i', 'l', 't', 'e', 'r')) {
|
192
|
+
xh_param_assign_filter(&opts->filter, value);
|
193
|
+
break;
|
194
|
+
}
|
195
|
+
goto error;
|
196
|
+
case 7:
|
197
|
+
if (xh_str_equal7(keyptr, 'c', 'o', 'n', 't', 'e', 'n', 't')) {
|
198
|
+
xh_param_assign_string(opts->content, value);
|
199
|
+
break;
|
200
|
+
}
|
201
|
+
if (xh_str_equal7(keyptr, 'v', 'e', 'r', 's', 'i', 'o', 'n')) {
|
202
|
+
xh_param_assign_string(opts->version, value);
|
203
|
+
break;
|
204
|
+
}
|
205
|
+
goto error;
|
206
|
+
case 8:
|
207
|
+
if (xh_str_equal8(keyptr, 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g')) {
|
208
|
+
xh_param_assign_string(opts->encoding, value);
|
209
|
+
break;
|
210
|
+
}
|
211
|
+
if (xh_str_equal8(keyptr, 'u', 's', 'e', '_', 'a', 't', 't', 'r')) {
|
212
|
+
opts->use_attr = xh_param_assign_bool(value);
|
213
|
+
break;
|
214
|
+
}
|
215
|
+
if (xh_str_equal8(keyptr, 'x', 'm', 'l', '_', 'd', 'e', 'c', 'l')) {
|
216
|
+
opts->xml_decl = xh_param_assign_bool(value);
|
217
|
+
break;
|
218
|
+
}
|
219
|
+
if (xh_str_equal8(keyptr, 'b', 'u', 'f', '_', 's', 'i', 'z', 'e')) {
|
220
|
+
xh_param_assign_int(keyptr, &opts->buf_size, value);
|
221
|
+
break;
|
222
|
+
}
|
223
|
+
goto error;
|
224
|
+
case 9:
|
225
|
+
if (xh_str_equal9(keyptr, 'c', 'a', 'n', 'o', 'n', 'i', 'c', 'a', 'l')) {
|
226
|
+
opts->canonical = xh_param_assign_bool(value);
|
227
|
+
break;
|
228
|
+
}
|
229
|
+
if (xh_str_equal9(keyptr, 'm', 'a', 'x', '_', 'd', 'e', 'p', 't', 'h')) {
|
230
|
+
xh_param_assign_int(keyptr, &opts->max_depth, value);
|
231
|
+
break;
|
232
|
+
}
|
233
|
+
if (xh_str_equal9(keyptr, 'k', 'e', 'e', 'p', '_', 'r', 'o', 'o', 't')) {
|
234
|
+
opts->keep_root = xh_param_assign_bool(value);
|
235
|
+
break;
|
236
|
+
}
|
237
|
+
goto error;
|
238
|
+
case 10:
|
239
|
+
if (xh_str_equal10(keyptr, 'm', 'e', 'r', 'g', 'e', '_', 't', 'e', 'x', 't')) {
|
240
|
+
opts->merge_text = xh_param_assign_bool(value);
|
241
|
+
break;
|
242
|
+
}
|
243
|
+
case 11:
|
244
|
+
if (xh_str_equal11(keyptr, 'f', 'o', 'r', 'c', 'e', '_', 'a', 'r', 'r', 'a', 'y')) {
|
245
|
+
xh_param_assign_pattern(&opts->force_array, value);
|
246
|
+
break;
|
247
|
+
}
|
248
|
+
case 13:
|
249
|
+
if (xh_str_equal13(keyptr, 'f', 'o', 'r', 'c', 'e', '_', 'c', 'o', 'n', 't', 'e', 'n', 't')) {
|
250
|
+
opts->force_content = xh_param_assign_bool(value);
|
251
|
+
break;
|
252
|
+
}
|
253
|
+
default:
|
254
|
+
goto error;
|
255
|
+
}
|
256
|
+
|
257
|
+
return ST_CONTINUE;
|
258
|
+
|
259
|
+
error_value:
|
260
|
+
rb_raise(rb_eArgError, "Invalid parameter value for '%s': %s", StringValueCStr(key), StringValueCStr(value));
|
261
|
+
|
262
|
+
error:
|
263
|
+
rb_raise(rb_eArgError, "Invalid parameter '%s'", StringValueCStr(key));
|
264
|
+
}
|
265
|
+
|
266
|
+
void
|
267
|
+
xh_parse_args(xh_opts_t *opts, xh_int_t *nparam, xh_int_t argc, VALUE *argv)
|
268
|
+
{
|
269
|
+
VALUE hash;
|
270
|
+
|
271
|
+
if (*nparam >= argc)
|
272
|
+
return;
|
273
|
+
|
274
|
+
hash = argv[*nparam];
|
275
|
+
if (rb_cHash != rb_obj_class(hash))
|
276
|
+
rb_raise(rb_eArgError, "Parameter is not a hash");
|
277
|
+
|
278
|
+
(*nparam)++;
|
279
|
+
|
280
|
+
rb_hash_foreach(hash, xh_parse_arg, (VALUE) opts);
|
281
|
+
}
|
282
|
+
|
283
|
+
void *
|
284
|
+
xh_get_obj_param(xh_int_t *nparam, xh_int_t argc, VALUE *argv, const char *class)
|
285
|
+
{
|
286
|
+
void *obj = NULL;
|
287
|
+
/*
|
288
|
+
SV *param;
|
289
|
+
|
290
|
+
if (*nparam >= items)
|
291
|
+
rb_raise(rb_eArgError, "Invalid parameters");
|
292
|
+
|
293
|
+
param = ST(*nparam);
|
294
|
+
if ( sv_derived_from(param, class) ) {
|
295
|
+
if ( sv_isobject(param) ) {
|
296
|
+
// reference to object
|
297
|
+
IV tmp = SvIV((SV *) SvRV(param));
|
298
|
+
obj = INT2PTR(xh_opts_t *, tmp);
|
299
|
+
}
|
300
|
+
(*nparam)++;
|
301
|
+
}
|
302
|
+
*/
|
303
|
+
return obj;
|
304
|
+
}
|
305
|
+
|
306
|
+
VALUE
|
307
|
+
xh_get_hash_param(xh_int_t *nparam, xh_int_t argc, VALUE *argv)
|
308
|
+
{
|
309
|
+
VALUE param;
|
310
|
+
|
311
|
+
if (*nparam >= argc)
|
312
|
+
rb_raise(rb_eArgError, "Invalid parameters");
|
313
|
+
|
314
|
+
param = argv[*nparam];
|
315
|
+
if (rb_cHash != rb_obj_class(param))
|
316
|
+
rb_raise(rb_eArgError, "Parameter is not a hash");
|
317
|
+
|
318
|
+
(*nparam)++;
|
319
|
+
|
320
|
+
return param;
|
321
|
+
}
|
322
|
+
|
323
|
+
void
|
324
|
+
xh_merge_opts(xh_opts_t *ctx_opts, xh_opts_t *opts, xh_int_t *nparam, xh_int_t argc, VALUE *argv)
|
325
|
+
{
|
326
|
+
if (opts == NULL) {
|
327
|
+
/* read global options */
|
328
|
+
xh_init_opts(ctx_opts);
|
329
|
+
}
|
330
|
+
else {
|
331
|
+
/* copy options from object */
|
332
|
+
xh_copy_opts(ctx_opts, opts);
|
333
|
+
}
|
334
|
+
if (*nparam < argc) {
|
335
|
+
xh_parse_args(ctx_opts, nparam, argc, argv);
|
336
|
+
}
|
337
|
+
}
|
338
|
+
|