Hi - I have a simple SAX handler set up, and schema validation errors are being caught by my structured error handler. So far so good. It appears that the userdata argument to xmlSAXUserParseMemory
must be the xmlSchemaSAXPlugPtr returned by the call to xmlSchemaSAXPlug, and that this pointer is passed as the ctx pointer to the SAX handler callbacks. Is there any way for me to make a userdata pointer of my choosing available to my SAX handler callbacks while still getting schema validation? My code is below, thanks for any suggestions! Lara #include <iostream> #include <fstream> #include <sstream> #include <stdio.h> #include <memory.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> #include <libxml/xmlschemas.h> #include <string> std::string getFileContents( std::string filename ) { std::ifstream file ( filename ); std::string line; std::ostringstream fileContents; while ( std::getline ( file, line ) ) { fileContents << line << "\n"; } file.close ( ); return fileContents.str ( ); } void startElementNs( void * ctx, const xmlChar * localname, const xmlChar * prefix, const xmlChar * URI, int nb_namespaces, const xmlChar ** namespaces, int nb_attributes, int nb_defaulted, const xmlChar ** attributes) { fprintf(stderr, "startElementNs: ctx = %p\n", (unsigned long)ctx ); fprintf(stderr, "startElementNs: %s %s %s\n", (char*)prefix, (char*)localname, (char*)URI ); } void endElementNs( void * ctx, const xmlChar * localname, const xmlChar * prefix, const xmlChar * URI) { fprintf(stderr, "endElementNs: ctx = %p\n", (unsigned long)ctx ); fprintf(stderr, "endElementNs: %s %s %s\n", (char*)prefix, (char*)localname, (char*)URI ); } void structuredErrors(void *userdata, xmlErrorPtr error) { fprintf(stderr, "Structured error userdata=%p\n", userdata ); fprintf(stderr, "Structured error (%s, line %d): %s\n", error->file, error->line, error->message); } int main(int argc, const char * argv[]) { if ( argc != 3 ) { fprintf( stderr, "Usage: %s <xml file> <schema file>\n", argv[0] ); exit(1); } const char* filename = argv[1]; const char* schema = argv[2]; std::string xmlIn = getFileContents( filename ); xmlSAXHandler *schemaValHandler = new xmlSAXHandler; memset( schemaValHandler, 0, sizeof(xmlSAXHandler) ); schemaValHandler->initialized = XML_SAX2_MAGIC; schemaValHandler->error = NULL; schemaValHandler->warning = warning; schemaValHandler->startElementNs = startElementNs; schemaValHandler->endElementNs = endElementNs; schemaValHandler->startElement = NULL; schemaValHandler->endElement = NULL; xmlSchemaParserCtxtPtr parseCtxt = xmlSchemaNewParserCtxt(schema); xmlSchemaPtr xsdSchemas = xmlSchemaParse(parseCtxt); xmlSchemaValidCtxtPtr xsdValidCtxt = xmlSchemaNewValidCtxt(xsdSchemas); xmlSchemaSetValidStructuredErrors(xsdValidCtxt, structuredErrors, NULL ); // userdata arg is set to the pointer to the original SAX user data pointer xmlSchemaValidCtxtPtr oldXsdValidCtxt = NULL;; void *ctxptr = &oldXsdValidCtxt; xmlSchemaSAXPlugPtr saxPlug = xmlSchemaSAXPlug(xsdValidCtxt, &schemaValHandler, &ctxptr ); // !!!!!!!! the userdata in the second argument MUST be the xmlSchemaSAXPlugPtr, the pointer value is in // !!!!!!!! both saxPlug and ctxptr // !!!!!!!! This pointer is passed to functions such as startElementNsSplit that are configured in // !!!!!!!! the call to xmlSchemaSAXPlug, which cast the pointer to a xmlSchemaSAXPlugPtr, so if you // !!!!!!!! try to pass ANY other pointer, you'll get a crash int result = xmlSAXUserParseMemory( schemaValHandler, ctxptr, xmlIn.c_str(), xmlIn.length() ); if ( result != 0 ) { fprintf(stderr, "Failed to parse document.\n" ); } xmlCleanupParser(); xmlSchemaSAXUnplug( saxPlug ); xmlSchemaFreeValidCtxt(xsdValidCtxt); xmlSchemaFree(xsdSchemas); xmlSchemaFreeParserCtxt(parseCtxt); delete schemaValHandler; return 0; } Lara Blatchford Principal Engineer Nteligen, LLC lara blatchford nteligen com (443) 864-5042 x110 |