#include "ruby_libxml.h" #define LIBXML_OUTPUT_ENABLED #define DUMP_CONTENT_MODEL #include "ruby_xml_schema.h" #include "ruby_xml_schema_type.h" #include "ruby_xml_schema_element.h" #include "ruby_xml_schema_attribute.h" #include "ruby_xml_schema_facet.h" /* * Document-class: LibXML::XML::Schema * * The XML::Schema class is used to prepare XML Schemas for validation of xml * documents. * * Schemas can be created from XML documents, strinings or URIs using the * corresponding methods (new for URIs). * * Once a schema is prepared, an XML document can be validated by the * XML::Document#validate_schema method providing the XML::Schema object * as parameter. The method return true if the document validates, false * otherwise. * * Basic usage: * * # parse schema as xml document * schema_document = XML::Document.file('schema.rng') * * # prepare schema for validation * schema = XML::Schema.document(schema_document) * * # parse xml document to be validated * instance = XML::Document.file('instance.xml') * * # validate * instance.validate_schema(schema) */ VALUE cXMLSchema; static void rxml_schema_free(xmlSchemaPtr xschema) { xmlSchemaFree(xschema); } VALUE rxml_wrap_schema(xmlSchemaPtr xschema) { return Data_Wrap_Struct(cXMLSchema, NULL, rxml_schema_free, xschema); } /* * call-seq: * XML::Schema.initialize(schema_uri) -> schema * * Create a new schema from the specified URI. */ static VALUE rxml_schema_init_from_uri(VALUE class, VALUE uri) { xmlSchemaParserCtxtPtr xparser; xmlSchemaPtr xschema; Check_Type(uri, T_STRING); xparser = xmlSchemaNewParserCtxt(StringValuePtr(uri)); xschema = xmlSchemaParse(xparser); xmlSchemaFreeParserCtxt(xparser); return Data_Wrap_Struct(cXMLSchema, NULL, rxml_schema_free, xschema); } /* * call-seq: * XML::Schema.document(document) -> schema * * Create a new schema from the specified document. */ static VALUE rxml_schema_init_from_document(VALUE class, VALUE document) { xmlDocPtr xdoc; xmlSchemaPtr xschema; xmlSchemaParserCtxtPtr xparser; Data_Get_Struct(document, xmlDoc, xdoc); xparser = xmlSchemaNewDocParserCtxt(xdoc); xschema = xmlSchemaParse(xparser); xmlSchemaFreeParserCtxt(xparser); if (xschema == NULL) return Qnil; return Data_Wrap_Struct(cXMLSchema, NULL, rxml_schema_free, xschema); } /* * call-seq: * XML::Schema.string("schema_data") -> "value" * * Create a new schema using the specified string. */ static VALUE rxml_schema_init_from_string(VALUE self, VALUE schema_str) { xmlSchemaParserCtxtPtr xparser; xmlSchemaPtr xschema; Check_Type(schema_str, T_STRING); xparser = xmlSchemaNewMemParserCtxt(StringValuePtr(schema_str), strlen( StringValuePtr(schema_str))); xschema = xmlSchemaParse(xparser); xmlSchemaFreeParserCtxt(xparser); return Data_Wrap_Struct(cXMLSchema, NULL, rxml_schema_free, xschema); } static VALUE rxml_schema_target_namespace(VALUE self) { xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); QNIL_OR_STRING(xschema->targetNamespace) } static VALUE rxml_schema_name(VALUE self) { xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); QNIL_OR_STRING(xschema->name) } static VALUE rxml_schema_version(VALUE self) { xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); QNIL_OR_STRING(xschema->version) } static VALUE rxml_schema_id(VALUE self) { xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); QNIL_OR_STRING(xschema->id) } static VALUE rxml_schema_document(VALUE self) { xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); return rxml_node_wrap(xmlDocGetRootElement(xschema->doc)); } static void storeNs(xmlSchemaImportPtr import, VALUE self, xmlChar *nsname) { VALUE schemas; xmlNodePtr xnode; xmlNsPtr xns; schemas = rb_iv_get(self, "@namespaces"); if (import->doc) { xnode = xmlDocGetRootElement(import->doc); xns = xnode->nsDef; while (xns) { VALUE anamespace = rxml_namespace_wrap(xns); rb_ary_push(schemas, anamespace); xns = xns->next; } } } static VALUE rxml_schema_namespaces(VALUE self) { VALUE schemas; xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); if (rb_iv_get(self, "@namespaces") == Qnil) { schemas = rb_ary_new(); rb_iv_set(self, "@namespaces", schemas); xmlHashScan(xschema->schemasImports, (xmlHashScanner) storeNs, (void *)self); } return rb_iv_get(self, "@namespaces"); } static void storeType(xmlSchemaTypePtr type, VALUE self, xmlChar *name) { VALUE types; VALUE rtype; types = rb_iv_get(self, "@types"); rtype = rxml_wrap_schema_type(type); rb_hash_aset(types, rb_str_new2(name), rtype); } static VALUE rxml_schema_collect_types(VALUE self); static VALUE rxml_schema_types(VALUE self) { VALUE types; xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); if (rb_iv_get(self, "@types") == Qnil) { types = rb_hash_new(); rb_iv_set(self, "@types", types); rxml_schema_collect_types(self); if(xschema != NULL && xschema->typeDecl != NULL) xmlHashScan(xschema->typeDecl, (xmlHashScanner) storeType, (void *)self); } return rb_iv_get(self, "@types"); } static void storeElement(xmlSchemaElementPtr element, VALUE self, xmlChar *name) { VALUE elements; VALUE relement; elements = rb_iv_get(self, "@elements"); relement = rxml_wrap_schema_element(element); rb_hash_aset(elements, rb_str_new2(name), relement); } static VALUE rxml_schema_elements(VALUE self) { VALUE elements; xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); if (rb_iv_get(self, "@elements") == Qnil) { elements = rb_hash_new(); rb_iv_set(self, "@elements", elements); xmlHashScan(xschema->elemDecl, (xmlHashScanner) storeElement, (void *)self); } return rb_iv_get(self, "@elements"); } static void collectSchemaTypes(xmlSchemaImportPtr import, VALUE self) { if (import->imported && import->schema) { xmlHashScan(import->schema->typeDecl, (xmlHashScanner) storeType, (void *)self); } } static VALUE rxml_schema_collect_types(VALUE self) { xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); if(xschema){ xmlHashScan(xschema->schemasImports, (xmlHashScanner) collectSchemaTypes, (void *)self); } return Qnil; } void rxml_init_schema(void) { cXMLSchema = rb_define_class_under(mXML, "Schema", rb_cObject); rb_define_singleton_method(cXMLSchema, "new", rxml_schema_init_from_uri, 1); rb_define_singleton_method(cXMLSchema, "from_string", rxml_schema_init_from_string, 1); rb_define_singleton_method(cXMLSchema, "document", rxml_schema_init_from_document, 1); rb_define_method(cXMLSchema, "target_namespace", rxml_schema_target_namespace, 0); rb_define_method(cXMLSchema, "name", rxml_schema_name, 0); rb_define_method(cXMLSchema, "id", rxml_schema_id, 0); rb_define_method(cXMLSchema, "version", rxml_schema_version, 0); rb_define_method(cXMLSchema, "document", rxml_schema_document, 0); rb_define_method(cXMLSchema, "_namespaces", rxml_schema_namespaces, 0); rb_define_method(cXMLSchema, "_collect_types", rxml_schema_collect_types, 0); rb_define_method(cXMLSchema, "types", rxml_schema_types, 0); rb_define_method(cXMLSchema, "elements", rxml_schema_elements, 0); rxml_init_schema_facet(); rxml_init_schema_element(); rxml_init_schema_attribute(); rxml_init_schema_type(); }