class Ox::Builder
An XML builder.
Public Class Methods
Creates a new Builder
that will write to a file.
-
filename
(String) filename to write to -
options
- (Hash) formating options-
:indent
(Fixnum) indentaion level, negative values excludes terminating newline -
:size
(Fixnum) the initial size of the string buffer
-
static VALUE builder_file(int argc, VALUE *argv, VALUE self) { Builder b = ALLOC(struct _builder); int indent = ox_default_options.indent; long buf_size = 0; FILE *f; if (1 > argc) { rb_raise(ox_arg_error_class, "missing filename"); } Check_Type(*argv, T_STRING); if (NULL == (f = fopen(StringValuePtr(*argv), "w"))) { xfree(b); rb_raise(rb_eIOError, "%s\n", strerror(errno)); } if (2 == argc) { volatile VALUE v; rb_check_type(argv[1], T_HASH); if (Qnil != (v = rb_hash_lookup(argv[1], ox_indent_sym))) { #ifdef RUBY_INTEGER_UNIFICATION if (rb_cInteger != rb_obj_class(v)) { #else if (rb_cFixnum != rb_obj_class(v)) { #endif rb_raise(ox_parse_error_class, ":indent must be a fixnum.\n"); } indent = NUM2INT(v); } if (Qnil != (v = rb_hash_lookup(argv[1], ox_size_sym))) { #ifdef RUBY_INTEGER_UNIFICATION if (rb_cInteger != rb_obj_class(v)) { #else if (rb_cFixnum != rb_obj_class(v)) { #endif rb_raise(ox_parse_error_class, ":size must be a fixnum.\n"); } buf_size = NUM2LONG(v); } } b->file = f; init(b, fileno(f), indent, buf_size); if (rb_block_given_p()) { volatile VALUE rb = Data_Wrap_Struct(builder_class, NULL, builder_free, b); rb_yield(rb); bclose(b); return Qnil; } else { return Data_Wrap_Struct(builder_class, NULL, builder_free, b); } }
Creates a new Builder
that will write to an IO instance.
-
io
(String) IO to write to -
options
- (Hash) formating options-
:indent
(Fixnum) indentaion level, negative values excludes terminating newline -
:size
(Fixnum) the initial size of the string buffer
-
static VALUE builder_io(int argc, VALUE *argv, VALUE self) { Builder b = ALLOC(struct _builder); int indent = ox_default_options.indent; long buf_size = 0; int fd; volatile VALUE v; if (1 > argc) { rb_raise(ox_arg_error_class, "missing IO object"); } if (!rb_respond_to(*argv, ox_fileno_id) || Qnil == (v = rb_funcall(*argv, ox_fileno_id, 0)) || 0 == (fd = FIX2INT(v))) { rb_raise(rb_eIOError, "expected an IO that has a fileno."); } if (2 == argc) { volatile VALUE v; rb_check_type(argv[1], T_HASH); if (Qnil != (v = rb_hash_lookup(argv[1], ox_indent_sym))) { #ifdef RUBY_INTEGER_UNIFICATION if (rb_cInteger != rb_obj_class(v)) { #else if (rb_cFixnum != rb_obj_class(v)) { #endif rb_raise(ox_parse_error_class, ":indent must be a fixnum.\n"); } indent = NUM2INT(v); } if (Qnil != (v = rb_hash_lookup(argv[1], ox_size_sym))) { #ifdef RUBY_INTEGER_UNIFICATION if (rb_cInteger != rb_obj_class(v)) { #else if (rb_cFixnum != rb_obj_class(v)) { #endif rb_raise(ox_parse_error_class, ":size must be a fixnum.\n"); } buf_size = NUM2LONG(v); } } b->file = NULL; init(b, fd, indent, buf_size); if (rb_block_given_p()) { volatile VALUE rb = Data_Wrap_Struct(builder_class, NULL, builder_free, b); rb_yield(rb); bclose(b); return Qnil; } else { return Data_Wrap_Struct(builder_class, NULL, builder_free, b); } }
Creates a new Builder
that will write to a string that can be retrieved with the to_s
() method. If a block is given it is executed with a single parameter which is the builder instance. The return value is then the generated string.
-
options
- (Hash) formating options-
:indent
(Fixnum) indentaion level, negative values excludes terminating newline -
:size
(Fixnum) the initial size of the string buffer
-
static VALUE builder_new(int argc, VALUE *argv, VALUE self) { Builder b = ALLOC(struct _builder); int indent = ox_default_options.indent; long buf_size = 0; if (1 == argc) { volatile VALUE v; rb_check_type(*argv, T_HASH); if (Qnil != (v = rb_hash_lookup(*argv, ox_indent_sym))) { #ifdef RUBY_INTEGER_UNIFICATION if (rb_cInteger != rb_obj_class(v)) { #else if (rb_cFixnum != rb_obj_class(v)) { #endif rb_raise(ox_parse_error_class, ":indent must be a fixnum.\n"); } indent = NUM2INT(v); } if (Qnil != (v = rb_hash_lookup(*argv, ox_size_sym))) { #ifdef RUBY_INTEGER_UNIFICATION if (rb_cInteger != rb_obj_class(v)) { #else if (rb_cFixnum != rb_obj_class(v)) { #endif rb_raise(ox_parse_error_class, ":size must be a fixnum.\n"); } buf_size = NUM2LONG(v); } } b->file = NULL; init(b, 0, indent, buf_size); if (rb_block_given_p()) { volatile VALUE rb = Data_Wrap_Struct(builder_class, NULL, builder_free, b); rb_yield(rb); bclose(b); return to_s(b); } else { return Data_Wrap_Struct(builder_class, NULL, builder_free, b); } }
Public Instance Methods
Adds a CDATA element to the XML string being formed.
-
data
- (String) contents of the CDATA element
static VALUE builder_cdata(VALUE self, VALUE data) { Builder b = (Builder)DATA_PTR(self); volatile VALUE v = data; const char *str; const char *s; const char *end; int len; if (T_STRING != rb_type(v)) { v = rb_funcall(v, ox_to_s_id, 0); } str = StringValuePtr(v); len = (int)RSTRING_LEN(v); s = str; end = str + len; i_am_a_child(b, false); append_indent(b); buf_append_string(&b->buf, "<![CDATA[", 9); b->col += 9; b->pos += 9; buf_append_string(&b->buf, str, len); b->col += len; s = strchr(s, '\n'); while (NULL != s) { b->line++; b->col = end - s; s = strchr(s + 1, '\n'); } b->pos += len; buf_append_string(&b->buf, "]]>", 3); b->col += 3; b->pos += 3; return Qnil; }
Closes the all elements and the document.
static VALUE builder_close(VALUE self) { bclose((Builder)DATA_PTR(self)); return Qnil; }
Returns the current column in the output. The first character in a line is at column 1.
static VALUE builder_column(VALUE self) { return LONG2NUM(((Builder)DATA_PTR(self))->col); }
Adds a comment element to the XML string being formed.
-
text
- (String) contents of the comment
static VALUE builder_comment(VALUE self, VALUE text) { Builder b = (Builder)DATA_PTR(self); rb_check_type(text, T_STRING); i_am_a_child(b, false); append_indent(b); buf_append_string(&b->buf, "<!--", 4); b->col += 5; b->pos += 5; append_string(b, StringValuePtr(text), RSTRING_LEN(text), xml_element_chars, false); buf_append_string(&b->buf, "-->", 3); b->col += 5; b->pos += 5; return Qnil; }
Adds a DOCTYPE element to the XML string being formed.
-
text
- (String) contents of the doctype
static VALUE builder_doctype(VALUE self, VALUE text) { Builder b = (Builder)DATA_PTR(self); rb_check_type(text, T_STRING); i_am_a_child(b, false); append_indent(b); buf_append_string(&b->buf, "<!DOCTYPE ", 10); b->col += 10; b->pos += 10; append_string(b, StringValuePtr(text), RSTRING_LEN(text), xml_element_chars, false); buf_append(&b->buf, '>'); b->col++; b->pos++; return Qnil; }
Adds an element with the name and attributes provided. If a block is given then on closing of the block a pop() is called.
-
name
- (String) name of the element -
attributes
- (Hash) of the element
static VALUE builder_element(int argc, VALUE *argv, VALUE self) { Builder b = (Builder)DATA_PTR(self); Element e; const char *name; long len; if (1 > argc) { rb_raise(ox_arg_error_class, "missing element name"); } i_am_a_child(b, false); append_indent(b); b->depth++; if (MAX_DEPTH <= b->depth) { rb_raise(ox_arg_error_class, "XML too deeply nested"); } switch (rb_type(*argv)) { case T_STRING: name = StringValuePtr(*argv); len = RSTRING_LEN(*argv); break; case T_SYMBOL: name = rb_id2name(SYM2ID(*argv)); len = strlen(name); break; default: rb_raise(ox_arg_error_class, "expected a Symbol or String for an element name"); break; } e = &b->stack[b->depth]; if (sizeof(e->buf) <= (size_t)len) { e->name = strdup(name); *e->buf = '\0'; } else { strcpy(e->buf, name); e->name = e->buf; } e->len = len; e->has_child = false; e->non_text_child = false; buf_append(&b->buf, '<'); b->col++; b->pos++; append_string(b, e->name, len, xml_element_chars, false); if (1 < argc && T_HASH == rb_type(argv[1])) { rb_hash_foreach(argv[1], append_attr, (VALUE)b); } // Do not close with > or /> yet. That is done with i_am_a_child() or pop(). if (rb_block_given_p()) { rb_yield(self); pop(b); } return Qnil; }
Adds the top level <?xml?> element.
-
decl
- (String) 'xml' expected -
options
- (Hash) version or encoding
static VALUE builder_instruct(int argc, VALUE *argv, VALUE self) { Builder b = (Builder)DATA_PTR(self); i_am_a_child(b, false); append_indent(b); if (0 == argc) { buf_append_string(&b->buf, "<?xml?>", 7); b->col += 7; b->pos += 7; } else { volatile VALUE v; buf_append_string(&b->buf, "<?", 2); b->col += 2; b->pos += 2; append_sym_str(b, *argv); if (1 < argc && rb_cHash == rb_obj_class(argv[1])) { int len; if (Qnil != (v = rb_hash_lookup(argv[1], ox_version_sym))) { if (rb_cString != rb_obj_class(v)) { rb_raise(ox_parse_error_class, ":version must be a Symbol.\n"); } len = (int)RSTRING_LEN(v); buf_append_string(&b->buf, " version=\"", 10); buf_append_string(&b->buf, StringValuePtr(v), len); buf_append(&b->buf, '"'); b->col += len + 11; b->pos += len + 11; } if (Qnil != (v = rb_hash_lookup(argv[1], ox_encoding_sym))) { if (rb_cString != rb_obj_class(v)) { rb_raise(ox_parse_error_class, ":encoding must be a Symbol.\n"); } len = (int)RSTRING_LEN(v); buf_append_string(&b->buf, " encoding=\"", 11); buf_append_string(&b->buf, StringValuePtr(v), len); buf_append(&b->buf, '"'); b->col += len + 12; b->pos += len + 12; strncpy(b->encoding, StringValuePtr(v), sizeof(b->encoding)); b->encoding[sizeof(b->encoding) - 1] = '\0'; } if (Qnil != (v = rb_hash_lookup(argv[1], ox_standalone_sym))) { if (rb_cString != rb_obj_class(v)) { rb_raise(ox_parse_error_class, ":standalone must be a Symbol.\n"); } len = (int)RSTRING_LEN(v); buf_append_string(&b->buf, " standalone=\"", 13); buf_append_string(&b->buf, StringValuePtr(v), len); buf_append(&b->buf, '"'); b->col += len + 14; b->pos += len + 14; } } buf_append_string(&b->buf, "?>", 2); b->col += 2; b->pos += 2; } return Qnil; }
Returns the current line in the output. The first line is line 1.
static VALUE builder_line(VALUE self) { return LONG2NUM(((Builder)DATA_PTR(self))->line); }
Closes the current element.
static VALUE builder_pop(VALUE self) { pop((Builder)DATA_PTR(self)); return Qnil; }
Returns the number of bytes written.
static VALUE builder_pos(VALUE self) { return LONG2NUM(((Builder)DATA_PTR(self))->pos); }
Adds the provided string directly to the XML without formatting or modifications.
-
text
- (String) contents to be added
static VALUE builder_raw(VALUE self, VALUE text) { Builder b = (Builder)DATA_PTR(self); volatile VALUE v = text; const char *str; const char *s; const char *end; int len; if (T_STRING != rb_type(v)) { v = rb_funcall(v, ox_to_s_id, 0); } str = StringValuePtr(v); len = (int)RSTRING_LEN(v); s = str; end = str + len; i_am_a_child(b, true); buf_append_string(&b->buf, str, len); b->col += len; s = strchr(s, '\n'); while (NULL != s) { b->line++; b->col = end - s; s = strchr(s + 1, '\n'); } b->pos += len; return Qnil; }
Adds a text element to the XML string being formed.
-
text
- (String) contents of the text field -
strip_invalid_chars
- [true|false] strips any characters invalid for XML, defaults to false
static VALUE builder_text(int argc, VALUE *argv, VALUE self) { Builder b = (Builder)DATA_PTR(self); volatile VALUE v; volatile VALUE strip_invalid_chars; if ((0 == argc) || (argc > 2)) { rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1..2)", argc); } v = argv[0]; if (2 == argc) { strip_invalid_chars = argv[1]; } else { strip_invalid_chars = Qfalse; } if (T_STRING != rb_type(v)) { v = rb_funcall(v, ox_to_s_id, 0); } i_am_a_child(b, true); append_string(b, StringValuePtr(v), RSTRING_LEN(v), xml_element_chars, RTEST(strip_invalid_chars)); return Qnil; }
Returns the JSON document string in what ever state the construction is at.
static VALUE builder_to_s(VALUE self) { return to_s((Builder)DATA_PTR(self)); }
Adds an void element with the name and attributes provided.
-
name
- (String) name of the element -
attributes
- (Hash) of the element
static VALUE builder_void_element(int argc, VALUE *argv, VALUE self) { Builder b = (Builder)DATA_PTR(self); const char *name; long len; if (1 > argc) { rb_raise(ox_arg_error_class, "missing element name"); } i_am_a_child(b, false); append_indent(b); switch (rb_type(*argv)) { case T_STRING: name = StringValuePtr(*argv); len = RSTRING_LEN(*argv); break; case T_SYMBOL: name = rb_id2name(SYM2ID(*argv)); len = strlen(name); break; default: rb_raise(ox_arg_error_class, "expected a Symbol or String for an element name"); break; } buf_append(&b->buf, '<'); b->col++; b->pos++; append_string(b, name, len, xml_element_chars, false); if (1 < argc && T_HASH == rb_type(argv[1])) { rb_hash_foreach(argv[1], append_attr, (VALUE)b); } buf_append_string(&b->buf, ">", 1); b->col++;; b->pos++; return Qnil; }