Hi,
Since implementing that first-cut Sax API, I've been having a few regrets
about doing it with Procs - it's pretty slow (duh!). I've been working on
an alternative implementation based on method calls to a strategy object
held in the C struct for the Sax parser. The downside is, this breaks the
API (more in a moment). The upside is it's a fair bit faster.
Breaking the API is, I think, not as big a thing as it might be - we're
coming up for 0.4.0 next, and though I don't like this kind of breakage on
a minor release, the sax parser API is also new in 0.3.8 and still
experimental, so IMHO it's better to change it now rather than wait.
I've attached a patch against CVS head (update first, there've been
changes today) that implements the new functionality if anyone wants to
try it and let me know what they think. I've also run a few benchmarks.
First up, this is using the sax parser, parse 1 being with no callbacks,
parse 2 being with callbacks applied (empty procs / methods). Really it's
just testing the overhead of calling the callbacks:
########### OLD (proc-based) ###############
user system total real
XML::SAXParser#parse 1 2.200000 0.210000 2.410000 ( 5.066253)
user system total real
XML::SAXParser#parse 2 14.450000 0.370000 14.820000 ( 15.340662)
########### NEW (class-based) ##############
user system total real
XML::SAXParser#parse 1 1.850000 0.140000 1.990000 ( 2.000680)
user system total real
XML::SAXParser#parse 2 6.570000 0.190000 6.760000 ( 6.906034)
You can see that the overhead of the class-based approach is much lower. I
also did a slightly more real-world benchmark using my digestr library.
This compares the REXML-based XMLDigester, DigestR based on the proc-based
sax parser, and DigestR based on the new sax parser. The difference is
less marked, but still worthwhile I believe (these tests run 500
iterations over an small addressbook XML file, and build a custom tree in
the callbacks).
###### XMLDIGESTER ######
user system total real
22.120000 0.920000 23.040000 ( 23.336247)
###### DIGESTR ######
user system total real
8.400000 0.200000 8.600000 ( 8.731552)
###### DIGESTR-NEWSAX ######
user system total real
6.360000 0.120000 6.480000 ( 6.591864)
Anyway, I'd really appreciate any thoughts or ideas anyone has about this.
Cheers,
--
Ross Bamford - [EMAIL PROTECTED]? tests/tc_xml_sax_parser_new.rb
Index: ext/xml/ruby_xml_sax_parser.c
===================================================================
RCS file: /var/cvs/libxml/libxml/ext/xml/ruby_xml_sax_parser.c,v
retrieving revision 1.4
diff -u -d -r1.4 ruby_xml_sax_parser.c
--- ext/xml/ruby_xml_sax_parser.c 14 Apr 2006 23:46:06 -0000 1.4
+++ ext/xml/ruby_xml_sax_parser.c 31 May 2006 18:28:02 -0000
@@ -6,7 +6,25 @@
#include "ruby_xml_sax_parser.h"
VALUE cXMLSaxParser;
-VALUE callsym;
+VALUE mXMLSaxParserCallbacks;
+
+VALUE cbidOnInternalSubset;
+VALUE cbidOnIsStandalone;
+VALUE cbidOnHasInternalSubset;
+VALUE cbidOnHasExternalSubset;
+VALUE cbidOnStartDocument;
+VALUE cbidOnEndDocument;
+VALUE cbidOnStartElement;
+VALUE cbidOnEndElement;
+VALUE cbidOnReference;
+VALUE cbidOnCharacters;
+VALUE cbidOnProcessingInstruction;
+VALUE cbidOnComment;
+VALUE cbidOnXmlParserWarning;
+VALUE cbidOnXmlParserError;
+VALUE cbidOnXmlParserFatalError;
+VALUE cbidOnCdataBlock;
+VALUE cbidOnExternalSubset;
#include "sax_parser_callbacks.inc"
@@ -17,30 +35,20 @@
/* xmlFreeSax_Parser(rxsp->sax_parser); */
}
-#define mark_handler(rxsp, handler) \
- if (rxsp->cbp->handler && (rxsp->cbp->handler != Qnil)) \
- rb_gc_mark(rxsp->cbp->handler)
-
void
ruby_xml_sax_parser_mark(ruby_xml_sax_parser *rxsp) {
- mark_handler(rxsp, internalSubset);
- mark_handler(rxsp, isStandalone);
- mark_handler(rxsp, hasInternalSubset);
- mark_handler(rxsp, hasExternalSubset);
- mark_handler(rxsp, startDocument);
- mark_handler(rxsp, endDocument);
- mark_handler(rxsp, startElement);
- mark_handler(rxsp, endElement);
- mark_handler(rxsp, reference);
- mark_handler(rxsp, characters);
- mark_handler(rxsp, processingInstruction);
- mark_handler(rxsp, comment);
- mark_handler(rxsp, xmlParserWarning);
- mark_handler(rxsp, xmlParserError);
- mark_handler(rxsp, xmlParserFatalError);
- mark_handler(rxsp, cdataBlock);
-}
+ if (rxsp->callbackHandler && (rxsp->callbackHandler != Qnil)) {
+ rb_gc_mark(rxsp->callbackHandler);
+ }
+
+ if (rxsp->filename && (rxsp->filename != Qnil)) {
+ rb_gc_mark(rxsp->filename);
+ }
+ if (rxsp->str && (rxsp->str != Qnil)) {
+ rb_gc_mark(rxsp->str);
+ }
+}
/*
* call-seq:
@@ -53,10 +61,9 @@
ruby_xml_sax_parser *rxsp;
rxsp = ALLOC(ruby_xml_sax_parser);
- rxsp->cbp = ALLOC(ruby_xml_sax_parser_callbacks);
- memset(rxsp->cbp, 0, sizeof(ruby_xml_sax_parser_callbacks));
rxsp->xsh = &rubySAXHandlerStruct;
-
+
+ rxsp->callbackHandler = Qnil;
rxsp->xpc = NULL;
rxsp->filename = Qnil;
rxsp->str = Qnil;
@@ -68,6 +75,38 @@
/*
* call-seq:
+ * sax_parser.callbacks => #<XML::SaxParser::Callbacks subclass>
+ *
+ * Obtain the callbacks used by this parser.
+ */
+VALUE
+ruby_xml_sax_parser_callbacks_get(VALUE self) {
+ ruby_xml_sax_parser *rxsp;
+ Data_Get_Struct(self, ruby_xml_sax_parser, rxsp);
+ return(rxsp->callbackHandler);
+}
+
+
+/*
+ * call-seq:
+ * sax_parser.callbacks = #<XML::SaxParser::Callbacks subclass>
+ *
+ * Set the callbacks used by this parser. The value assigned to
+ * this attribute will usually be an object that extends the the
+ * XML::SaxParser::Callbacks module, overriding the callbacks it
+ * wishes to process.
+ */
+VALUE
+ruby_xml_sax_parser_callbacks_set(VALUE self, VALUE callbacks) {
+ ruby_xml_sax_parser *rxsp;
+ Data_Get_Struct(self, ruby_xml_sax_parser, rxsp);
+ rxsp->callbackHandler = callbacks;
+ return(rxsp->callbackHandler);
+}
+
+
+/*
+ * call-seq:
* sax_parser.filename => "filename"
*
* Obtain the filename this parser reads from.
@@ -95,280 +134,276 @@
return(rxsp->filename);
}
-#define set_handler(self, argc, argv, handler) \
- VALUE proc; \
- rb_scan_args(argc, argv, "0&", &proc); \
- ruby_xml_sax_parser *rxsp; \
- Data_Get_Struct(self, ruby_xml_sax_parser, rxsp); \
- rxsp->cbp->handler = proc; \
- return(Qnil);
+
+/*
+ * call-seq:
+ * parser.parse => (true|false)
+ *
+ * Parse the input XML, generating callbacks to the object
+ * registered via the +callbacks+ attribute.
+ */
+VALUE
+ruby_xml_sax_parser_parse(VALUE self) {
+ char *str;
+ int status = 1;
+ ruby_xml_sax_parser *rxsp;
+
+ Data_Get_Struct(self, ruby_xml_sax_parser, rxsp);
+
+ if (rxsp->filename != Qnil) {
+ status = xmlSAXUserParseFile(rxsp->xsh, rxsp, StringValuePtr(rxsp->filename));
+ } else if (rxsp->str != Qnil) {
+ str = StringValuePtr(rxsp->str);
+ status = //ruby_xml_document_new(cXMLDocument,
+ xmlSAXUserParseMemory(rxsp->xsh, rxsp,
+ str, strlen(str)); //);
+ }
+
+ /* XXX This should return an exception for the various error codes
+ * that can come back in status, but I'm too lazy to do that right
+ * now. */
+ if (status)
+ return(Qfalse);
+ else
+ return(Qtrue);
+}
/*
* call-seq:
- * parser.on_internal_subset { |name, external_id, system_id| ... } => nil
+ * parser.string => "xml"
+ *
+ * Obtain the parser's input string.
+ */
+VALUE
+ruby_xml_sax_parser_str_get(VALUE self) {
+ ruby_xml_sax_parser *rxsp;
+ Data_Get_Struct(self, ruby_xml_sax_parser, rxsp);
+ return(rxsp->str);
+}
+
+
+/*
+ * call-seq:
+ * parser.string = "xml"
+ *
+ * Set the parser's input string.
+ */
+VALUE
+ruby_xml_sax_parser_str_set(VALUE self, VALUE str) {
+ ruby_xml_sax_parser *rxsp;
+ Check_Type(str, T_STRING);
+ Data_Get_Struct(self, ruby_xml_sax_parser, rxsp);
+ rxsp->str = str;
+ return(rxsp->str);
+}
+
+
+/****** SaxCallbacks ******/
+/* These are all the same. Bloody Rdoc... */
+
+/*
+ * call-seq:
+ * callbacks.on_internal_subset(name, external_id, system_id)
*
- * Set the callback block for an internal subset event.
+ * Called for an internal subset event.
*/
VALUE
-ruby_xml_sax_parser_on_internal_subset(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, internalSubset);
+ruby_xml_sax_callbacks_on_internal_subset(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_is_standalone { || ... } => nil
+ * callbacks.on_is_standalone()
*
- * Set the callback proc for 'is standalone' event.
+ * Called for 'is standalone' event.
*/
VALUE
-ruby_xml_sax_parser_on_is_standalone(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, isStandalone);
+ruby_xml_sax_callbacks_on_is_standalone(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_has_internal_subset { || ... } => nil
+ * callbacks.on_has_internal_subset()
*
- * Set the callback proc for an internal subset notification event.
+ * Called for an internal subset notification event.
*/
VALUE
-ruby_xml_sax_parser_on_has_internal_subset(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, hasInternalSubset);
+ruby_xml_sax_callbacks_on_has_internal_subset(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_has_external_subset { || ... } => nil
+ * callbacks.on_has_external_subset()
*
- * Set the callback proc for an external subset notification event.
+ * Called for an external subset notification event.
*/
VALUE
-ruby_xml_sax_parser_on_has_external_subset(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, hasExternalSubset);
+ruby_xml_sax_callbacks_on_has_external_subset(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_start_document { || ... } => nil
+ * callbacks.on_start_document()
*
- * Set the callback proc for a start document event.
+ * Called for a start document event.
*/
VALUE
-ruby_xml_sax_parser_on_start_document(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, startDocument);
+ruby_xml_sax_callbacks_on_start_document(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_end_document { || ... } => nil
+ * callbacks.on_end_document()
*
- * Set the callback proc for an end document event.
+ * Called for an end document event.
*/
VALUE
-ruby_xml_sax_parser_on_end_document(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, endDocument);
+ruby_xml_sax_callbacks_on_end_document(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_start_element { |name, attr_hash| ... } => nil
+ * callbacks.on_start_element(name, attr_hash)
*
- * Set the callback proc for an element start event.
+ * Called for an element start event.
*/
VALUE
-ruby_xml_sax_parser_on_start_element(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, startElement);
+ruby_xml_sax_callbacks_on_start_element(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_end_element { |name| ... } => nil
+ * callbacks.on_end_element(name)
*
- * Set the callback proc for an element end event.
+ * Called for an element end event.
*/
VALUE
-ruby_xml_sax_parser_on_end_element(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, endElement);
+ruby_xml_sax_callbacks_on_end_element(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_reference { |name| ... } => nil
+ * callbacks.on_reference(name)
*
- * Set the callback proc for a reference event.
+ * Called for a reference event.
*/
VALUE
-ruby_xml_sax_parser_on_reference(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, reference);
+ruby_xml_sax_callbacks_on_reference(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_characters { |chars| ... } => nil
+ * callbacks.on_characters(chars)
*
- * Set the callback proc for a characters event.
+ * Called for a characters event.
*/
VALUE
-ruby_xml_sax_parser_on_characters(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, characters);
+ruby_xml_sax_callbacks_on_characters(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_processing_instruction { |target, data| ... } => nil
+ * callbacks.on_processing_instruction(target, data)
*
- * Set the callback proc for an processing instruction event.
+ * Called for an processing instruction event.
*/
VALUE
-ruby_xml_sax_parser_on_processing_instruction(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, processingInstruction);
+ruby_xml_sax_callbacks_on_processing_instruction(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_comment { |msg| ... } => nil
+ * callbacks.on_comment(msg)
*
- * Set the callback proc for a comment event.
+ * Called for a comment event.
*/
VALUE
-ruby_xml_sax_parser_on_comment(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, comment);
+ruby_xml_sax_callbacks_on_comment(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_parser_warning { |msg| ... } => nil
+ * callbacks.on_parser_warning(msg)
*
- * Set the callback proc that receives parser warnings.
+ * Called for parser warnings.
*/
VALUE
-ruby_xml_sax_parser_on_parser_warning(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, xmlParserWarning);
+ruby_xml_sax_callbacks_on_parser_warning(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_parser_error { |msg| ... } => nil
+ * callbacks.on_parser_error(msg)
*
- * Set the callback proc that receives parser errors.
+ * Called for parser errors.
*/
VALUE
-ruby_xml_sax_parser_on_parser_error(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, xmlParserError);
+ruby_xml_sax_callbacks_on_parser_error(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_parser_fatal_error { |msg| ... } => nil
+ * callbacks.on_parser_fatal_error(msg)
*
- * Set the callback proc that receives fatal parser errors.
+ * Called for fatal parser errors.
*/
VALUE
-ruby_xml_sax_parser_on_parser_fatal_error(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, xmlParserFatalError);
+ruby_xml_sax_callbacks_on_parser_fatal_error(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_cdata_block { |cdata| ... } => nil
+ * callbacks.on_cdata_block(cdata)
*
- * Set the callback proc for a CDATA block event.
+ * Called for a CDATA block event.
*/
VALUE
-ruby_xml_sax_parser_on_cdata_block(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, cdataBlock);
+ruby_xml_sax_callbacks_on_cdata_block(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
/*
* call-seq:
- * parser.on_external_subset { |name, external_id, system_id| ... } => nil
+ * callbacks.on_external_subset(name, external_id, system_id)
*
- * Set the callback proc for an external subset event.
- */
-VALUE
-ruby_xml_sax_parser_on_external_subset(int argc, VALUE *argv, VALUE self) {
- set_handler(self, argc, argv, externalSubset);
-}
-
-
-/*
- * call-seq:
- * parser.parse => (true|false)
- *
- * Parse the input XML, generating callbacks to the procs
- * registered with the parser (via the on_xxxx attributes).
- */
-VALUE
-ruby_xml_sax_parser_parse(VALUE self) {
- char *str;
- int status = 1;
- ruby_xml_sax_parser *rxsp;
-
- Data_Get_Struct(self, ruby_xml_sax_parser, rxsp);
-
- if (rxsp->filename != Qnil) {
- status = xmlSAXUserParseFile(rxsp->xsh, rxsp->cbp, StringValuePtr(rxsp->filename));
- } else if (rxsp->str != Qnil) {
- str = StringValuePtr(rxsp->str);
- status = //ruby_xml_document_new(cXMLDocument,
- xmlSAXUserParseMemory(rxsp->xsh, rxsp->cbp,
- str, strlen(str)); //);
- }
-
- /* XXX This should return an exception for the various error codes
- * that can come back in status, but I'm too lazy to do that right
- * now. */
- if (status)
- return(Qfalse);
- else
- return(Qtrue);
-}
-
-
-/*
- * call-seq:
- * parser.string => "xml"
- *
- * Obtain the parser's input string.
+ * Called for an external subset event.
*/
VALUE
-ruby_xml_sax_parser_str_get(VALUE self) {
- ruby_xml_sax_parser *rxsp;
- Data_Get_Struct(self, ruby_xml_sax_parser, rxsp);
- return(rxsp->str);
+ruby_xml_sax_callbacks_on_external_subset(int argc, VALUE *argv, VALUE self) {
+ return Qnil;
}
-/*
- * call-seq:
- * parser.string = "xml"
- *
- * Set the parser's input string.
- */
-VALUE
-ruby_xml_sax_parser_str_set(VALUE self, VALUE str) {
- ruby_xml_sax_parser *rxsp;
- Check_Type(str, T_STRING);
- Data_Get_Struct(self, ruby_xml_sax_parser, rxsp);
- rxsp->str = str;
- return(rxsp->str);
-}
-
// Rdoc needs to know
#ifdef RDOC_NEVER_DEFINED
mXML = rb_define_module("XML");
@@ -377,50 +412,74 @@
void
ruby_init_xml_sax_parser(void) {
cXMLSaxParser = rb_define_class_under(mXML, "SaxParser", rb_cObject);
- callsym = rb_intern("call");
+ mXMLSaxParserCallbacks = rb_define_module_under(cXMLSaxParser, "Callbacks");
+ /* SaxParser */
rb_define_singleton_method(cXMLSaxParser, "new", ruby_xml_sax_parser_new, 0);
rb_define_method(cXMLSaxParser, "filename",
- ruby_xml_sax_parser_filename_get, 0);
+ ruby_xml_sax_parser_filename_get, 0);
rb_define_method(cXMLSaxParser, "filename=",
- ruby_xml_sax_parser_filename_set, 1);
+ ruby_xml_sax_parser_filename_set, 1);
+ rb_define_method(cXMLSaxParser, "callbacks",
+ ruby_xml_sax_parser_callbacks_get, 0);
+ rb_define_method(cXMLSaxParser, "callbacks=",
+ ruby_xml_sax_parser_callbacks_set, 1);
rb_define_method(cXMLSaxParser, "parse", ruby_xml_sax_parser_parse, 0);
rb_define_method(cXMLSaxParser, "string", ruby_xml_sax_parser_str_get, 0);
rb_define_method(cXMLSaxParser, "string=", ruby_xml_sax_parser_str_set, 1);
- rb_define_method(cXMLSaxParser, "on_internal_subset",
- ruby_xml_sax_parser_on_internal_subset, -1);
- rb_define_method(cXMLSaxParser, "on_is_standalone",
- ruby_xml_sax_parser_on_is_standalone, -1);
- rb_define_method(cXMLSaxParser, "on_has_internal_subset",
- ruby_xml_sax_parser_on_has_internal_subset, -1);
- rb_define_method(cXMLSaxParser, "on_has_external_subset",
- ruby_xml_sax_parser_on_has_external_subset, -1);
- rb_define_method(cXMLSaxParser, "on_start_document",
- ruby_xml_sax_parser_on_start_document, -1);
- rb_define_method(cXMLSaxParser, "on_end_document",
- ruby_xml_sax_parser_on_end_document, -1);
- rb_define_method(cXMLSaxParser, "on_start_element",
- ruby_xml_sax_parser_on_start_element, -1);
- rb_define_method(cXMLSaxParser, "on_end_element",
- ruby_xml_sax_parser_on_end_element, -1);
- rb_define_method(cXMLSaxParser, "on_reference",
- ruby_xml_sax_parser_on_reference, -1);
- rb_define_method(cXMLSaxParser, "on_characters",
- ruby_xml_sax_parser_on_characters, -1);
- rb_define_method(cXMLSaxParser, "on_processing_instruction",
- ruby_xml_sax_parser_on_processing_instruction, -1);
- rb_define_method(cXMLSaxParser, "on_comment",
- ruby_xml_sax_parser_on_comment, -1);
- rb_define_method(cXMLSaxParser, "on_parser_warning",
- ruby_xml_sax_parser_on_parser_warning, -1);
- rb_define_method(cXMLSaxParser, "on_parser_error",
- ruby_xml_sax_parser_on_parser_error, -1);
- rb_define_method(cXMLSaxParser, "on_parser_fatal_error",
- ruby_xml_sax_parser_on_parser_fatal_error, -1);
- rb_define_method(cXMLSaxParser, "on_cdata_block",
- ruby_xml_sax_parser_on_cdata_block, -1);
- rb_define_method(cXMLSaxParser, "on_external_subset",
- ruby_xml_sax_parser_on_external_subset, -1);
+ /* SaxCallbacks */
+ cbidOnInternalSubset = rb_intern("on_internal_subset");
+ cbidOnIsStandalone = rb_intern("on_is_standalone");
+ cbidOnHasInternalSubset = rb_intern("on_has_internal_subset");
+ cbidOnHasExternalSubset = rb_intern("on_has_external_subset");
+ cbidOnStartDocument = rb_intern("on_start_document");
+ cbidOnEndDocument = rb_intern("on_end_document");
+ cbidOnStartElement = rb_intern("on_start_element");
+ cbidOnEndElement = rb_intern("on_end_element");
+ cbidOnReference = rb_intern("on_reference");
+ cbidOnCharacters = rb_intern("on_characters");
+ cbidOnProcessingInstruction = rb_intern("on_processing_instruction");
+ cbidOnComment = rb_intern("on_comment");
+ cbidOnXmlParserWarning = rb_intern("on_parser_warning");
+ cbidOnXmlParserError = rb_intern("on_parser_error");
+ cbidOnXmlParserFatalError = rb_intern("on_parser_fatal_error");
+ cbidOnCdataBlock = rb_intern("on_cdata_block");
+ cbidOnExternalSubset = rb_intern("on_external_subset");
+
+ rb_define_method(mXMLSaxParserCallbacks, "on_internal_subset",
+ ruby_xml_sax_callbacks_on_internal_subset, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_is_standalone",
+ ruby_xml_sax_callbacks_on_is_standalone, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_has_internal_subset",
+ ruby_xml_sax_callbacks_on_has_internal_subset, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_has_external_subset",
+ ruby_xml_sax_callbacks_on_has_external_subset, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_start_document",
+ ruby_xml_sax_callbacks_on_start_document, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_end_document",
+ ruby_xml_sax_callbacks_on_end_document, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_start_element",
+ ruby_xml_sax_callbacks_on_start_element, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_end_element",
+ ruby_xml_sax_callbacks_on_end_element, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_reference",
+ ruby_xml_sax_callbacks_on_reference, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_characters",
+ ruby_xml_sax_callbacks_on_characters, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_processing_instruction",
+ ruby_xml_sax_callbacks_on_processing_instruction, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_comment",
+ ruby_xml_sax_callbacks_on_comment, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_parser_warning",
+ ruby_xml_sax_callbacks_on_parser_warning, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_parser_error",
+ ruby_xml_sax_callbacks_on_parser_error, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_parser_fatal_error",
+ ruby_xml_sax_callbacks_on_parser_fatal_error, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_cdata_block",
+ ruby_xml_sax_callbacks_on_cdata_block, -1);
+ rb_define_method(mXMLSaxParserCallbacks, "on_external_subset",
+ ruby_xml_sax_callbacks_on_external_subset, -1);
}
Index: ext/xml/ruby_xml_sax_parser.h
===================================================================
RCS file: /var/cvs/libxml/libxml/ext/xml/ruby_xml_sax_parser.h,v
retrieving revision 1.2
diff -u -d -r1.2 ruby_xml_sax_parser.h
--- ext/xml/ruby_xml_sax_parser.h 14 Apr 2006 14:45:52 -0000 1.2
+++ ext/xml/ruby_xml_sax_parser.h 31 May 2006 18:28:02 -0000
@@ -6,7 +6,9 @@
#define __RUBY_XML_SAX_PARSER__
extern VALUE cXMLSaxParser;
+extern VALUE mXMLSaxParserCallbacks;
+/*
typedef struct ruby_xml_sax_parser_callbacks {
VALUE internalSubset;
VALUE isStandalone;
@@ -36,11 +38,13 @@
VALUE cdataBlock;
VALUE externalSubset;
} ruby_xml_sax_parser_callbacks;
+*/
typedef struct ruby_xml_sax_parser {
xmlParserCtxtPtr xpc;
xmlSAXHandlerPtr xsh;
- ruby_xml_sax_parser_callbacks *cbp;
+ //ruby_xml_sax_parser_callbacks *cbp;
+ VALUE callbackHandler;
VALUE filename;
VALUE str;
} ruby_xml_sax_parser;
Index: ext/xml/sax_parser_callbacks.inc
===================================================================
RCS file: /var/cvs/libxml/libxml/ext/xml/sax_parser_callbacks.inc,v
retrieving revision 1.1
diff -u -d -r1.1 sax_parser_callbacks.inc
--- ext/xml/sax_parser_callbacks.inc 14 Apr 2006 14:50:58 -0000 1.1
+++ ext/xml/sax_parser_callbacks.inc 31 May 2006 18:28:03 -0000
@@ -5,61 +5,61 @@
/*
* SAX CALLBACK HANDLERS
*/
-static void internal_subset_func(ruby_xml_sax_parser_callbacks *cbp,
+static void internal_subset_func(ruby_xml_sax_parser *cbp,
const char *name,
const char *extid,
const char *sysid) {
- VALUE handler = cbp->internalSubset;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler, callsym, 3, rb_str_new2(name),
+ rb_funcall(handler, cbidOnInternalSubset, 3, rb_str_new2(name),
rb_str_new2(extid), rb_str_new2(sysid));
}
}
-static void is_standalone_func(ruby_xml_sax_parser_callbacks *cbp) {
- VALUE handler = cbp->isStandalone;
+static void is_standalone_func(ruby_xml_sax_parser *cbp) {
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,0);
+ rb_funcall(handler,cbidOnIsStandalone,0);
}
}
-static void has_internal_subset_func(ruby_xml_sax_parser_callbacks *cbp) {
- VALUE handler = cbp->hasInternalSubset;
+static void has_internal_subset_func(ruby_xml_sax_parser *cbp) {
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,0);
+ rb_funcall(handler,cbidOnHasInternalSubset,0);
}
}
-static void has_external_subset_func(ruby_xml_sax_parser_callbacks *cbp) {
- VALUE handler = cbp->hasExternalSubset;
+static void has_external_subset_func(ruby_xml_sax_parser *cbp) {
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,0);
+ rb_funcall(handler,cbidOnHasExternalSubset,0);
}
}
-static void start_document_func(ruby_xml_sax_parser_callbacks *cbp) {
- VALUE handler = cbp->startDocument;
+static void start_document_func(ruby_xml_sax_parser *cbp) {
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,0);
+ rb_funcall(handler,cbidOnStartDocument,0);
}
}
-static void end_document_func(ruby_xml_sax_parser_callbacks *cbp) {
- VALUE handler = cbp->endDocument;
+static void end_document_func(ruby_xml_sax_parser *cbp) {
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,0);
+ rb_funcall(handler,cbidOnEndDocument,0);
}
}
-static void start_element_func(ruby_xml_sax_parser_callbacks *cbp,
+static void start_element_func(ruby_xml_sax_parser *cbp,
const char *name, const char **attrs) {
- VALUE handler = cbp->startElement;
+ VALUE handler = cbp->callbackHandler;
VALUE ahsh = rb_hash_new();
const char *attr, *value;
@@ -71,101 +71,101 @@
}
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,2,rb_str_new2(name),ahsh);
+ rb_funcall(handler,cbidOnStartElement,2,rb_str_new2(name),ahsh);
}
}
-static void end_element_func(ruby_xml_sax_parser_callbacks *cbp,
+static void end_element_func(ruby_xml_sax_parser *cbp,
const char *name) {
- VALUE handler = cbp->endElement;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,1,rb_str_new2(name));
+ rb_funcall(handler,cbidOnEndElement,1,rb_str_new2(name));
}
}
-static void reference_func(ruby_xml_sax_parser_callbacks *cbp,
+static void reference_func(ruby_xml_sax_parser *cbp,
const char *name) {
- VALUE handler = cbp->reference;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,1,rb_str_new2(name));
+ rb_funcall(handler,cbidOnReference,1,rb_str_new2(name));
}
}
-static void characters_func(ruby_xml_sax_parser_callbacks *cbp,
+static void characters_func(ruby_xml_sax_parser *cbp,
const char *chars, int len) {
- VALUE handler = cbp->characters;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,1,rb_str_new(chars, len));
+ rb_funcall(handler,cbidOnCharacters,1,rb_str_new(chars, len));
}
}
-static void processing_instruction_func(ruby_xml_sax_parser_callbacks *cbp,
+static void processing_instruction_func(ruby_xml_sax_parser *cbp,
const char *target, const char *data) {
- VALUE handler = cbp->processingInstruction;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler, callsym, 2,
+ rb_funcall(handler, cbidOnProcessingInstruction, 2,
rb_str_new2(target),rb_str_new2(data));
}
}
-static void comment_func(ruby_xml_sax_parser_callbacks *cbp,
+static void comment_func(ruby_xml_sax_parser *cbp,
const char *msg) {
- VALUE handler = cbp->comment;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,1,rb_str_new2(msg));
+ rb_funcall(handler,cbidOnComment,1,rb_str_new2(msg));
}
}
// TODO these next three should actually be formatting messages.
-static void warning_func(ruby_xml_sax_parser_callbacks *cbp,
+static void warning_func(ruby_xml_sax_parser *cbp,
const char *msg, ...) {
- VALUE handler = cbp->xmlParserWarning;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,1,rb_str_new2(msg));
+ rb_funcall(handler,cbidOnXmlParserWarning,1,rb_str_new2(msg));
}
}
-static void error_func(ruby_xml_sax_parser_callbacks *cbp,
+static void error_func(ruby_xml_sax_parser *cbp,
const char *msg, ...) {
- VALUE handler = cbp->xmlParserError;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,1,rb_str_new2(msg));
+ rb_funcall(handler,cbidOnXmlParserError,1,rb_str_new2(msg));
}
}
-static void fatal_error_func(ruby_xml_sax_parser_callbacks *cbp,
+static void fatal_error_func(ruby_xml_sax_parser *cbp,
const char *msg, ...) {
- VALUE handler = cbp->xmlParserFatalError;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,1,rb_str_new2(msg));
+ rb_funcall(handler,cbidOnXmlParserFatalError,1,rb_str_new2(msg));
}
}
-static void cdata_block_func(ruby_xml_sax_parser_callbacks *cbp,
+static void cdata_block_func(ruby_xml_sax_parser *cbp,
const char *value, int len) {
- VALUE handler = cbp->cdataBlock;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler,callsym,1,rb_str_new(value, len));
+ rb_funcall(handler,cbidOnCdataBlock,1,rb_str_new(value, len));
}
}
-static void external_subset_func(ruby_xml_sax_parser_callbacks *cbp,
+static void external_subset_func(ruby_xml_sax_parser *cbp,
const char *name,
const char *extid,
const char *sysid) {
- VALUE handler = cbp->externalSubset;
+ VALUE handler = cbp->callbackHandler;
if (handler && handler != Qnil) {
- rb_funcall(handler, callsym, 3, rb_str_new2(name),
+ rb_funcall(handler, cbidOnExternalSubset, 3, rb_str_new2(name),
rb_str_new2(extid), rb_str_new2(sysid));
}
}
_______________________________________________
libxml-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/libxml-devel