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
@@ -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
|
+
}
|