150 lines
4.1 KiB
C
150 lines
4.1 KiB
C
#include <nokogiri.h>
|
|
|
|
VALUE cNokogiriXmlRelaxNG;
|
|
|
|
static void
|
|
_noko_xml_relax_ng_deallocate(void *data)
|
|
{
|
|
xmlRelaxNGPtr schema = data;
|
|
xmlRelaxNGFree(schema);
|
|
}
|
|
|
|
static const rb_data_type_t xml_relax_ng_type = {
|
|
.wrap_struct_name = "xmlRelaxNG",
|
|
.function = {
|
|
.dfree = _noko_xml_relax_ng_deallocate,
|
|
},
|
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
};
|
|
|
|
static VALUE
|
|
noko_xml_relax_ng__validate_document(VALUE self, VALUE document)
|
|
{
|
|
xmlDocPtr doc;
|
|
xmlRelaxNGPtr schema;
|
|
VALUE errors;
|
|
xmlRelaxNGValidCtxtPtr valid_ctxt;
|
|
|
|
TypedData_Get_Struct(self, xmlRelaxNG, &xml_relax_ng_type, schema);
|
|
doc = noko_xml_document_unwrap(document);
|
|
|
|
errors = rb_ary_new();
|
|
|
|
valid_ctxt = xmlRelaxNGNewValidCtxt(schema);
|
|
|
|
if (NULL == valid_ctxt) {
|
|
/* we have a problem */
|
|
rb_raise(rb_eRuntimeError, "Could not create a validation context");
|
|
}
|
|
|
|
xmlRelaxNGSetValidStructuredErrors(
|
|
valid_ctxt,
|
|
noko__error_array_pusher,
|
|
(void *)errors
|
|
);
|
|
|
|
xmlRelaxNGValidateDoc(valid_ctxt, doc);
|
|
|
|
xmlRelaxNGFreeValidCtxt(valid_ctxt);
|
|
|
|
return errors;
|
|
}
|
|
|
|
static VALUE
|
|
_noko_xml_relax_ng_parse_schema(
|
|
VALUE rb_class,
|
|
xmlRelaxNGParserCtxtPtr c_parser_context,
|
|
VALUE rb_parse_options
|
|
)
|
|
{
|
|
VALUE rb_errors;
|
|
VALUE rb_schema;
|
|
xmlRelaxNGPtr c_schema;
|
|
libxmlStructuredErrorHandlerState handler_state;
|
|
|
|
if (NIL_P(rb_parse_options)) {
|
|
rb_parse_options = rb_const_get_at(
|
|
rb_const_get_at(mNokogiriXml, rb_intern("ParseOptions")),
|
|
rb_intern("DEFAULT_SCHEMA")
|
|
);
|
|
}
|
|
|
|
rb_errors = rb_ary_new();
|
|
|
|
noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, noko__error_array_pusher);
|
|
xmlRelaxNGSetParserStructuredErrors(
|
|
c_parser_context,
|
|
noko__error_array_pusher,
|
|
(void *)rb_errors
|
|
);
|
|
|
|
c_schema = xmlRelaxNGParse(c_parser_context);
|
|
|
|
xmlRelaxNGFreeParserCtxt(c_parser_context);
|
|
noko__structured_error_func_restore(&handler_state);
|
|
|
|
if (NULL == c_schema) {
|
|
VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors);
|
|
|
|
if (RB_TEST(exception)) {
|
|
rb_exc_raise(exception);
|
|
} else {
|
|
rb_raise(rb_eRuntimeError, "Could not parse document");
|
|
}
|
|
}
|
|
|
|
rb_schema = TypedData_Wrap_Struct(rb_class, &xml_relax_ng_type, c_schema);
|
|
rb_iv_set(rb_schema, "@errors", rb_errors);
|
|
rb_iv_set(rb_schema, "@parse_options", rb_parse_options);
|
|
|
|
return rb_schema;
|
|
}
|
|
|
|
/*
|
|
* :call-seq:
|
|
* from_document(document) → Nokogiri::XML::RelaxNG
|
|
* from_document(document, parse_options) → Nokogiri::XML::RelaxNG
|
|
*
|
|
* Parse a RELAX NG schema definition from a Document to create a new Nokogiri::XML::RelaxNG.
|
|
*
|
|
* [Parameters]
|
|
* - +document+ (XML::Document) A document containing the RELAX NG schema definition
|
|
* - +parse_options+ (Nokogiri::XML::ParseOptions)
|
|
* Defaults to ParseOptions::DEFAULT_SCHEMA ⚠ Unused
|
|
*
|
|
* [Returns] Nokogiri::XML::RelaxNG
|
|
*
|
|
* ⚠ +parse_options+ is currently unused by this method and is present only as a placeholder for
|
|
* future functionality.
|
|
*/
|
|
static VALUE
|
|
noko_xml_relax_ng_s_from_document(int argc, VALUE *argv, VALUE rb_class)
|
|
{
|
|
/* TODO: deprecate this method and put file-or-string logic into .new so that becomes the
|
|
* preferred entry point, and this can become a private method */
|
|
VALUE rb_document;
|
|
VALUE rb_parse_options;
|
|
xmlDocPtr c_document;
|
|
xmlRelaxNGParserCtxtPtr c_parser_context;
|
|
|
|
rb_scan_args(argc, argv, "11", &rb_document, &rb_parse_options);
|
|
|
|
c_document = noko_xml_document_unwrap(rb_document);
|
|
c_document = c_document->doc; /* In case someone passes us a node. ugh. */
|
|
|
|
c_parser_context = xmlRelaxNGNewDocParserCtxt(c_document);
|
|
|
|
return _noko_xml_relax_ng_parse_schema(rb_class, c_parser_context, rb_parse_options);
|
|
}
|
|
|
|
void
|
|
noko_init_xml_relax_ng(void)
|
|
{
|
|
assert(cNokogiriXmlSchema);
|
|
cNokogiriXmlRelaxNG = rb_define_class_under(mNokogiriXml, "RelaxNG", cNokogiriXmlSchema);
|
|
|
|
rb_define_singleton_method(cNokogiriXmlRelaxNG, "from_document", noko_xml_relax_ng_s_from_document, -1);
|
|
|
|
rb_define_private_method(cNokogiriXmlRelaxNG, "validate_document", noko_xml_relax_ng__validate_document, 1);
|
|
}
|