/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_sax_parser.h" /* * Document-class: LibXML::XML::SaxParser * * XML::SaxParser provides a callback based API for parsing documents, * in contrast to XML::Parser's tree based API and XML::Reader's stream * based API. * * The XML::SaxParser API is fairly complex, not well standardized, * and does not directly support validation making entity, namespace and * base processing relatively hard. * * To use the XML::SaxParser, register a callback class via the * XML::SaxParser#callbacks=. It is easiest to include the * XML::SaxParser::Callbacks module in your class and override * the methods as needed. * * Basic example: * * class MyCallbacks * include XML::SaxParser::Callbacks * def on_start_element(element, attributes) * puts #Element started: #{element}" * end * end * * parser = XML::SaxParser.string(my_string) * parser.callbacks = MyCallbacks.new * parser.parse * * You can also parse strings (see XML::SaxParser.string) and * io objects (see XML::SaxParser.io). */ VALUE cXMLSaxParser; static ID CALLBACKS_ATTR; static ID CONTEXT_ATTR; /* ====== Parser =========== */ /* * call-seq: * parser.initialize(context) -> XML::Parser * * Creates a new XML::Parser from the specified * XML::Parser::Context. */ static VALUE rxml_sax_parser_initialize(int argc, VALUE *argv, VALUE self) { VALUE context = Qnil; rb_scan_args(argc, argv, "01", &context); if (context == Qnil) { rb_raise(rb_eArgError, "An instance of a XML::Parser::Context must be passed to XML::SaxParser.new"); } rb_ivar_set(self, CONTEXT_ATTR, context); return self; } /* * call-seq: * parser.parse -> (true|false) * * Parse the input XML, generating callbacks to the object * registered via the +callbacks+ attributesibute. */ static VALUE rxml_sax_parser_parse(VALUE self) { int status; VALUE context = rb_ivar_get(self, CONTEXT_ATTR); xmlParserCtxtPtr ctxt; Data_Get_Struct(context, xmlParserCtxt, ctxt); ctxt->sax2 = 1; ctxt->userData = (void*)rb_ivar_get(self, CALLBACKS_ATTR); if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) xmlFree(ctxt->sax); ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(rxml_sax_handler)); if (ctxt->sax == NULL) rb_fatal("Not enough memory."); memcpy(ctxt->sax, &rxml_sax_handler, sizeof(rxml_sax_handler)); status = xmlParseDocument(ctxt); /* Now check the parsing result*/ if (status == -1 || !ctxt->wellFormed) { rxml_raise(&ctxt->lastError); } return Qtrue; } void rxml_init_sax_parser(void) { /* SaxParser */ cXMLSaxParser = rb_define_class_under(mXML, "SaxParser", rb_cObject); /* Atributes */ CALLBACKS_ATTR = rb_intern("@callbacks"); CONTEXT_ATTR = rb_intern("@context"); rb_define_attr(cXMLSaxParser, "callbacks", 1, 1); /* Instance Methods */ rb_define_method(cXMLSaxParser, "initialize", rxml_sax_parser_initialize, -1); rb_define_method(cXMLSaxParser, "parse", rxml_sax_parser_parse, 0); }