Skip to content

Commit

Permalink
Add no_empty option
Browse files Browse the repository at this point in the history
  • Loading branch information
ohler55 committed Dec 18, 2019
1 parent f5b6182 commit 7c96307
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 24 deletions.
14 changes: 13 additions & 1 deletion ext/ox/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,14 @@ dump_start(Out out, Element e) {
fill_attr(out, 'i', s, end - s);
}
if (e->closed) {
*out->cur++ = '/';
if (out->opts->no_empty) {
*out->cur++ = '>';
*out->cur++ = '<';
*out->cur++ = '/';
*out->cur++ = e->type;
} else {
*out->cur++ = '/';
}
}
*out->cur++ = '>';
*out->cur = '\0';
Expand Down Expand Up @@ -1105,6 +1112,11 @@ dump_gen_element(VALUE obj, int depth, Out out) {
*out->cur++ = '<';
*out->cur++ = '/';
fill_value(out, name, nlen);
} else if (out->opts->no_empty) {
*out->cur++ = '>';
*out->cur++ = '<';
*out->cur++ = '/';
fill_value(out, name, nlen);
} else {
*out->cur++ = '/';
}
Expand Down
25 changes: 24 additions & 1 deletion ext/ox/ox.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ static VALUE limited_sym;
static VALUE margin_sym;
static VALUE mode_sym;
static VALUE nest_ok_sym;
static VALUE no_empty_sym;
static VALUE object_sym;
static VALUE off_sym;
static VALUE opt_format_sym;
Expand Down Expand Up @@ -176,8 +177,9 @@ struct _options ox_default_options = {
Yes, // sym_keys
SpcSkip, // skip
No, // smart
1, // convert_special
true, // convert_special
No, // allow_invalid
false, // no_empty
{ '\0' }, // inv_repl
{ '\0' }, // strip_ns
NULL, // html_hints
Expand Down Expand Up @@ -292,6 +294,7 @@ hints_to_overlay(Hints hints) {
* - _:smart_ [true|false|nil] flag indicating the SAX parser uses hints if available (use with html)
* - _:convert_special_ [true|false|nil] flag indicating special characters like &lt; are converted with the SAX parser
* - _:invalid_replace_ [nil|String] replacement string for invalid XML characters on dump. nil indicates include anyway as hex. A string, limited to 10 characters will replace the invalid character with the replace.
* - _:no_empty_ [true|false|nil] flag indicating there should be no empty elements in a dump
* - _:strip_namespace_ [String|true|false] false or "" results in no namespace stripping. A string of "*" or true will strip all namespaces. Any other non-empty string indicates that matching namespaces will be stripped.
* - _:overlay_ [Hash] a Hash of keys that match html element names and values that are one of
* - _:active_ - make the normal callback for the element
Expand Down Expand Up @@ -325,6 +328,7 @@ get_def_opts(VALUE self) {
rb_hash_aset(opts, element_key_mod_sym, ox_default_options.element_key_mod);
rb_hash_aset(opts, smart_sym, (Yes == ox_default_options.smart) ? Qtrue : ((No == ox_default_options.smart) ? Qfalse : Qnil));
rb_hash_aset(opts, convert_special_sym, (ox_default_options.convert_special) ? Qtrue : Qfalse);
rb_hash_aset(opts, no_empty_sym, (ox_default_options.no_empty) ? Qtrue : Qfalse);
switch (ox_default_options.mode) {
case ObjMode: rb_hash_aset(opts, mode_sym, object_sym); break;
case GenMode: rb_hash_aset(opts, mode_sym, generic_sym); break;
Expand Down Expand Up @@ -541,6 +545,17 @@ set_def_opts(VALUE self, VALUE opts) {
rb_raise(ox_parse_error_class, ":convert_special must be true or false.\n");
}

v = rb_hash_lookup(opts, no_empty_sym);
if (Qnil == v) {
// no change
} else if (Qtrue == v) {
ox_default_options.no_empty = 1;
} else if (Qfalse == v) {
ox_default_options.no_empty = 0;
} else {
rb_raise(ox_parse_error_class, ":no_empty must be true or false.\n");
}

v = rb_hash_aref(opts, invalid_replace_sym);
if (Qnil == v) {
ox_default_options.allow_invalid = Yes;
Expand Down Expand Up @@ -776,6 +791,9 @@ load(char *xml, size_t len, int argc, VALUE *argv, VALUE self, VALUE encoding, E
if (Qnil != (v = rb_hash_lookup(h, convert_special_sym))) {
options.convert_special = (Qfalse != v);
}
if (Qnil != (v = rb_hash_lookup(h, no_empty_sym))) {
options.no_empty = (Qfalse != v);
}

v = rb_hash_lookup(h, invalid_replace_sym);
if (Qnil == v) {
Expand Down Expand Up @@ -1207,6 +1225,9 @@ parse_dump_options(VALUE ropts, Options copts) {
}
strncpy(copts->encoding, StringValuePtr(v), sizeof(copts->encoding) - 1);
}
if (Qnil != (v = rb_hash_lookup(ropts, no_empty_sym))) {
copts->no_empty = (v == Qtrue);
}
if (Qnil != (v = rb_hash_lookup(ropts, effort_sym))) {
if (auto_define_sym == v) {
copts->effort = AutoEffort;
Expand Down Expand Up @@ -1274,6 +1295,7 @@ parse_dump_options(VALUE ropts, Options copts) {
* - +obj+ [Object] Object to serialize as an XML document String
* - +options+ [Hash] formating options
* - *:indent* [Fixnum] format expected
* - *:no_empty* [true|false] if true don't output empty elements
* - *:xsd_date* [true|false] use XSD date format if true, default: false
* - *:circular* [true|false] allow circular references, default: false
* - *:strict|:tolerant]* [ :effort effort to use when an undumpable object (e.g., IO) is encountered, default: :strict
Expand Down Expand Up @@ -1478,6 +1500,7 @@ void Init_ox() {
margin_sym = ID2SYM(rb_intern("margin")); rb_gc_register_address(&margin_sym);
mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
nest_ok_sym = ID2SYM(rb_intern("nest_ok")); rb_gc_register_address(&nest_ok_sym);
no_empty_sym = ID2SYM(rb_intern("no_empty")); rb_gc_register_address(&no_empty_sym);
object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
off_sym = ID2SYM(rb_intern("off")); rb_gc_register_address(&off_sym);
opt_format_sym = ID2SYM(rb_intern("opt_format")); rb_gc_register_address(&opt_format_sym);
Expand Down
45 changes: 23 additions & 22 deletions ext/ox/ox.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,26 +123,27 @@ typedef struct _circArray {
} *CircArray;

typedef struct _options {
char encoding[64]; /* encoding, stored in the option to avoid GC invalidation in default values */
char margin[128]; /* left margin for dumping */
int indent; /* indention for dump, default 2 */
int trace; /* trace level */
char margin_len; /* margin length */
char with_dtd; /* YesNo */
char with_xml; /* YesNo */
char with_instruct; /* YesNo */
char circular; /* YesNo */
char xsd_date; /* YesNo */
char mode; /* LoadMode */
char effort; /* Effort */
char sym_keys; /* symbolize keys */
char skip; /* skip mode */
char smart; /* YesNo sax smart mode */
char convert_special;/* boolean true or false */
char allow_invalid; /* YesNo */
char inv_repl[12]; /* max 10 valid characters, first character is the length */
char strip_ns[64]; /* namespace to strip, \0 is no-strip, \* is all, else only matches */
struct _hints *html_hints; /* html hints */
char encoding[64]; // encoding, stored in the option to avoid GC invalidation in default values
char margin[128]; // left margin for dumping
int indent; // indention for dump, default 2
int trace; // trace level
char margin_len; // margin length
char with_dtd; // YesNo
char with_xml; // YesNo
char with_instruct; // YesNo
char circular; // YesNo
char xsd_date; // YesNo
char mode; // LoadMode
char effort; // Effort
char sym_keys; // symbolize keys
char skip; // skip mode
char smart; // YesNo sax smart mode
char convert_special;// boolean true or false
char allow_invalid; // YesNo
char no_empty; // boolean - no empty elements when dumping
char inv_repl[12]; // max 10 valid characters, first character is the length
char strip_ns[64]; // namespace to strip, \0 is no-strip, \* is all, else only matches
struct _hints *html_hints; // html hints
VALUE attr_key_mod;
VALUE element_key_mod;
#if HAS_ENCODING_SUPPORT
Expand All @@ -158,13 +159,13 @@ typedef struct _options {
struct _pInfo {
struct _helperStack helpers;
struct _err err;
char *str; //buffer being read from
char *str; // buffer being read from
char *end; // end of original string
char *s; // current position in buffer
VALUE obj;
ParseCallbacks pcb;
CircArray circ_array;
unsigned long id; //set for text types when cirs_array is set
unsigned long id; // set for text types when cirs_array is set
Options options;
char last; // last character read, rarely set
};
Expand Down
12 changes: 12 additions & 0 deletions test/tests.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
:smart=>false,
:convert_special=>true,
:effort=>:strict,
:no_empty=>false,
:invalid_replace=>'',
:strip_namespace=>false,
:overlay=>nil,
Expand All @@ -62,6 +63,7 @@
:smart=>false,
:convert_special=>true,
:effort=>:strict,
:no_empty=>false,
:invalid_replace=>'',
:strip_namespace=>false,
:overlay=>nil,
Expand Down Expand Up @@ -99,6 +101,7 @@ def test_set_options
:smart=>true,
:convert_special=>false,
:effort=>:tolerant,
:no_empty=>true,
:invalid_replace=>'*',
:strip_namespace=>'spaced',
:overlay=>nil,
Expand Down Expand Up @@ -792,6 +795,15 @@ def test_nameerror
assert(false)
end

def test_no_empty
Ox::default_options = $ox_generic_options
h = {}
x = Ox.dump(h, no_empty: true)
assert_equal(x, "<h></h>\n")
x = Ox.dump(Ox::Element.new('empty'), no_empty: true)
assert_equal(x, "\n<empty></empty>\n")
end

def test_mutex
Ox::default_options = $ox_object_options
if defined?(Mutex) && 'rubinius' != $ruby
Expand Down

0 comments on commit 7c96307

Please sign in to comment.