ext/nokogiri/xml_document.c in nokogiri-maglev--1.5.0.1 vs ext/nokogiri/xml_document.c in nokogiri-maglev--1.5.2

- old
+ new

@@ -46,16 +46,19 @@ xmlSetNs(node, NULL); for (child = node->children ; child ; child = child->next) recursively_remove_namespaces_from_node(child); - if (node->nsDef) { + if (((node->type == XML_ELEMENT_NODE) || + (node->type == XML_XINCLUDE_START) || + (node->type == XML_XINCLUDE_END)) && + node->nsDef) { xmlFreeNsList(node->nsDef); node->nsDef = NULL; } - if (node->properties != NULL) { + if (node->type == XML_ELEMENT_NODE && node->properties != NULL) { property = node->properties ; while (property != NULL) { if (property->ns) property->ns = NULL ; property = property->next ; } @@ -150,10 +153,13 @@ static VALUE set_encoding(VALUE self, VALUE encoding) { xmlDocPtr doc; Data_Get_Struct(self, xmlDoc, doc); + if (doc->encoding) + free((char *) doc->encoding); // this may produce a gcc cast warning + doc->encoding = xmlStrdup((xmlChar *)StringValuePtr(encoding)); return encoding; } @@ -419,10 +425,101 @@ } return Nokogiri_wrap_xml_node(cNokogiriXmlEntityDecl, (xmlNodePtr)ptr); } +static int block_caller(void * ctx, xmlNodePtr _node, xmlNodePtr _parent) +{ + VALUE block; + VALUE node; + VALUE parent; + VALUE ret; + + if(_node->type == XML_NAMESPACE_DECL){ + node = Nokogiri_wrap_xml_namespace(_parent->doc, (xmlNsPtr) _node); + } + else{ + node = Nokogiri_wrap_xml_node(Qnil, _node); + } + parent = _parent ? Nokogiri_wrap_xml_node(Qnil, _parent) : Qnil; + block = (VALUE)ctx; + + ret = rb_funcall(block, rb_intern("call"), 2, node, parent); + + if(Qfalse == ret || Qnil == ret) return 0; + + return 1; +} + +/* call-seq: + * doc.canonicalize(mode=XML_C14N_1_0,inclusive_namespaces=nil,with_comments=false) + * doc.canonicalize { |obj, parent| ... } + * + * Canonicalize a document and return the results. Takes an optional block + * that takes two parameters: the +obj+ and that node's +parent+. + * The +obj+ will be either a Nokogiri::XML::Node, or a Nokogiri::XML::Namespace + * The block must return a non-nil, non-false value if the +obj+ passed in + * should be included in the canonicalized document. + */ +static VALUE canonicalize(int argc, VALUE* argv, VALUE self) +{ + VALUE mode; + VALUE incl_ns; + VALUE with_comments; + xmlChar **ns; + long ns_len, i; + + xmlDocPtr doc; + xmlOutputBufferPtr buf; + xmlC14NIsVisibleCallback cb = NULL; + void * ctx = NULL; + + VALUE rb_cStringIO; + VALUE io; + + rb_scan_args(argc, argv, "03", &mode, &incl_ns, &with_comments); + + Data_Get_Struct(self, xmlDoc, doc); + + rb_cStringIO = rb_const_get_at(rb_cObject, rb_intern("StringIO")); + io = rb_class_new_instance(0, 0, rb_cStringIO); + buf = xmlAllocOutputBuffer(NULL); + + buf->writecallback = (xmlOutputWriteCallback)io_write_callback; + buf->closecallback = (xmlOutputCloseCallback)io_close_callback; + buf->context = (void *)io; + + if(rb_block_given_p()) { + cb = block_caller; + ctx = (void *)rb_block_proc(); + } + + if(NIL_P(incl_ns)){ + ns = NULL; + } + else{ + ns_len = RARRAY_LEN(incl_ns); + ns = calloc((size_t)ns_len+1, sizeof(xmlChar *)); + for (i = 0 ; i < ns_len ; i++) { + VALUE entry = rb_ary_entry(incl_ns, i); + const char * ptr = StringValuePtr(entry); + ns[i] = (xmlChar*) ptr; + } + } + + + xmlC14NExecute(doc, cb, ctx, + (int) (NIL_P(mode) ? 0 : NUM2INT(mode)), + ns, + (int) (NIL_P(with_comments) ? 0 : 1), + buf); + + xmlOutputBufferClose(buf); + + return rb_funcall(io, rb_intern("string"), 0); +} + VALUE cNokogiriXmlDocument ; void init_xml_document() { VALUE nokogiri = rb_define_module("Nokogiri"); VALUE xml = rb_define_module_under(nokogiri, "XML"); @@ -442,10 +539,11 @@ rb_define_method(klass, "root", root, 0); rb_define_method(klass, "root=", set_root, 1); rb_define_method(klass, "encoding", encoding, 0); rb_define_method(klass, "encoding=", set_encoding, 1); rb_define_method(klass, "version", version, 0); + rb_define_method(klass, "canonicalize", canonicalize, -1); rb_define_method(klass, "dup", duplicate_node, -1); rb_define_method(klass, "url", url, 0); rb_define_method(klass, "create_entity", create_entity, -1); rb_define_method(klass, "remove_namespaces!", remove_namespaces_bang, 0); } @@ -465,10 +563,10 @@ VALUE cache = rb_ary_new(); rb_iv_set(rb_doc, "@decorators", Qnil); rb_iv_set(rb_doc, "@node_cache", cache); - tuple->doc = (void *)rb_doc; + tuple->doc = rb_doc; tuple->unlinkedNodes = st_init_numtable_with_size(128); tuple->node_cache = cache; doc->_private = tuple ; rb_obj_call_init(rb_doc, 0, NULL);