fast-xml 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,56 @@
|
|
1
|
+
#ifndef _XH_ENCODER_H_
|
2
|
+
#define _XH_ENCODER_H_
|
3
|
+
|
4
|
+
#include "xh_config.h"
|
5
|
+
#include "xh_core.h"
|
6
|
+
|
7
|
+
#ifdef XH_HAVE_ENCODER
|
8
|
+
|
9
|
+
#ifdef XH_HAVE_ICONV
|
10
|
+
#if defined(__MINGW32__) || defined(_WIN32)
|
11
|
+
#define LIBICONV_STATIC
|
12
|
+
#endif
|
13
|
+
#include <iconv.h>
|
14
|
+
#endif
|
15
|
+
#ifdef XH_HAVE_ICU
|
16
|
+
#include <unicode/utypes.h>
|
17
|
+
#include <unicode/ucnv.h>
|
18
|
+
#endif
|
19
|
+
|
20
|
+
typedef enum {
|
21
|
+
XH_ENC_ICONV,
|
22
|
+
XH_ENC_ICU
|
23
|
+
} xh_encoder_type_t;
|
24
|
+
|
25
|
+
typedef enum {
|
26
|
+
XH_ENC_OK = 0,
|
27
|
+
XH_ENC_BUFFER_OVERFLOW,
|
28
|
+
XH_ENC_TRUNCATED_CHAR_FOUND
|
29
|
+
} xh_encoder_state_t;
|
30
|
+
|
31
|
+
typedef struct _xh_encoder_t xh_encoder_t;
|
32
|
+
struct _xh_encoder_t {
|
33
|
+
xh_encoder_type_t type;
|
34
|
+
xh_encoder_state_t state;
|
35
|
+
xh_char_t fromcode[XH_PARAM_LEN];
|
36
|
+
xh_char_t tocode[XH_PARAM_LEN];
|
37
|
+
#ifdef XH_HAVE_ICONV
|
38
|
+
iconv_t iconv;
|
39
|
+
#endif
|
40
|
+
#ifdef XH_HAVE_ICU
|
41
|
+
UConverter *uconv_from;
|
42
|
+
UConverter *uconv_to;
|
43
|
+
UChar pivotBuffer[1024];
|
44
|
+
const UChar *pivotLimit;
|
45
|
+
UChar *pivotSource, *pivotTarget, *pivotStart;
|
46
|
+
#endif
|
47
|
+
};
|
48
|
+
|
49
|
+
void xh_encoder_destroy(xh_encoder_t *encoder);
|
50
|
+
xh_encoder_t *xh_encoder_create(xh_char_t *tocode, xh_char_t *fromcode);
|
51
|
+
void xh_encoder_encode_ruby_buffer(xh_encoder_t *encoder, xh_ruby_buffer_t *main_buf, xh_ruby_buffer_t *enc_buf);
|
52
|
+
void xh_encoder_encode_string(xh_encoder_t *encoder, xh_char_t **src, size_t *src_left, xh_char_t **dst, size_t *dst_left);
|
53
|
+
|
54
|
+
#endif /* XH_HAVE_ENCODER */
|
55
|
+
|
56
|
+
#endif /* _XH_ENCODER_H_ */
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#include "xh_config.h"
|
2
|
+
#include "xh_core.h"
|
3
|
+
|
4
|
+
static VALUE
|
5
|
+
xh_h2x_exec(VALUE arg)
|
6
|
+
{
|
7
|
+
xh_h2x_ctx_t *ctx = (xh_h2x_ctx_t *) arg;
|
8
|
+
|
9
|
+
xh_writer_init(&ctx->writer, ctx->opts.encoding, ctx->opts.output, ctx->opts.buf_size, ctx->opts.indent, ctx->opts.trim);
|
10
|
+
|
11
|
+
if (ctx->opts.xml_decl) {
|
12
|
+
xh_xml_write_xml_declaration(&ctx->writer, ctx->opts.version, ctx->opts.encoding);
|
13
|
+
}
|
14
|
+
|
15
|
+
switch (ctx->opts.method) {
|
16
|
+
case XH_METHOD_NATIVE:
|
17
|
+
if (ctx->opts.use_attr) {
|
18
|
+
xh_h2x_native_attr(ctx, ctx->opts.root, xh_strlen(ctx->opts.root), ctx->hash, XH_H2X_F_COMPLEX);
|
19
|
+
}
|
20
|
+
else {
|
21
|
+
xh_h2x_native(ctx, ctx->opts.root, xh_strlen(ctx->opts.root), ctx->hash);
|
22
|
+
}
|
23
|
+
break;
|
24
|
+
case XH_METHOD_LX:
|
25
|
+
//xh_h2x_lx(ctx, ctx->hash, NULL, 0, XH_H2X_F_NONE);
|
26
|
+
break;
|
27
|
+
default:
|
28
|
+
rb_raise(rb_eArgError, "Invalid method");
|
29
|
+
}
|
30
|
+
|
31
|
+
return Qnil;
|
32
|
+
}
|
33
|
+
|
34
|
+
VALUE
|
35
|
+
xh_h2x(xh_h2x_ctx_t *ctx)
|
36
|
+
{
|
37
|
+
VALUE result;
|
38
|
+
int state;
|
39
|
+
|
40
|
+
result = rb_protect(xh_h2x_exec, (VALUE) ctx, &state);
|
41
|
+
|
42
|
+
if (state) {
|
43
|
+
result = xh_writer_flush(&ctx->writer);
|
44
|
+
xh_writer_destroy(&ctx->writer);
|
45
|
+
rb_exc_raise(rb_errinfo());
|
46
|
+
}
|
47
|
+
|
48
|
+
result = xh_writer_flush(&ctx->writer);
|
49
|
+
if (result != Qnil && ctx->opts.utf8) {
|
50
|
+
#ifdef XH_HAVE_ENCODER
|
51
|
+
if (ctx->writer.encoder == NULL) {
|
52
|
+
XH_FORCE_UTF8(result);
|
53
|
+
}
|
54
|
+
#else
|
55
|
+
XH_FORCE_UTF8(result);
|
56
|
+
#endif
|
57
|
+
}
|
58
|
+
|
59
|
+
xh_writer_destroy(&ctx->writer);
|
60
|
+
|
61
|
+
return result;
|
62
|
+
}
|
@@ -0,0 +1,93 @@
|
|
1
|
+
#ifndef _XH_H2X_H_
|
2
|
+
#define _XH_H2X_H_
|
3
|
+
|
4
|
+
#include "xh_config.h"
|
5
|
+
#include "xh_core.h"
|
6
|
+
|
7
|
+
#define XH_H2X_F_NONE 0
|
8
|
+
#define XH_H2X_F_SIMPLE 1
|
9
|
+
#define XH_H2X_F_COMPLEX 2
|
10
|
+
#define XH_H2X_F_CONTENT 4
|
11
|
+
#define XH_H2X_F_ATTR_ONLY 8
|
12
|
+
|
13
|
+
#define XH_H2X_T_SCALAR 1
|
14
|
+
#define XH_H2X_T_HASH 2
|
15
|
+
#define XH_H2X_T_ARRAY 4
|
16
|
+
//#define XH_H2X_T_BLESSED 8
|
17
|
+
#define XH_H2X_T_RAW 16
|
18
|
+
#define XH_H2X_T_NOT_NULL (XH_H2X_T_SCALAR | XH_H2X_T_ARRAY | XH_H2X_T_HASH)
|
19
|
+
|
20
|
+
#define XH_H2X_STASH_SIZE 16
|
21
|
+
|
22
|
+
typedef struct {
|
23
|
+
xh_opts_t opts;
|
24
|
+
xh_int_t depth;
|
25
|
+
xh_writer_t writer;
|
26
|
+
xh_stack_t stash;
|
27
|
+
VALUE hash;
|
28
|
+
} xh_h2x_ctx_t;
|
29
|
+
|
30
|
+
XH_INLINE VALUE
|
31
|
+
xh_h2x_resolve_value(xh_h2x_ctx_t *ctx, VALUE value, xh_uint_t *type)
|
32
|
+
{
|
33
|
+
*type = 0;
|
34
|
+
|
35
|
+
while (RB_TYPE_P(value, RUBY_T_DATA) || RB_TYPE_P(value, RUBY_T_OBJECT)) {
|
36
|
+
if (rb_obj_is_kind_of(value, rb_cProc) || rb_obj_is_kind_of(value, rb_cMethod)) {
|
37
|
+
value = rb_funcall(value, rb_intern("call"), 0);
|
38
|
+
}
|
39
|
+
else {
|
40
|
+
break;
|
41
|
+
}
|
42
|
+
|
43
|
+
if (++ctx->depth > ctx->opts.max_depth)
|
44
|
+
rb_raise(xh_parse_error_class, "Maximum recursion depth exceeded");
|
45
|
+
}
|
46
|
+
|
47
|
+
if (rb_cHash == rb_obj_class(value)) {
|
48
|
+
*type |= XH_H2X_T_HASH;
|
49
|
+
}
|
50
|
+
else if (rb_cArray == rb_obj_class(value)) {
|
51
|
+
*type |= XH_H2X_T_ARRAY;
|
52
|
+
}
|
53
|
+
else if (!RTEST(value)) {
|
54
|
+
*type = 0;
|
55
|
+
}
|
56
|
+
else {
|
57
|
+
*type |= XH_H2X_T_SCALAR;
|
58
|
+
}
|
59
|
+
|
60
|
+
/*
|
61
|
+
if (SvOBJECT(value))
|
62
|
+
*type |= XH_H2X_T_BLESSED;
|
63
|
+
*/
|
64
|
+
return value;
|
65
|
+
}
|
66
|
+
|
67
|
+
VALUE xh_h2x(xh_h2x_ctx_t *ctx);
|
68
|
+
void xh_h2x_native(xh_h2x_ctx_t *ctx, xh_char_t *key, size_t key_len, VALUE value);
|
69
|
+
xh_int_t xh_h2x_native_attr(xh_h2x_ctx_t *ctx, xh_char_t *key, size_t key_len, VALUE value, xh_int_t flag);
|
70
|
+
/*
|
71
|
+
void xh_h2x_lx(xh_h2x_ctx_t *ctx, SV *value, xh_char_t *key, I32 key_len, xh_int_t flag);
|
72
|
+
*/
|
73
|
+
|
74
|
+
XH_INLINE void
|
75
|
+
xh_h2x_destroy_ctx(xh_h2x_ctx_t *ctx)
|
76
|
+
{
|
77
|
+
xh_destroy_opts(&ctx->opts);
|
78
|
+
}
|
79
|
+
|
80
|
+
XH_INLINE void
|
81
|
+
xh_h2x_init_ctx(xh_h2x_ctx_t *ctx, xh_int_t argc, VALUE *argv)
|
82
|
+
{
|
83
|
+
xh_opts_t *opts = NULL;
|
84
|
+
xh_int_t nparam = 0;
|
85
|
+
|
86
|
+
memset(ctx, 0, sizeof(xh_h2x_ctx_t));
|
87
|
+
|
88
|
+
//opts = (xh_opts_t *) xh_get_obj_param(&nparam, ax, items, "XML::Hash::XS");
|
89
|
+
ctx->hash = xh_get_hash_param(&nparam, argc, argv);
|
90
|
+
xh_merge_opts(&ctx->opts, opts, &nparam, argc, argv);
|
91
|
+
}
|
92
|
+
|
93
|
+
#endif /* _XH_H2X_H_ */
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#include "xh_config.h"
|
2
|
+
#include "xh_core.h"
|
3
|
+
|
4
|
+
static int
|
5
|
+
xh_h2x_native_hash_iter(VALUE key, VALUE value, VALUE arg)
|
6
|
+
{
|
7
|
+
xh_h2x_ctx_t *ctx = (xh_h2x_ctx_t *) arg;
|
8
|
+
|
9
|
+
if (SYMBOL_P(key)) {
|
10
|
+
key = rb_sym2str(key);
|
11
|
+
}
|
12
|
+
else {
|
13
|
+
key = rb_obj_as_string(key);
|
14
|
+
}
|
15
|
+
|
16
|
+
xh_h2x_native(ctx, XH_CHAR_CAST RSTRING_PTR(key), RSTRING_LEN(key), value);
|
17
|
+
|
18
|
+
return ST_CONTINUE;
|
19
|
+
}
|
20
|
+
|
21
|
+
static VALUE
|
22
|
+
xh_h2x_native_call_next(VALUE obj)
|
23
|
+
{
|
24
|
+
return rb_funcall(obj, xh_id_next, 0);
|
25
|
+
}
|
26
|
+
|
27
|
+
static VALUE
|
28
|
+
xh_h2x_native_call_stop(VALUE obj)
|
29
|
+
{
|
30
|
+
return Qnil;
|
31
|
+
}
|
32
|
+
|
33
|
+
void
|
34
|
+
xh_h2x_native(xh_h2x_ctx_t *ctx, xh_char_t *key, size_t key_len, VALUE value)
|
35
|
+
{
|
36
|
+
xh_uint_t type;
|
37
|
+
size_t i, len;
|
38
|
+
VALUE next_value;
|
39
|
+
xh_sort_hash_t sorted_hash;
|
40
|
+
|
41
|
+
value = xh_h2x_resolve_value(ctx, value, &type);
|
42
|
+
|
43
|
+
if (rb_obj_is_kind_of(value, rb_cEnumerator)) {
|
44
|
+
while (1) {
|
45
|
+
next_value = rb_rescue2(xh_h2x_native_call_next, value, xh_h2x_native_call_stop, value, rb_eStopIteration, (VALUE) 0);
|
46
|
+
if (next_value == Qnil) break;
|
47
|
+
xh_h2x_native(ctx, key, key_len, next_value);
|
48
|
+
}
|
49
|
+
goto FINISH;
|
50
|
+
}
|
51
|
+
|
52
|
+
if (type & XH_H2X_T_SCALAR) {
|
53
|
+
xh_xml_write_node(&ctx->writer, key, key_len, value, type & XH_H2X_T_RAW);
|
54
|
+
}
|
55
|
+
else if (type & XH_H2X_T_HASH) {
|
56
|
+
len = RHASH_SIZE(value);
|
57
|
+
if (len == 0) goto ADD_EMPTY_NODE;
|
58
|
+
|
59
|
+
xh_xml_write_start_node(&ctx->writer, key, key_len);
|
60
|
+
|
61
|
+
if (len > 1 && ctx->opts.canonical) {
|
62
|
+
sorted_hash.elts = alloca(sizeof(xh_sort_hash_elt_t) * len);
|
63
|
+
|
64
|
+
xh_sort_hash(&sorted_hash, value);
|
65
|
+
|
66
|
+
for (i = 0; i < sorted_hash.nelts; i++) {
|
67
|
+
xh_h2x_native(ctx, sorted_hash.elts[i].key, sorted_hash.elts[i].key_len, sorted_hash.elts[i].value);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
else {
|
71
|
+
rb_hash_foreach(value, xh_h2x_native_hash_iter, (VALUE) ctx);
|
72
|
+
}
|
73
|
+
|
74
|
+
xh_xml_write_end_node(&ctx->writer, key, key_len);
|
75
|
+
}
|
76
|
+
else if (type & XH_H2X_T_ARRAY) {
|
77
|
+
len = RARRAY_LEN(value);
|
78
|
+
for (i = 0; i < len; i++) {
|
79
|
+
xh_h2x_native(ctx, key, key_len, RARRAY_AREF(value, i));
|
80
|
+
}
|
81
|
+
}
|
82
|
+
else {
|
83
|
+
ADD_EMPTY_NODE:
|
84
|
+
xh_xml_write_empty_node(&ctx->writer, key, key_len);
|
85
|
+
}
|
86
|
+
|
87
|
+
FINISH:
|
88
|
+
ctx->depth--;
|
89
|
+
}
|
@@ -0,0 +1,161 @@
|
|
1
|
+
#include "xh_config.h"
|
2
|
+
#include "xh_core.h"
|
3
|
+
|
4
|
+
typedef struct {
|
5
|
+
xh_h2x_ctx_t *ctx;
|
6
|
+
xh_int_t flag;
|
7
|
+
size_t *done;
|
8
|
+
} xh_iter_ctx_t;
|
9
|
+
|
10
|
+
static int
|
11
|
+
xh_h2x_native_attr_hash_iter(VALUE key, VALUE value, VALUE arg)
|
12
|
+
{
|
13
|
+
xh_iter_ctx_t *iter_ctx = (xh_iter_ctx_t *) arg;
|
14
|
+
|
15
|
+
if (SYMBOL_P(key)) {
|
16
|
+
key = rb_sym2str(key);
|
17
|
+
}
|
18
|
+
else {
|
19
|
+
key = rb_obj_as_string(key);
|
20
|
+
}
|
21
|
+
|
22
|
+
*iter_ctx->done += xh_h2x_native_attr(iter_ctx->ctx, XH_CHAR_CAST RSTRING_PTR(key), RSTRING_LEN(key), value, iter_ctx->flag);
|
23
|
+
|
24
|
+
return ST_CONTINUE;
|
25
|
+
}
|
26
|
+
|
27
|
+
static VALUE
|
28
|
+
xh_h2x_native_attr_call_next(VALUE obj)
|
29
|
+
{
|
30
|
+
return rb_funcall(obj, xh_id_next, 0);
|
31
|
+
}
|
32
|
+
|
33
|
+
static VALUE
|
34
|
+
xh_h2x_native_attr_call_stop(VALUE obj)
|
35
|
+
{
|
36
|
+
return Qnil;
|
37
|
+
}
|
38
|
+
|
39
|
+
xh_int_t
|
40
|
+
xh_h2x_native_attr(xh_h2x_ctx_t *ctx, xh_char_t *key, size_t key_len, VALUE value, xh_int_t flag)
|
41
|
+
{
|
42
|
+
xh_uint_t type;
|
43
|
+
size_t len, i, nattrs, done;
|
44
|
+
xh_sort_hash_t sorted_hash;
|
45
|
+
VALUE next_value;
|
46
|
+
xh_iter_ctx_t iter_ctx;
|
47
|
+
|
48
|
+
nattrs = 0;
|
49
|
+
|
50
|
+
if (ctx->opts.content[0] != '\0' && xh_strcmp(key, ctx->opts.content) == 0)
|
51
|
+
flag = flag | XH_H2X_F_CONTENT;
|
52
|
+
|
53
|
+
value = xh_h2x_resolve_value(ctx, value, &type);
|
54
|
+
|
55
|
+
if (rb_obj_is_kind_of(value, rb_cEnumerator)) {
|
56
|
+
if (!(flag & XH_H2X_F_COMPLEX)) goto FINISH;
|
57
|
+
|
58
|
+
while (1) {
|
59
|
+
next_value = rb_rescue2(xh_h2x_native_attr_call_next, value, xh_h2x_native_attr_call_stop, value, rb_eStopIteration, (VALUE) 0);
|
60
|
+
if (next_value == Qnil) break;
|
61
|
+
(void) xh_h2x_native_attr(ctx, key, key_len, next_value, XH_H2X_F_SIMPLE | XH_H2X_F_COMPLEX);
|
62
|
+
}
|
63
|
+
|
64
|
+
nattrs++;
|
65
|
+
|
66
|
+
goto FINISH;
|
67
|
+
}
|
68
|
+
|
69
|
+
if (type & XH_H2X_T_SCALAR) {
|
70
|
+
if (flag & XH_H2X_F_COMPLEX && (flag & XH_H2X_F_SIMPLE || type & XH_H2X_T_RAW)) {
|
71
|
+
xh_xml_write_node(&ctx->writer, key, key_len, value, type & XH_H2X_T_RAW);
|
72
|
+
}
|
73
|
+
else if (flag & XH_H2X_F_COMPLEX && flag & XH_H2X_F_CONTENT) {
|
74
|
+
xh_xml_write_content(&ctx->writer, value);
|
75
|
+
}
|
76
|
+
else if (flag & XH_H2X_F_SIMPLE && !(flag & XH_H2X_F_CONTENT) && !(type & XH_H2X_T_RAW)) {
|
77
|
+
xh_xml_write_attribute(&ctx->writer, key, key_len, value);
|
78
|
+
nattrs++;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
else if (type & XH_H2X_T_HASH) {
|
82
|
+
if (!(flag & XH_H2X_F_COMPLEX)) goto FINISH;
|
83
|
+
|
84
|
+
len = RHASH_SIZE(value);
|
85
|
+
if (len == 0) {
|
86
|
+
xh_xml_write_empty_node(&ctx->writer, key, key_len);
|
87
|
+
goto FINISH;
|
88
|
+
}
|
89
|
+
|
90
|
+
xh_xml_write_start_tag(&ctx->writer, key, key_len);
|
91
|
+
|
92
|
+
done = 0;
|
93
|
+
iter_ctx.ctx = ctx;
|
94
|
+
iter_ctx.done = &done;
|
95
|
+
|
96
|
+
if (len > 1 && ctx->opts.canonical) {
|
97
|
+
sorted_hash.elts = alloca(sizeof(xh_sort_hash_elt_t) * len);
|
98
|
+
|
99
|
+
xh_sort_hash(&sorted_hash, value);
|
100
|
+
|
101
|
+
for (i = 0; i < sorted_hash.nelts; i++) {
|
102
|
+
done += xh_h2x_native_attr(ctx, sorted_hash.elts[i].key, sorted_hash.elts[i].key_len, sorted_hash.elts[i].value, XH_H2X_F_SIMPLE);
|
103
|
+
}
|
104
|
+
|
105
|
+
if (done == len) {
|
106
|
+
xh_xml_write_closed_end_tag(&ctx->writer);
|
107
|
+
}
|
108
|
+
else {
|
109
|
+
xh_xml_write_end_tag(&ctx->writer);
|
110
|
+
|
111
|
+
for (i = 0; i < sorted_hash.nelts; i++) {
|
112
|
+
(void) xh_h2x_native_attr(ctx, sorted_hash.elts[i].key, sorted_hash.elts[i].key_len, sorted_hash.elts[i].value, XH_H2X_F_COMPLEX);
|
113
|
+
}
|
114
|
+
|
115
|
+
xh_xml_write_end_node(&ctx->writer, key, key_len);
|
116
|
+
}
|
117
|
+
}
|
118
|
+
else {
|
119
|
+
iter_ctx.flag = XH_H2X_F_SIMPLE;
|
120
|
+
rb_hash_foreach(value, xh_h2x_native_attr_hash_iter, (VALUE) &iter_ctx);
|
121
|
+
|
122
|
+
if (done == len) {
|
123
|
+
xh_xml_write_closed_end_tag(&ctx->writer);
|
124
|
+
}
|
125
|
+
else {
|
126
|
+
xh_xml_write_end_tag(&ctx->writer);
|
127
|
+
|
128
|
+
iter_ctx.flag = XH_H2X_F_COMPLEX;
|
129
|
+
rb_hash_foreach(value, xh_h2x_native_attr_hash_iter, (VALUE) &iter_ctx);
|
130
|
+
|
131
|
+
xh_xml_write_end_node(&ctx->writer, key, key_len);
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
nattrs++;
|
136
|
+
}
|
137
|
+
else if (type & XH_H2X_T_ARRAY) {
|
138
|
+
if (!(flag & XH_H2X_F_COMPLEX)) goto FINISH;
|
139
|
+
|
140
|
+
len = RARRAY_LEN(value);
|
141
|
+
for (i = 0; i < len; i++) {
|
142
|
+
(void) xh_h2x_native_attr(ctx, key, key_len, RARRAY_AREF(value, i), XH_H2X_F_SIMPLE | XH_H2X_F_COMPLEX);
|
143
|
+
}
|
144
|
+
|
145
|
+
nattrs++;
|
146
|
+
}
|
147
|
+
else {
|
148
|
+
if (flag & XH_H2X_F_SIMPLE && flag & XH_H2X_F_COMPLEX) {
|
149
|
+
xh_xml_write_empty_node(&ctx->writer, key, key_len);
|
150
|
+
}
|
151
|
+
else if (flag & XH_H2X_F_SIMPLE && !(flag & XH_H2X_F_CONTENT)) {
|
152
|
+
xh_xml_write_attribute(&ctx->writer, key, key_len, Qnil);
|
153
|
+
nattrs++;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
FINISH:
|
158
|
+
ctx->depth--;
|
159
|
+
|
160
|
+
return nattrs;
|
161
|
+
}
|