/* 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);
}