Alexey Mironov
Alexey Mironov

Reputation: 11

How to stop parsing xml document with LIBXML SAX at any time?

I have win32 c++ code that uses LIBXML SAX parser. This code parses big xml file (>1Gb) and validates it via xsd schema. When xsd validation error raises LIBXML invokes callback and continues parsing. I want to stop the parsing process in this callback. So far I achieve this result by raising c++ exception. But this approach leaves unreleased resources and causes memory leaks.

SAX Running code:

xmlSchemaParserCtxtPtr  sch = xmlSchemaNewParserCtxt("MUXGate.xsd");
xmlSchemaPtr schema = xmlSchemaParse(sch);  
xmlSchemaValidCtxtPtr vsch = xmlSchemaNewValidCtxt(schema);     
context.vsch = xmlSchemaNewValidCtxt(schema);
xmlSchemaSetValidErrors(
    vsch,
    xmlMySchemaValidityErrorFunc,
    xmlMySchemaValidityWarningFunc,
    &context);

xmlSAXHandlerPtr hndlrptr = &my_handler;
void* ctxptr = &context;
xmlSchemaSAXPlugPtr saxPlug = xmlSchemaSAXPlug(vsch,&hndlrptr,&ctxptr);     


try{
    if (xmlSAXUserParseFile(hndlrptr, ctxptr , "errschema.xml1") < 0) {
        xmess<<"Parse error\n";
    } else
        xmess<<"Parse ok\n";

    if(context.SchemaError)
    {
        xmess <<"Schema error\n";
    }
}   
catch(...) //Catching exception
{
    xmess<<"Exception\n";
}

xmlSchemaSAXUnplug(saxPlug);
xmlSchemaFreeValidCtxt(context.vsch);
xmlSchemaFreeValidCtxt(vsch);
xmlSchemaFree(schema);
xmlSchemaFreeParserCtxt(sch);

Schema error callback:

void    xmlMySchemaValidityErrorFunc    (void * ctx, 
                                 const char * msg, 
                                 ...)
{
MyContext& context = *(MyContext*)ctx;
context.SchemaError = true;

char buf[1024];
va_list args;

va_start(args, msg);
int len = vsnprintf_s(buf, sizeof(buf), sizeof(buf)/sizeof(buf[0]), msg, args);
va_end(args);

puts(buf);

throw new int(1); //throwing an exception
}

There is a function void xmlStopParser (xmlParserCtxtPtr ctxt) but there is no parser context in schema error callback function.

Please help! Thank you!

Upvotes: 1

Views: 819

Answers (1)

Mark Niebur
Mark Niebur

Reputation: 11

I know you posted this a long time ago, so you might not care anymore, but I had a similar issue. In case anyone else runs into it I think the answer is using the push context. This is where you continuously push new data into the parser. When you encounter the error, you can stop pushing data and call the free. Here is some example code from libxml2's testSAX.c:

if (sax2)
    ctxt = xmlCreatePushParserCtxt(debugSAX2Handler, NULL,
        chars, ret, filename);
else
    ctxt = xmlCreatePushParserCtxt(debugSAXHandler, NULL,
        chars, ret, filename);
while ((ret = fread(chars, 1, 3, f)) > 0) {
    xmlParseChunk(ctxt, chars, ret, 0);
}
ret = xmlParseChunk(ctxt, chars, 0, 1);
xmlFreeParserCtxt(ctxt);

Upvotes: 1

Related Questions