ox 1.5.7 → 1.5.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ox might be problematic. Click here for more details.
- data/README.md +2 -2
- data/ext/ox/gen_load.c +44 -24
- data/ext/ox/obj_load.c +10 -10
- data/ext/ox/ox.c +249 -237
- data/ext/ox/ox.h +113 -113
- data/ext/ox/parse.c +5 -6
- data/lib/ox/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -30,9 +30,9 @@ A fast XML parser and Object marshaller as a Ruby gem.
|
|
30
30
|
|
31
31
|
## <a name="release">Release Notes</a>
|
32
32
|
|
33
|
-
### Release 1.5.
|
33
|
+
### Release 1.5.8
|
34
34
|
|
35
|
-
-
|
35
|
+
- Added an option to not symbolize attribute keys in generic parsing.
|
36
36
|
|
37
37
|
## <a name="description">Description</a>
|
38
38
|
|
data/ext/ox/gen_load.c
CHANGED
@@ -114,23 +114,34 @@ create_prolog_doc(PInfo pi, const char *target, Attr attrs) {
|
|
114
114
|
doc = rb_obj_alloc(ox_document_clas);
|
115
115
|
ah = rb_hash_new();
|
116
116
|
for (; 0 != attrs->name; attrs++) {
|
117
|
+
if (Yes == pi->options->sym_keys) {
|
117
118
|
#if HAS_ENCODING_SUPPORT
|
118
|
-
|
119
|
-
|
119
|
+
if (0 != pi->encoding) {
|
120
|
+
VALUE rstr = rb_str_new2(attrs->name);
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
122
|
+
rb_enc_associate(rstr, pi->encoding);
|
123
|
+
sym = rb_funcall(rstr, ox_to_sym_id, 0);
|
124
|
+
} else {
|
125
|
+
sym = ID2SYM(rb_intern(attrs->name));
|
126
|
+
}
|
126
127
|
#else
|
127
|
-
|
128
|
+
sym = ID2SYM(rb_intern(attrs->name));
|
128
129
|
#endif
|
129
|
-
|
130
|
+
rb_hash_aset(ah, sym, rb_str_new2(attrs->value));
|
131
|
+
} else {
|
132
|
+
VALUE rstr = rb_str_new2(attrs->name);
|
133
|
+
|
130
134
|
#if HAS_ENCODING_SUPPORT
|
131
|
-
|
132
|
-
|
133
|
-
|
135
|
+
if (0 != pi->encoding) {
|
136
|
+
rb_enc_associate(rstr, pi->encoding);
|
137
|
+
}
|
138
|
+
#endif
|
139
|
+
rb_hash_aset(ah, rstr, rb_str_new2(attrs->value));
|
140
|
+
}
|
141
|
+
#if HAS_ENCODING_SUPPORT
|
142
|
+
if (0 == strcmp("encoding", attrs->name)) {
|
143
|
+
pi->encoding = rb_enc_find(attrs->value);
|
144
|
+
}
|
134
145
|
#endif
|
135
146
|
}
|
136
147
|
nodes = rb_ary_new();
|
@@ -154,7 +165,7 @@ instruct(PInfo pi, const char *target, Attr attrs) {
|
|
154
165
|
// ignore other instructions
|
155
166
|
}
|
156
167
|
} else {
|
157
|
-
if (TRACE <= pi->trace) {
|
168
|
+
if (TRACE <= pi->options->trace) {
|
158
169
|
printf("Processing instruction %s ignored.\n", target);
|
159
170
|
}
|
160
171
|
}
|
@@ -187,7 +198,7 @@ nomode_instruct(PInfo pi, const char *target, Attr attrs) {
|
|
187
198
|
}
|
188
199
|
}
|
189
200
|
} else {
|
190
|
-
if (TRACE <= pi->trace) {
|
201
|
+
if (TRACE <= pi->options->trace) {
|
191
202
|
printf("Processing instruction %s ignored.\n", target);
|
192
203
|
}
|
193
204
|
}
|
@@ -278,21 +289,30 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
|
|
278
289
|
VALUE sym;
|
279
290
|
VALUE *slot;
|
280
291
|
|
281
|
-
|
292
|
+
if (Yes == pi->options->sym_keys) {
|
293
|
+
if (Qundef == (sym = ox_cache_get(ox_symbol_cache, attrs->name, &slot))) {
|
282
294
|
#if HAS_ENCODING_SUPPORT
|
283
|
-
|
284
|
-
|
295
|
+
if (0 != pi->encoding) {
|
296
|
+
VALUE rstr = rb_str_new2(attrs->name);
|
285
297
|
|
286
|
-
|
287
|
-
|
288
|
-
|
298
|
+
rb_enc_associate(rstr, pi->encoding);
|
299
|
+
sym = rb_funcall(rstr, ox_to_sym_id, 0);
|
300
|
+
} else {
|
301
|
+
sym = ID2SYM(rb_intern(attrs->name));
|
302
|
+
}
|
303
|
+
#else
|
289
304
|
sym = ID2SYM(rb_intern(attrs->name));
|
305
|
+
#endif
|
306
|
+
*slot = sym;
|
307
|
+
}
|
308
|
+
} else {
|
309
|
+
sym = rb_str_new2(attrs->name);
|
310
|
+
#if HAS_ENCODING_SUPPORT
|
311
|
+
if (0 != pi->encoding) {
|
312
|
+
rb_enc_associate(sym, pi->encoding);
|
290
313
|
}
|
291
|
-
#else
|
292
|
-
sym = ID2SYM(rb_intern(attrs->name));
|
293
314
|
#endif
|
294
|
-
|
295
|
-
}
|
315
|
+
}
|
296
316
|
s = rb_str_new2(attrs->value);
|
297
317
|
#if HAS_ENCODING_SUPPORT
|
298
318
|
if (0 != pi->encoding) {
|
data/ext/ox/obj_load.c
CHANGED
@@ -237,7 +237,7 @@ classname2class(const char *name, PInfo pi, VALUE base_class) {
|
|
237
237
|
if (':' != *n) {
|
238
238
|
raise_error("Invalid classname, expected another ':'", pi->str, pi->s);
|
239
239
|
}
|
240
|
-
if (Qundef == (clas = resolve_classname(clas, class_name, pi->effort, base_class))) {
|
240
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
|
241
241
|
return Qundef;
|
242
242
|
}
|
243
243
|
s = class_name;
|
@@ -246,7 +246,7 @@ classname2class(const char *name, PInfo pi, VALUE base_class) {
|
|
246
246
|
}
|
247
247
|
}
|
248
248
|
*s = '\0';
|
249
|
-
if (Qundef != (clas = resolve_classname(clas, class_name, pi->effort, base_class))) {
|
249
|
+
if (Qundef != (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
|
250
250
|
*slot = clas;
|
251
251
|
}
|
252
252
|
}
|
@@ -411,7 +411,7 @@ add_text(PInfo pi, char *text, int closed) {
|
|
411
411
|
if (!closed) {
|
412
412
|
raise_error("Text not closed", pi->str, pi->s);
|
413
413
|
}
|
414
|
-
if (DEBUG <= pi->trace) {
|
414
|
+
if (DEBUG <= pi->options->trace) {
|
415
415
|
char indent[128];
|
416
416
|
|
417
417
|
fill_indent(pi, indent, sizeof(indent));
|
@@ -540,7 +540,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
|
|
540
540
|
Helper h;
|
541
541
|
unsigned long id;
|
542
542
|
|
543
|
-
if (TRACE <= pi->trace) {
|
543
|
+
if (TRACE <= pi->options->trace) {
|
544
544
|
char buf[1024];
|
545
545
|
char indent[128];
|
546
546
|
char *s = buf;
|
@@ -552,7 +552,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
|
|
552
552
|
}
|
553
553
|
*s++ = '>';
|
554
554
|
*s++ = '\0';
|
555
|
-
if (DEBUG <= pi->trace) {
|
555
|
+
if (DEBUG <= pi->options->trace) {
|
556
556
|
debug_stack(pi, buf);
|
557
557
|
} else {
|
558
558
|
fill_indent(pi, indent, sizeof(indent));
|
@@ -627,7 +627,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
|
|
627
627
|
break;
|
628
628
|
case RawCode:
|
629
629
|
if (hasChildren) {
|
630
|
-
h->obj = ox_parse(pi->s, ox_gen_callbacks, &pi->s, pi->
|
630
|
+
h->obj = ox_parse(pi->s, ox_gen_callbacks, &pi->s, pi->options);
|
631
631
|
if (0 != pi->circ_array) {
|
632
632
|
circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
|
633
633
|
}
|
@@ -673,17 +673,17 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
|
|
673
673
|
raise_error("Invalid element name", pi->str, pi->s);
|
674
674
|
break;
|
675
675
|
}
|
676
|
-
if (DEBUG <= pi->trace) {
|
676
|
+
if (DEBUG <= pi->options->trace) {
|
677
677
|
debug_stack(pi, " -----------");
|
678
678
|
}
|
679
679
|
}
|
680
680
|
|
681
681
|
static void
|
682
682
|
end_element(PInfo pi, const char *ename) {
|
683
|
-
if (TRACE <= pi->trace) {
|
683
|
+
if (TRACE <= pi->options->trace) {
|
684
684
|
char indent[128];
|
685
685
|
|
686
|
-
if (DEBUG <= pi->trace) {
|
686
|
+
if (DEBUG <= pi->options->trace) {
|
687
687
|
char buf[1024];
|
688
688
|
|
689
689
|
snprintf(buf, sizeof(buf) - 1, "</%s>", ename);
|
@@ -779,7 +779,7 @@ end_element(PInfo pi, const char *ename) {
|
|
779
779
|
circ_array_free(pi->circ_array);
|
780
780
|
pi->circ_array = 0;
|
781
781
|
}
|
782
|
-
if (DEBUG <= pi->trace) {
|
782
|
+
if (DEBUG <= pi->options->trace) {
|
783
783
|
debug_stack(pi, " ----------");
|
784
784
|
}
|
785
785
|
}
|
data/ext/ox/ox.c
CHANGED
@@ -40,13 +40,13 @@
|
|
40
40
|
#define SMALL_XML 65536
|
41
41
|
|
42
42
|
typedef struct _YesNoOpt {
|
43
|
-
VALUE
|
44
|
-
char
|
43
|
+
VALUE sym;
|
44
|
+
char *attr;
|
45
45
|
} *YesNoOpt;
|
46
46
|
|
47
47
|
void Init_ox();
|
48
48
|
|
49
|
-
VALUE
|
49
|
+
VALUE Ox = Qnil;
|
50
50
|
|
51
51
|
ID ox_at_id;
|
52
52
|
ID ox_at_value_id;
|
@@ -86,66 +86,68 @@ ID ox_tv_nsec_id;
|
|
86
86
|
ID ox_tv_usec_id;
|
87
87
|
ID ox_value_id;
|
88
88
|
|
89
|
-
VALUE
|
89
|
+
VALUE ox_encoding_sym;
|
90
90
|
|
91
|
-
VALUE
|
92
|
-
VALUE
|
91
|
+
VALUE ox_empty_string;
|
92
|
+
VALUE ox_zero_fixnum;
|
93
93
|
|
94
|
-
VALUE
|
95
|
-
VALUE
|
96
|
-
VALUE
|
97
|
-
VALUE
|
98
|
-
VALUE
|
99
|
-
VALUE
|
100
|
-
VALUE
|
101
|
-
VALUE
|
102
|
-
VALUE
|
94
|
+
VALUE ox_cdata_clas;
|
95
|
+
VALUE ox_comment_clas;
|
96
|
+
VALUE ox_doctype_clas;
|
97
|
+
VALUE ox_document_clas;
|
98
|
+
VALUE ox_element_clas;
|
99
|
+
VALUE ox_bag_clas;
|
100
|
+
VALUE ox_struct_class;
|
101
|
+
VALUE ox_time_class;
|
102
|
+
VALUE ox_date_class;
|
103
103
|
VALUE ox_stringio_class;
|
104
104
|
|
105
|
-
Cache
|
106
|
-
Cache
|
107
|
-
Cache
|
105
|
+
Cache ox_symbol_cache = 0;
|
106
|
+
Cache ox_class_cache = 0;
|
107
|
+
Cache ox_attr_cache = 0;
|
108
108
|
|
109
|
-
static VALUE
|
110
|
-
static VALUE opt_format_sym;
|
111
|
-
static VALUE circular_sym;
|
112
|
-
static VALUE mode_sym;
|
109
|
+
static VALUE auto_define_sym;
|
113
110
|
static VALUE auto_sym;
|
114
|
-
static VALUE
|
115
|
-
static VALUE
|
111
|
+
static VALUE circular_sym;
|
112
|
+
static VALUE convert_special_sym;
|
113
|
+
static VALUE effort_sym;
|
116
114
|
static VALUE generic_sym;
|
115
|
+
static VALUE indent_sym;
|
117
116
|
static VALUE limited_sym;
|
117
|
+
static VALUE mode_sym;
|
118
|
+
static VALUE object_sym;
|
119
|
+
static VALUE opt_format_sym;
|
120
|
+
static VALUE optimized_sym;
|
121
|
+
static VALUE strict_sym;
|
118
122
|
static VALUE strict_sym;
|
123
|
+
static VALUE symbolize_keys_sym;
|
119
124
|
static VALUE tolerant_sym;
|
120
|
-
static VALUE effort_sym;
|
121
|
-
static VALUE auto_define_sym;
|
122
125
|
static VALUE trace_sym;
|
123
|
-
static VALUE strict_sym;
|
124
126
|
static VALUE with_dtd_sym;
|
125
127
|
static VALUE with_instruct_sym;
|
126
|
-
static VALUE convert_special_sym;
|
127
128
|
static VALUE with_xml_sym;
|
128
|
-
static VALUE
|
129
|
+
static VALUE xsd_date_sym;
|
129
130
|
|
130
|
-
struct _Options
|
131
|
-
{ '\0' },
|
132
|
-
2,
|
133
|
-
0,
|
134
|
-
No,
|
135
|
-
No,
|
136
|
-
No,
|
137
|
-
No,
|
138
|
-
No,
|
139
|
-
NoMode,
|
140
|
-
StrictEffort,
|
131
|
+
struct _Options ox_default_options = {
|
132
|
+
{ '\0' }, // encoding
|
133
|
+
2, // indent
|
134
|
+
0, // trace
|
135
|
+
No, // with_dtd
|
136
|
+
No, // with_xml
|
137
|
+
No, // with_instruct
|
138
|
+
No, // circular
|
139
|
+
No, // xsd_date
|
140
|
+
NoMode, // mode
|
141
|
+
StrictEffort, // effort
|
142
|
+
Yes // sym_keys
|
141
143
|
};
|
142
144
|
|
143
|
-
extern ParseCallbacks
|
144
|
-
extern ParseCallbacks
|
145
|
-
extern ParseCallbacks
|
146
|
-
extern ParseCallbacks
|
145
|
+
extern ParseCallbacks ox_obj_callbacks;
|
146
|
+
extern ParseCallbacks ox_gen_callbacks;
|
147
|
+
extern ParseCallbacks ox_limited_callbacks;
|
148
|
+
extern ParseCallbacks ox_nomode_callbacks;
|
147
149
|
|
148
|
-
static void
|
150
|
+
static void parse_dump_options(VALUE ropts, Options copts);
|
149
151
|
|
150
152
|
/* call-seq: ox_default_options() => Hash
|
151
153
|
*
|
@@ -160,12 +162,13 @@ static void parse_dump_options(VALUE ropts, Options copts);
|
|
160
162
|
* - xsd_date: [true|false|nil] use XSD date format instead of decimal format
|
161
163
|
* - mode: [:object|:generic|:limited|nil] load method to use for XML
|
162
164
|
* - effort: [:strict|:tolerant|:auto_define] set the tolerance level for loading
|
165
|
+
* - symbolize_keys: [true|false|nil] symbolize element attribute keys or leave as Strings
|
163
166
|
* @return [Hash] all current option settings.
|
164
167
|
*/
|
165
168
|
static VALUE
|
166
169
|
get_def_opts(VALUE self) {
|
167
|
-
VALUE
|
168
|
-
int
|
170
|
+
VALUE opts = rb_hash_new();
|
171
|
+
int elen = (int)strlen(ox_default_options.encoding);
|
169
172
|
|
170
173
|
rb_hash_aset(opts, ox_encoding_sym, (0 == elen) ? Qnil : rb_str_new(ox_default_options.encoding, elen));
|
171
174
|
rb_hash_aset(opts, indent_sym, INT2FIX(ox_default_options.indent));
|
@@ -175,19 +178,20 @@ get_def_opts(VALUE self) {
|
|
175
178
|
rb_hash_aset(opts, with_instruct_sym, (Yes == ox_default_options.with_instruct) ? Qtrue : ((No == ox_default_options.with_instruct) ? Qfalse : Qnil));
|
176
179
|
rb_hash_aset(opts, circular_sym, (Yes == ox_default_options.circular) ? Qtrue : ((No == ox_default_options.circular) ? Qfalse : Qnil));
|
177
180
|
rb_hash_aset(opts, xsd_date_sym, (Yes == ox_default_options.xsd_date) ? Qtrue : ((No == ox_default_options.xsd_date) ? Qfalse : Qnil));
|
181
|
+
rb_hash_aset(opts, symbolize_keys_sym, (Yes == ox_default_options.sym_keys) ? Qtrue : ((No == ox_default_options.sym_keys) ? Qfalse : Qnil));
|
178
182
|
switch (ox_default_options.mode) {
|
179
|
-
case ObjMode:
|
180
|
-
case GenMode:
|
181
|
-
case LimMode:
|
183
|
+
case ObjMode: rb_hash_aset(opts, mode_sym, object_sym); break;
|
184
|
+
case GenMode: rb_hash_aset(opts, mode_sym, generic_sym); break;
|
185
|
+
case LimMode: rb_hash_aset(opts, mode_sym, limited_sym); break;
|
182
186
|
case NoMode:
|
183
|
-
default:
|
187
|
+
default: rb_hash_aset(opts, mode_sym, Qnil); break;
|
184
188
|
}
|
185
189
|
switch (ox_default_options.effort) {
|
186
|
-
case StrictEffort:
|
187
|
-
case TolerantEffort:
|
188
|
-
case AutoEffort:
|
190
|
+
case StrictEffort: rb_hash_aset(opts, effort_sym, strict_sym); break;
|
191
|
+
case TolerantEffort: rb_hash_aset(opts, effort_sym, tolerant_sym); break;
|
192
|
+
case AutoEffort: rb_hash_aset(opts, effort_sym, auto_define_sym); break;
|
189
193
|
case NoEffort:
|
190
|
-
default:
|
194
|
+
default: rb_hash_aset(opts, effort_sym, Qnil); break;
|
191
195
|
}
|
192
196
|
return opts;
|
193
197
|
}
|
@@ -206,79 +210,81 @@ get_def_opts(VALUE self) {
|
|
206
210
|
* @param [true|false|nil] :xsd_date use XSD date format instead of decimal format
|
207
211
|
* @param [:object|:generic|:limited|nil] :mode load method to use for XML
|
208
212
|
* @param [:strict|:tolerant|:auto_define] :effort set the tolerance level for loading
|
213
|
+
* @param [true|false|nil] :symbolize_keys symbolize element attribute keys or leave as Strings
|
209
214
|
* @return [nil]
|
210
215
|
*/
|
211
216
|
static VALUE
|
212
217
|
set_def_opts(VALUE self, VALUE opts) {
|
213
|
-
struct _YesNoOpt
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
218
|
+
struct _YesNoOpt ynos[] = {
|
219
|
+
{ with_xml_sym, &ox_default_options.with_xml },
|
220
|
+
{ with_dtd_sym, &ox_default_options.with_dtd },
|
221
|
+
{ with_instruct_sym, &ox_default_options.with_instruct },
|
222
|
+
{ xsd_date_sym, &ox_default_options.xsd_date },
|
223
|
+
{ circular_sym, &ox_default_options.circular },
|
224
|
+
{ symbolize_keys_sym, &ox_default_options.sym_keys },
|
225
|
+
{ Qnil, 0 }
|
220
226
|
};
|
221
|
-
YesNoOpt
|
222
|
-
VALUE
|
227
|
+
YesNoOpt o;
|
228
|
+
VALUE v;
|
223
229
|
|
224
230
|
Check_Type(opts, T_HASH);
|
225
231
|
|
226
232
|
v = rb_hash_aref(opts, ox_encoding_sym);
|
227
233
|
if (Qnil == v) {
|
228
|
-
|
234
|
+
*ox_default_options.encoding = '\0';
|
229
235
|
} else {
|
230
|
-
|
231
|
-
|
236
|
+
Check_Type(v, T_STRING);
|
237
|
+
strncpy(ox_default_options.encoding, StringValuePtr(v), sizeof(ox_default_options.encoding) - 1);
|
232
238
|
}
|
233
239
|
|
234
240
|
v = rb_hash_aref(opts, indent_sym);
|
235
241
|
if (Qnil != v) {
|
236
|
-
|
237
|
-
|
242
|
+
Check_Type(v, T_FIXNUM);
|
243
|
+
ox_default_options.indent = FIX2INT(v);
|
238
244
|
}
|
239
245
|
|
240
246
|
v = rb_hash_aref(opts, trace_sym);
|
241
247
|
if (Qnil != v) {
|
242
|
-
|
243
|
-
|
248
|
+
Check_Type(v, T_FIXNUM);
|
249
|
+
ox_default_options.trace = FIX2INT(v);
|
244
250
|
}
|
245
251
|
|
246
252
|
v = rb_hash_aref(opts, mode_sym);
|
247
253
|
if (Qnil == v) {
|
248
|
-
|
254
|
+
ox_default_options.mode = NoMode;
|
249
255
|
} else if (object_sym == v) {
|
250
|
-
|
256
|
+
ox_default_options.mode = ObjMode;
|
251
257
|
} else if (generic_sym == v) {
|
252
|
-
|
258
|
+
ox_default_options.mode = GenMode;
|
253
259
|
} else if (limited_sym == v) {
|
254
|
-
|
260
|
+
ox_default_options.mode = LimMode;
|
255
261
|
} else {
|
256
|
-
|
262
|
+
rb_raise(rb_eArgError, ":mode must be :object, :generic, :limited, or nil.\n");
|
257
263
|
}
|
258
264
|
|
259
265
|
v = rb_hash_aref(opts, effort_sym);
|
260
266
|
if (Qnil == v) {
|
261
|
-
|
267
|
+
ox_default_options.effort = NoEffort;
|
262
268
|
} else if (strict_sym == v) {
|
263
|
-
|
269
|
+
ox_default_options.effort = StrictEffort;
|
264
270
|
} else if (tolerant_sym == v) {
|
265
|
-
|
271
|
+
ox_default_options.effort = TolerantEffort;
|
266
272
|
} else if (auto_define_sym == v) {
|
267
|
-
|
273
|
+
ox_default_options.effort = AutoEffort;
|
268
274
|
} else {
|
269
|
-
|
275
|
+
rb_raise(rb_eArgError, ":effort must be :strict, :tolerant, :auto_define, or nil.\n");
|
270
276
|
}
|
271
277
|
for (o = ynos; 0 != o->attr; o++) {
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
278
|
+
v = rb_hash_lookup(opts, o->sym);
|
279
|
+
if (Qnil == v) {
|
280
|
+
*o->attr = NotSet;
|
281
|
+
} else if (Qtrue == v) {
|
282
|
+
*o->attr = Yes;
|
283
|
+
} else if (Qfalse == v) {
|
284
|
+
*o->attr = No;
|
285
|
+
} else {
|
280
286
|
rb_raise(rb_eArgError, "%s must be true or false.\n", rb_id2name(SYM2ID(o->sym)));
|
281
|
-
|
287
|
+
}
|
282
288
|
}
|
283
289
|
return Qnil;
|
284
290
|
}
|
@@ -295,7 +301,7 @@ set_def_opts(VALUE self, VALUE opts) {
|
|
295
301
|
*/
|
296
302
|
static VALUE
|
297
303
|
to_obj(VALUE self, VALUE ruby_xml) {
|
298
|
-
char
|
304
|
+
char *xml;
|
299
305
|
size_t len;
|
300
306
|
VALUE obj;
|
301
307
|
|
@@ -308,7 +314,7 @@ to_obj(VALUE self, VALUE ruby_xml) {
|
|
308
314
|
xml = ALLOCA_N(char, len);
|
309
315
|
}
|
310
316
|
strcpy(xml, StringValuePtr(ruby_xml));
|
311
|
-
obj = ox_parse(xml, ox_obj_callbacks, 0,
|
317
|
+
obj = ox_parse(xml, ox_obj_callbacks, 0, &ox_default_options);
|
312
318
|
if (SMALL_XML < len) {
|
313
319
|
xfree(xml);
|
314
320
|
}
|
@@ -324,9 +330,9 @@ to_obj(VALUE self, VALUE ruby_xml) {
|
|
324
330
|
*/
|
325
331
|
static VALUE
|
326
332
|
to_gen(VALUE self, VALUE ruby_xml) {
|
327
|
-
char
|
328
|
-
size_t
|
329
|
-
VALUE
|
333
|
+
char *xml;
|
334
|
+
size_t len;
|
335
|
+
VALUE obj;
|
330
336
|
|
331
337
|
Check_Type(ruby_xml, T_STRING);
|
332
338
|
// the xml string gets modified so make a copy of it
|
@@ -337,7 +343,7 @@ to_gen(VALUE self, VALUE ruby_xml) {
|
|
337
343
|
xml = ALLOCA_N(char, len);
|
338
344
|
}
|
339
345
|
strcpy(xml, StringValuePtr(ruby_xml));
|
340
|
-
obj = ox_parse(xml, ox_gen_callbacks, 0,
|
346
|
+
obj = ox_parse(xml, ox_gen_callbacks, 0, &ox_default_options);
|
341
347
|
if (SMALL_XML < len) {
|
342
348
|
xfree(xml);
|
343
349
|
}
|
@@ -346,58 +352,61 @@ to_gen(VALUE self, VALUE ruby_xml) {
|
|
346
352
|
|
347
353
|
static VALUE
|
348
354
|
load(char *xml, int argc, VALUE *argv, VALUE self) {
|
349
|
-
VALUE
|
350
|
-
struct _Options
|
355
|
+
VALUE obj;
|
356
|
+
struct _Options options = ox_default_options;
|
351
357
|
|
352
358
|
if (1 == argc && rb_cHash == rb_obj_class(*argv)) {
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
359
|
+
VALUE h = *argv;
|
360
|
+
VALUE v;
|
361
|
+
|
362
|
+
if (Qnil != (v = rb_hash_lookup(h, mode_sym))) {
|
363
|
+
if (object_sym == v) {
|
364
|
+
options.mode = ObjMode;
|
365
|
+
} else if (optimized_sym == v) {
|
366
|
+
options.mode = ObjMode;
|
367
|
+
} else if (generic_sym == v) {
|
368
|
+
options.mode = GenMode;
|
369
|
+
} else if (limited_sym == v) {
|
370
|
+
options.mode = LimMode;
|
371
|
+
} else {
|
372
|
+
rb_raise(rb_eArgError, ":mode must be :generic, :object, or :limited.\n");
|
373
|
+
}
|
374
|
+
}
|
375
|
+
if (Qnil != (v = rb_hash_lookup(h, effort_sym))) {
|
376
|
+
if (auto_define_sym == v) {
|
377
|
+
options.effort = AutoEffort;
|
378
|
+
} else if (tolerant_sym == v) {
|
379
|
+
options.effort = TolerantEffort;
|
380
|
+
} else if (strict_sym == v) {
|
381
|
+
options.effort = StrictEffort;
|
382
|
+
} else {
|
383
|
+
rb_raise(rb_eArgError, ":effort must be :strict, :tolerant, or :auto_define.\n");
|
384
|
+
}
|
385
|
+
}
|
386
|
+
if (Qnil != (v = rb_hash_lookup(h, trace_sym))) {
|
387
|
+
Check_Type(v, T_FIXNUM);
|
388
|
+
options.trace = FIX2INT(v);
|
389
|
+
}
|
390
|
+
if (Qnil != (v = rb_hash_lookup(h, symbolize_keys_sym))) {
|
391
|
+
options.sym_keys = (Qfalse == v) ? No : Yes;
|
392
|
+
}
|
384
393
|
}
|
385
394
|
switch (options.mode) {
|
386
395
|
case ObjMode:
|
387
|
-
|
388
|
-
|
396
|
+
obj = ox_parse(xml, ox_obj_callbacks, 0, &options);
|
397
|
+
break;
|
389
398
|
case GenMode:
|
390
|
-
|
391
|
-
|
399
|
+
obj = ox_parse(xml, ox_gen_callbacks, 0, &options);
|
400
|
+
break;
|
392
401
|
case LimMode:
|
393
|
-
|
394
|
-
|
402
|
+
obj = ox_parse(xml, ox_limited_callbacks, 0, &options);
|
403
|
+
break;
|
395
404
|
case NoMode:
|
396
|
-
|
397
|
-
|
405
|
+
obj = ox_parse(xml, ox_nomode_callbacks, 0, &options);
|
406
|
+
break;
|
398
407
|
default:
|
399
|
-
|
400
|
-
|
408
|
+
obj = ox_parse(xml, ox_gen_callbacks, 0, &options);
|
409
|
+
break;
|
401
410
|
}
|
402
411
|
return obj;
|
403
412
|
}
|
@@ -418,10 +427,11 @@ load(char *xml, int argc, VALUE *argv, VALUE self) {
|
|
418
427
|
* - *:tolerant* - return nil for missing classes and modules
|
419
428
|
* - *:auto_define* - auto define missing classes and modules
|
420
429
|
* @param [Fixnum] :trace trace level as a Fixnum, default: 0 (silent)
|
430
|
+
* @param [true|false|nil] :symbolize_keys symbolize element attribute keys or leave as Strings
|
421
431
|
*/
|
422
432
|
static VALUE
|
423
433
|
load_str(int argc, VALUE *argv, VALUE self) {
|
424
|
-
char
|
434
|
+
char *xml;
|
425
435
|
size_t len;
|
426
436
|
VALUE obj;
|
427
437
|
|
@@ -444,7 +454,7 @@ load_str(int argc, VALUE *argv, VALUE self) {
|
|
444
454
|
/* call-seq: load_file(file_path, options) => Ox::Document or Ox::Element or Object
|
445
455
|
*
|
446
456
|
* Parses and XML document from a file into an Ox::Document, or Ox::Element,
|
447
|
-
* or Object depending on the options.
|
457
|
+
* or Object depending on the options. Raises an exception if the XML is
|
448
458
|
* malformed or the classes specified are not valid.
|
449
459
|
* @param [String] file_path file path to read the XML document from
|
450
460
|
* @param [Hash] options load options
|
@@ -457,6 +467,7 @@ load_str(int argc, VALUE *argv, VALUE self) {
|
|
457
467
|
* - *:tolerant* - return nil for missing classes and modules
|
458
468
|
* - *:auto_define* - auto define missing classes and modules
|
459
469
|
* @param [Fixnum] :trace trace level as a Fixnum, default: 0 (silent)
|
470
|
+
* @param [true|false|nil] :symbolize_keys symbolize element attribute keys or leave as Strings
|
460
471
|
*/
|
461
472
|
static VALUE
|
462
473
|
load_file(int argc, VALUE *argv, VALUE self) {
|
@@ -469,7 +480,7 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
469
480
|
Check_Type(*argv, T_STRING);
|
470
481
|
path = StringValuePtr(*argv);
|
471
482
|
if (0 == (f = fopen(path, "r"))) {
|
472
|
-
|
483
|
+
rb_raise(rb_eIOError, "%s\n", strerror(errno));
|
473
484
|
}
|
474
485
|
fseek(f, 0, SEEK_END);
|
475
486
|
len = ftell(f);
|
@@ -480,8 +491,8 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
480
491
|
}
|
481
492
|
fseek(f, 0, SEEK_SET);
|
482
493
|
if (len != fread(xml, 1, len, f)) {
|
483
|
-
|
484
|
-
|
494
|
+
fclose(f);
|
495
|
+
rb_raise(rb_eLoadError, "Failed to read %ld bytes from %s.\n", (long)len, path);
|
485
496
|
}
|
486
497
|
fclose(f);
|
487
498
|
xml[len] = '\0';
|
@@ -506,15 +517,15 @@ sax_parse(int argc, VALUE *argv, VALUE self) {
|
|
506
517
|
int convert = 0;
|
507
518
|
|
508
519
|
if (argc < 2) {
|
509
|
-
|
520
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to sax_parse.\n");
|
510
521
|
}
|
511
522
|
if (3 <= argc && rb_cHash == rb_obj_class(argv[2])) {
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
523
|
+
VALUE h = argv[2];
|
524
|
+
VALUE v;
|
525
|
+
|
526
|
+
if (Qnil != (v = rb_hash_lookup(h, convert_special_sym))) {
|
527
|
+
convert = (Qtrue == v);
|
528
|
+
}
|
518
529
|
}
|
519
530
|
ox_sax_parse(argv[0], argv[1], convert);
|
520
531
|
|
@@ -523,61 +534,61 @@ sax_parse(int argc, VALUE *argv, VALUE self) {
|
|
523
534
|
|
524
535
|
static void
|
525
536
|
parse_dump_options(VALUE ropts, Options copts) {
|
526
|
-
struct _YesNoOpt
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
537
|
+
struct _YesNoOpt ynos[] = {
|
538
|
+
{ with_xml_sym, &copts->with_xml },
|
539
|
+
{ with_dtd_sym, &copts->with_dtd },
|
540
|
+
{ with_instruct_sym, &copts->with_instruct },
|
541
|
+
{ xsd_date_sym, &copts->xsd_date },
|
542
|
+
{ circular_sym, &copts->circular },
|
543
|
+
{ Qnil, 0 }
|
533
544
|
};
|
534
|
-
YesNoOpt
|
545
|
+
YesNoOpt o;
|
535
546
|
|
536
547
|
if (rb_cHash == rb_obj_class(ropts)) {
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
548
|
+
VALUE v;
|
549
|
+
|
550
|
+
if (Qnil != (v = rb_hash_lookup(ropts, indent_sym))) {
|
551
|
+
if (rb_cFixnum != rb_obj_class(v)) {
|
552
|
+
rb_raise(rb_eArgError, ":indent must be a Fixnum.\n");
|
553
|
+
}
|
554
|
+
copts->indent = NUM2INT(v);
|
555
|
+
}
|
556
|
+
if (Qnil != (v = rb_hash_lookup(ropts, trace_sym))) {
|
557
|
+
if (rb_cFixnum != rb_obj_class(v)) {
|
558
|
+
rb_raise(rb_eArgError, ":trace must be a Fixnum.\n");
|
559
|
+
}
|
560
|
+
copts->trace = NUM2INT(v);
|
561
|
+
}
|
562
|
+
if (Qnil != (v = rb_hash_lookup(ropts, ox_encoding_sym))) {
|
563
|
+
if (rb_cString != rb_obj_class(v)) {
|
564
|
+
rb_raise(rb_eArgError, ":encoding must be a String.\n");
|
565
|
+
}
|
566
|
+
strncpy(copts->encoding, StringValuePtr(v), sizeof(copts->encoding) - 1);
|
567
|
+
}
|
568
|
+
if (Qnil != (v = rb_hash_lookup(ropts, effort_sym))) {
|
569
|
+
if (auto_define_sym == v) {
|
570
|
+
copts->effort = AutoEffort;
|
571
|
+
} else if (tolerant_sym == v) {
|
572
|
+
copts->effort = TolerantEffort;
|
573
|
+
} else if (strict_sym == v) {
|
574
|
+
copts->effort = StrictEffort;
|
575
|
+
} else {
|
576
|
+
rb_raise(rb_eArgError, ":effort must be :strict, :tolerant, or :auto_define.\n");
|
577
|
+
}
|
578
|
+
}
|
579
|
+
for (o = ynos; 0 != o->attr; o++) {
|
580
|
+
if (Qnil != (v = rb_hash_lookup(ropts, o->sym))) {
|
581
|
+
VALUE c = rb_obj_class(v);
|
582
|
+
|
583
|
+
if (rb_cTrueClass == c) {
|
584
|
+
*o->attr = Yes;
|
585
|
+
} else if (rb_cFalseClass == c) {
|
586
|
+
*o->attr = No;
|
587
|
+
} else {
|
588
|
+
rb_raise(rb_eArgError, "%s must be true or false.\n", rb_id2name(SYM2ID(o->sym)));
|
589
|
+
}
|
590
|
+
}
|
591
|
+
}
|
581
592
|
}
|
582
593
|
}
|
583
594
|
|
@@ -595,20 +606,20 @@ parse_dump_options(VALUE ropts, Options copts) {
|
|
595
606
|
*/
|
596
607
|
static VALUE
|
597
608
|
dump(int argc, VALUE *argv, VALUE self) {
|
598
|
-
char
|
599
|
-
struct _Options
|
600
|
-
VALUE
|
609
|
+
char *xml;
|
610
|
+
struct _Options copts = ox_default_options;
|
611
|
+
VALUE rstr;
|
601
612
|
|
602
613
|
if (2 == argc) {
|
603
|
-
|
614
|
+
parse_dump_options(argv[1], &copts);
|
604
615
|
}
|
605
616
|
if (0 == (xml = ox_write_obj_to_str(*argv, &copts))) {
|
606
|
-
|
617
|
+
rb_raise(rb_eNoMemError, "Not enough memory.\n");
|
607
618
|
}
|
608
619
|
rstr = rb_str_new2(xml);
|
609
620
|
#if HAS_ENCODING_SUPPORT
|
610
621
|
if ('\0' != *copts.encoding) {
|
611
|
-
|
622
|
+
rb_enc_associate(rstr, rb_enc_find(copts.encoding));
|
612
623
|
}
|
613
624
|
#endif
|
614
625
|
xfree(xml);
|
@@ -631,10 +642,10 @@ dump(int argc, VALUE *argv, VALUE self) {
|
|
631
642
|
*/
|
632
643
|
static VALUE
|
633
644
|
to_file(int argc, VALUE *argv, VALUE self) {
|
634
|
-
struct _Options
|
645
|
+
struct _Options copts = ox_default_options;
|
635
646
|
|
636
647
|
if (3 == argc) {
|
637
|
-
|
648
|
+
parse_dump_options(argv[2], &copts);
|
638
649
|
}
|
639
650
|
Check_Type(*argv, T_STRING);
|
640
651
|
ox_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);
|
@@ -642,7 +653,7 @@ to_file(int argc, VALUE *argv, VALUE self) {
|
|
642
653
|
return Qnil;
|
643
654
|
}
|
644
655
|
|
645
|
-
extern void
|
656
|
+
extern void ox_cache_test(void);
|
646
657
|
|
647
658
|
static VALUE
|
648
659
|
cache_test(VALUE self) {
|
@@ -650,7 +661,7 @@ cache_test(VALUE self) {
|
|
650
661
|
return Qnil;
|
651
662
|
}
|
652
663
|
|
653
|
-
extern void
|
664
|
+
extern void ox_cache8_test(void);
|
654
665
|
|
655
666
|
static VALUE
|
656
667
|
cache8_test(VALUE self) {
|
@@ -722,26 +733,27 @@ void Init_ox() {
|
|
722
733
|
ox_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
|
723
734
|
ox_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
|
724
735
|
|
736
|
+
auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym);
|
737
|
+
auto_sym = ID2SYM(rb_intern("auto")); rb_gc_register_address(&auto_sym);
|
738
|
+
circular_sym = ID2SYM(rb_intern("circular")); rb_gc_register_address(&circular_sym);
|
739
|
+
convert_special_sym = ID2SYM(rb_intern("convert_special")); rb_gc_register_address(&convert_special_sym);
|
740
|
+
effort_sym = ID2SYM(rb_intern("effort")); rb_gc_register_address(&effort_sym);
|
741
|
+
generic_sym = ID2SYM(rb_intern("generic")); rb_gc_register_address(&generic_sym);
|
742
|
+
indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&indent_sym);
|
743
|
+
limited_sym = ID2SYM(rb_intern("limited")); rb_gc_register_address(&limited_sym);
|
744
|
+
mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
|
745
|
+
object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
|
746
|
+
opt_format_sym = ID2SYM(rb_intern("opt_format")); rb_gc_register_address(&opt_format_sym);
|
747
|
+
optimized_sym = ID2SYM(rb_intern("optimized")); rb_gc_register_address(&optimized_sym);
|
725
748
|
ox_encoding_sym = ID2SYM(rb_intern("encoding")); rb_gc_register_address(&ox_encoding_sym);
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
optimized_sym = ID2SYM(rb_intern("optimized")); rb_gc_register_address(&optimized_sym);
|
732
|
-
object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
|
733
|
-
circular_sym = ID2SYM(rb_intern("circular")); rb_gc_register_address(&circular_sym);
|
734
|
-
generic_sym = ID2SYM(rb_intern("generic")); rb_gc_register_address(&generic_sym);
|
735
|
-
limited_sym = ID2SYM(rb_intern("limited")); rb_gc_register_address(&limited_sym);
|
736
|
-
trace_sym = ID2SYM(rb_intern("trace")); rb_gc_register_address(&trace_sym);
|
737
|
-
effort_sym = ID2SYM(rb_intern("effort")); rb_gc_register_address(&effort_sym);
|
738
|
-
strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym);
|
739
|
-
tolerant_sym = ID2SYM(rb_intern("tolerant")); rb_gc_register_address(&tolerant_sym);
|
740
|
-
auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym);
|
741
|
-
with_dtd_sym = ID2SYM(rb_intern("with_dtd")); rb_gc_register_address(&with_dtd_sym);
|
749
|
+
strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym);
|
750
|
+
symbolize_keys_sym = ID2SYM(rb_intern("symbolize_keys")); rb_gc_register_address(&symbolize_keys_sym);
|
751
|
+
tolerant_sym = ID2SYM(rb_intern("tolerant")); rb_gc_register_address(&tolerant_sym);
|
752
|
+
trace_sym = ID2SYM(rb_intern("trace")); rb_gc_register_address(&trace_sym);
|
753
|
+
with_dtd_sym = ID2SYM(rb_intern("with_dtd")); rb_gc_register_address(&with_dtd_sym);
|
742
754
|
with_instruct_sym = ID2SYM(rb_intern("with_instructions")); rb_gc_register_address(&with_instruct_sym);
|
743
|
-
with_xml_sym = ID2SYM(rb_intern("with_xml"));
|
744
|
-
|
755
|
+
with_xml_sym = ID2SYM(rb_intern("with_xml")); rb_gc_register_address(&with_xml_sym);
|
756
|
+
xsd_date_sym = ID2SYM(rb_intern("xsd_date")); rb_gc_register_address(&xsd_date_sym);
|
745
757
|
|
746
758
|
ox_empty_string = rb_str_new2(""); rb_gc_register_address(&ox_empty_string);
|
747
759
|
ox_zero_fixnum = INT2NUM(0); rb_gc_register_address(&ox_zero_fixnum);
|
@@ -765,16 +777,16 @@ void Init_ox() {
|
|
765
777
|
|
766
778
|
void
|
767
779
|
_ox_raise_error(const char *msg, const char *xml, const char *current, const char* file, int line) {
|
768
|
-
int
|
769
|
-
int
|
780
|
+
int xline = 1;
|
781
|
+
int col = 1;
|
770
782
|
|
771
783
|
for (; xml < current && '\n' != *current; current--) {
|
772
|
-
|
784
|
+
col++;
|
773
785
|
}
|
774
786
|
for (; xml < current; current--) {
|
775
|
-
|
776
|
-
|
777
|
-
|
787
|
+
if ('\n' == *current) {
|
788
|
+
xline++;
|
789
|
+
}
|
778
790
|
}
|
779
791
|
rb_raise(rb_eSyntaxError, "%s at line %d, column %d [%s:%d]\n", msg, xline, col, file, line);
|
780
792
|
}
|