Skip to content

Commit

Permalink
Remove usage of deprecated sax handlers.
Browse files Browse the repository at this point in the history
  • Loading branch information
cfis committed Jan 8, 2024
1 parent d8324b0 commit b0d1f07
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 125 deletions.
12 changes: 7 additions & 5 deletions ext/libxml/ruby_xml_html_parser_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,12 @@ static VALUE rxml_html_parser_context_string(int argc, VALUE* argv, VALUE klass)
VALUE string, options;
rb_scan_args(argc, argv, "11", &string, &options);

htmlParserCtxtPtr ctxt;
Check_Type(string, T_STRING);

if (RSTRING_LEN(string) == 0)
rb_raise(rb_eArgError, "Must specify a string with one or more characters");

ctxt = xmlCreateMemoryParserCtxt(StringValuePtr(string),
htmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt(StringValuePtr(string),
(int)RSTRING_LEN(string));
if (!ctxt)
rxml_raise(xmlGetLastError());
Expand All @@ -255,8 +254,11 @@ static VALUE rxml_html_parser_context_string(int argc, VALUE* argv, VALUE klass)
sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */
htmlCtxtUseOptions(ctxt, options == Qnil ? 0 : NUM2INT(options));

if (ctxt->sax != NULL)
memcpy(ctxt->sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1));
// Setup sax handler
// TODO - there must be a better way? The sax handler is initialized for XML, but we want
// to use HTML
memset(ctxt->sax, 0, sizeof(xmlSAXHandler));
xmlSAX2InitHtmlDefaultSAXHandler(ctxt->sax);

return rxml_html_parser_context_wrap(ctxt);
}
Expand Down Expand Up @@ -300,7 +302,7 @@ static VALUE rxml_html_parser_context_disable_cdata_set(VALUE self, VALUE value)
if (value)
ctxt->sax->cdataBlock = NULL;
else
ctxt->sax->cdataBlock = htmlDefaultSAXHandler.cdataBlock;
ctxt->sax->cdataBlock = xmlSAX2CDataBlock;

return value;
}
Expand Down
3 changes: 0 additions & 3 deletions ext/libxml/ruby_xml_namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ static VALUE rxml_namespace_initialize(VALUE self, VALUE node, VALUE prefix,
xmlPrefix = NIL_P(prefix) ? NULL : (xmlChar *)StringValuePtr(prefix);
xns = xmlNewNs(xnode, (xmlChar*) StringValuePtr(href), xmlPrefix);

if (!xns)
rxml_raise(xmlGetLastError());

DATA_PTR(self) = xns;
return self;
}
Expand Down
2 changes: 1 addition & 1 deletion ext/libxml/ruby_xml_parser_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ static VALUE rxml_parser_context_disable_cdata_set(VALUE self, VALUE value)
if (value)
ctxt->sax->cdataBlock = NULL;
else
ctxt->sax->cdataBlock = xmlDefaultSAXHandler.cdataBlock;
ctxt->sax->cdataBlock = xmlSAX2CDataBlock;

return value;
}
Expand Down
224 changes: 108 additions & 116 deletions ext/libxml/ruby_xml_sax_parser.c
Original file line number Diff line number Diff line change
@@ -1,116 +1,108 @@
/* 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);
}
/* 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)
{
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);
memcpy(ctxt->sax, &rxml_sax_handler, sizeof(rxml_sax_handler));

int 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);
}

0 comments on commit b0d1f07

Please sign in to comment.