Annotation of embedaddon/libxml2/schematron.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * schematron.c : implementation of the Schematron schema validity checking
        !             3:  *
        !             4:  * See Copyright for the status of this software.
        !             5:  *
        !             6:  * Daniel Veillard <daniel@veillard.com>
        !             7:  */
        !             8: 
        !             9: /*
        !            10:  * TODO:
        !            11:  * + double check the semantic, especially
        !            12:  *        - multiple rules applying in a single pattern/node
        !            13:  *        - the semantic of libxml2 patterns vs. XSLT production referenced
        !            14:  *          by the spec.
        !            15:  * + export of results in SVRL
        !            16:  * + full parsing and coverage of the spec, conformance of the input to the
        !            17:  *   spec
        !            18:  * + divergences between the draft and the ISO proposed standard :-(
        !            19:  * + hook and test include
        !            20:  * + try and compare with the XSLT version
        !            21:  */
        !            22: 
        !            23: #define IN_LIBXML
        !            24: #include "libxml.h"
        !            25: 
        !            26: #ifdef LIBXML_SCHEMATRON_ENABLED
        !            27: 
        !            28: #include <string.h>
        !            29: #include <libxml/parser.h>
        !            30: #include <libxml/tree.h>
        !            31: #include <libxml/uri.h>
        !            32: #include <libxml/xpath.h>
        !            33: #include <libxml/xpathInternals.h>
        !            34: #include <libxml/pattern.h>
        !            35: #include <libxml/schematron.h>
        !            36: 
        !            37: #define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT
        !            38: 
        !            39: #define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron"
        !            40: 
        !            41: #define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron"
        !            42: 
        !            43: 
        !            44: static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS;
        !            45: static const xmlChar *xmlOldSchematronNs = SCT_OLD_NS;
        !            46: 
        !            47: #define IS_SCHEMATRON(node, elem)                                      \
        !            48:    ((node != NULL) && (node->type == XML_ELEMENT_NODE ) &&             \
        !            49:     (node->ns != NULL) &&                                              \
        !            50:     (xmlStrEqual(node->name, (const xmlChar *) elem)) &&               \
        !            51:     ((xmlStrEqual(node->ns->href, xmlSchematronNs)) ||                 \
        !            52:      (xmlStrEqual(node->ns->href, xmlOldSchematronNs))))
        !            53: 
        !            54: #define NEXT_SCHEMATRON(node)                                          \
        !            55:    while (node != NULL) {                                              \
        !            56:        if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) &&  \
        !            57:            ((xmlStrEqual(node->ns->href, xmlSchematronNs)) ||          \
        !            58:            (xmlStrEqual(node->ns->href, xmlOldSchematronNs))))         \
        !            59:           break;                                                       \
        !            60:        node = node->next;                                              \
        !            61:    }
        !            62: 
        !            63: /**
        !            64:  * TODO:
        !            65:  *
        !            66:  * macro to flag unimplemented blocks
        !            67:  */
        !            68: #define TODO                                                           \
        !            69:     xmlGenericError(xmlGenericErrorContext,                            \
        !            70:            "Unimplemented block at %s:%d\n",                           \
        !            71:             __FILE__, __LINE__);
        !            72: 
        !            73: typedef enum {
        !            74:     XML_SCHEMATRON_ASSERT=1,
        !            75:     XML_SCHEMATRON_REPORT=2
        !            76: } xmlSchematronTestType;
        !            77: 
        !            78: /**
        !            79:  * _xmlSchematronTest:
        !            80:  *
        !            81:  * A Schematrons test, either an assert or a report
        !            82:  */
        !            83: typedef struct _xmlSchematronTest xmlSchematronTest;
        !            84: typedef xmlSchematronTest *xmlSchematronTestPtr;
        !            85: struct _xmlSchematronTest {
        !            86:     xmlSchematronTestPtr next; /* the next test in the list */
        !            87:     xmlSchematronTestType type;        /* the test type */
        !            88:     xmlNodePtr node;           /* the node in the tree */
        !            89:     xmlChar *test;             /* the expression to test */
        !            90:     xmlXPathCompExprPtr comp;  /* the compiled expression */
        !            91:     xmlChar *report;           /* the message to report */
        !            92: };
        !            93: 
        !            94: /**
        !            95:  * _xmlSchematronRule:
        !            96:  *
        !            97:  * A Schematrons rule
        !            98:  */
        !            99: typedef struct _xmlSchematronRule xmlSchematronRule;
        !           100: typedef xmlSchematronRule *xmlSchematronRulePtr;
        !           101: struct _xmlSchematronRule {
        !           102:     xmlSchematronRulePtr next; /* the next rule in the list */
        !           103:     xmlSchematronRulePtr patnext;/* the next rule in the pattern list */
        !           104:     xmlNodePtr node;           /* the node in the tree */
        !           105:     xmlChar *context;          /* the context evaluation rule */
        !           106:     xmlSchematronTestPtr tests;        /* the list of tests */
        !           107:     xmlPatternPtr pattern;     /* the compiled pattern associated */
        !           108:     xmlChar *report;           /* the message to report */
        !           109: };
        !           110: 
        !           111: /**
        !           112:  * _xmlSchematronPattern:
        !           113:  *
        !           114:  * A Schematrons pattern
        !           115:  */
        !           116: typedef struct _xmlSchematronPattern xmlSchematronPattern;
        !           117: typedef xmlSchematronPattern *xmlSchematronPatternPtr;
        !           118: struct _xmlSchematronPattern {
        !           119:     xmlSchematronPatternPtr next;/* the next pattern in the list */
        !           120:     xmlSchematronRulePtr rules;        /* the list of rules */
        !           121:     xmlChar *name;             /* the name of the pattern */
        !           122: };
        !           123: 
        !           124: /**
        !           125:  * _xmlSchematron:
        !           126:  *
        !           127:  * A Schematrons definition
        !           128:  */
        !           129: struct _xmlSchematron {
        !           130:     const xmlChar *name;       /* schema name */
        !           131:     int preserve;              /* was the document passed by the user */
        !           132:     xmlDocPtr doc;             /* pointer to the parsed document */
        !           133:     int flags;                 /* specific to this schematron */
        !           134: 
        !           135:     void *_private;            /* unused by the library */
        !           136:     xmlDictPtr dict;           /* the dictionnary used internally */
        !           137: 
        !           138:     const xmlChar *title;      /* the title if any */
        !           139: 
        !           140:     int nbNs;                  /* the number of namespaces */
        !           141: 
        !           142:     int nbPattern;             /* the number of patterns */
        !           143:     xmlSchematronPatternPtr patterns;/* the patterns found */
        !           144:     xmlSchematronRulePtr rules;        /* the rules gathered */
        !           145:     int nbNamespaces;          /* number of namespaces in the array */
        !           146:     int maxNamespaces;         /* size of the array */
        !           147:     const xmlChar **namespaces;        /* the array of namespaces */
        !           148: };
        !           149: 
        !           150: /**
        !           151:  * xmlSchematronValidCtxt:
        !           152:  *
        !           153:  * A Schematrons validation context
        !           154:  */
        !           155: struct _xmlSchematronValidCtxt {
        !           156:     int type;
        !           157:     int flags;                 /* an or of xmlSchematronValidOptions */
        !           158: 
        !           159:     xmlDictPtr dict;
        !           160:     int nberrors;
        !           161:     int err;
        !           162: 
        !           163:     xmlSchematronPtr schema;
        !           164:     xmlXPathContextPtr xctxt;
        !           165: 
        !           166:     FILE *outputFile;          /* if using XML_SCHEMATRON_OUT_FILE */
        !           167:     xmlBufferPtr outputBuffer; /* if using XML_SCHEMATRON_OUT_BUFFER */
        !           168:     xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */
        !           169:     xmlOutputCloseCallback  ioclose;
        !           170:     void *ioctx;
        !           171: 
        !           172:     /* error reporting data */
        !           173:     void *userData;                      /* user specific data block */
        !           174:     xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
        !           175:     xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
        !           176:     xmlStructuredErrorFunc serror;       /* the structured function */
        !           177: };
        !           178: 
        !           179: struct _xmlSchematronParserCtxt {
        !           180:     int type;
        !           181:     const xmlChar *URL;
        !           182:     xmlDocPtr doc;
        !           183:     int preserve;               /* Whether the doc should be freed  */
        !           184:     const char *buffer;
        !           185:     int size;
        !           186: 
        !           187:     xmlDictPtr dict;            /* dictionnary for interned string names */
        !           188: 
        !           189:     int nberrors;
        !           190:     int err;
        !           191:     xmlXPathContextPtr xctxt;  /* the XPath context used for compilation */
        !           192:     xmlSchematronPtr schema;
        !           193: 
        !           194:     int nbNamespaces;          /* number of namespaces in the array */
        !           195:     int maxNamespaces;         /* size of the array */
        !           196:     const xmlChar **namespaces;        /* the array of namespaces */
        !           197: 
        !           198:     int nbIncludes;            /* number of includes in the array */
        !           199:     int maxIncludes;           /* size of the array */
        !           200:     xmlNodePtr *includes;      /* the array of includes */
        !           201: 
        !           202:     /* error reporting data */
        !           203:     void *userData;                      /* user specific data block */
        !           204:     xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
        !           205:     xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
        !           206:     xmlStructuredErrorFunc serror;       /* the structured function */
        !           207: };
        !           208: 
        !           209: #define XML_STRON_CTXT_PARSER 1
        !           210: #define XML_STRON_CTXT_VALIDATOR 2
        !           211: 
        !           212: /************************************************************************
        !           213:  *                                                                     *
        !           214:  *                     Error reporting                                 *
        !           215:  *                                                                     *
        !           216:  ************************************************************************/
        !           217: 
        !           218: /**
        !           219:  * xmlSchematronPErrMemory:
        !           220:  * @node: a context node
        !           221:  * @extra:  extra informations
        !           222:  *
        !           223:  * Handle an out of memory condition
        !           224:  */
        !           225: static void
        !           226: xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt,
        !           227:                         const char *extra, xmlNodePtr node)
        !           228: {
        !           229:     if (ctxt != NULL)
        !           230:         ctxt->nberrors++;
        !           231:     __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
        !           232:                      extra);
        !           233: }
        !           234: 
        !           235: /**
        !           236:  * xmlSchematronPErr:
        !           237:  * @ctxt: the parsing context
        !           238:  * @node: the context node
        !           239:  * @error: the error code
        !           240:  * @msg: the error message
        !           241:  * @str1: extra data
        !           242:  * @str2: extra data
        !           243:  * 
        !           244:  * Handle a parser error
        !           245:  */
        !           246: static void
        !           247: xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error,
        !           248:               const char *msg, const xmlChar * str1, const xmlChar * str2)
        !           249: {
        !           250:     xmlGenericErrorFunc channel = NULL;
        !           251:     xmlStructuredErrorFunc schannel = NULL;
        !           252:     void *data = NULL;
        !           253: 
        !           254:     if (ctxt != NULL) {
        !           255:         ctxt->nberrors++;
        !           256:         channel = ctxt->error;
        !           257:         data = ctxt->userData;
        !           258:        schannel = ctxt->serror;
        !           259:     }
        !           260:     __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
        !           261:                     error, XML_ERR_ERROR, NULL, 0,
        !           262:                     (const char *) str1, (const char *) str2, NULL, 0, 0,
        !           263:                     msg, str1, str2);
        !           264: }
        !           265: 
        !           266: /**
        !           267:  * xmlSchematronVTypeErrMemory:
        !           268:  * @node: a context node
        !           269:  * @extra:  extra informations
        !           270:  *
        !           271:  * Handle an out of memory condition
        !           272:  */
        !           273: static void
        !           274: xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt,
        !           275:                         const char *extra, xmlNodePtr node)
        !           276: {
        !           277:     if (ctxt != NULL) {
        !           278:         ctxt->nberrors++;
        !           279:         ctxt->err = XML_SCHEMAV_INTERNAL;
        !           280:     }
        !           281:     __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
        !           282:                      extra);
        !           283: }
        !           284: 
        !           285: /************************************************************************
        !           286:  *                                                                     *
        !           287:  *             Parsing and compilation of the Schematrontrons          *
        !           288:  *                                                                     *
        !           289:  ************************************************************************/
        !           290: 
        !           291: /**
        !           292:  * xmlSchematronAddTest:
        !           293:  * @ctxt: the schema parsing context
        !           294:  * @type:  the type of test
        !           295:  * @rule:  the parent rule
        !           296:  * @node:  the node hosting the test
        !           297:  * @test: the associated test
        !           298:  * @report: the associated report string
        !           299:  *
        !           300:  * Add a test to a schematron
        !           301:  *
        !           302:  * Returns the new pointer or NULL in case of error
        !           303:  */
        !           304: static xmlSchematronTestPtr
        !           305: xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt,
        !           306:                      xmlSchematronTestType type,
        !           307:                      xmlSchematronRulePtr rule,
        !           308:                      xmlNodePtr node, xmlChar *test, xmlChar *report)
        !           309: {
        !           310:     xmlSchematronTestPtr ret;
        !           311:     xmlXPathCompExprPtr comp;
        !           312: 
        !           313:     if ((ctxt == NULL) || (rule == NULL) || (node == NULL) ||
        !           314:         (test == NULL))
        !           315:         return(NULL);
        !           316: 
        !           317:     /*
        !           318:      * try first to compile the test expression
        !           319:      */
        !           320:     comp = xmlXPathCtxtCompile(ctxt->xctxt, test);
        !           321:     if (comp == NULL) {
        !           322:        xmlSchematronPErr(ctxt, node,
        !           323:            XML_SCHEMAP_NOROOT,
        !           324:            "Failed to compile test expression %s",
        !           325:            test, NULL);
        !           326:        return(NULL);
        !           327:     }
        !           328: 
        !           329:     ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest));
        !           330:     if (ret == NULL) {
        !           331:         xmlSchematronPErrMemory(ctxt, "allocating schema test", node);
        !           332:         return (NULL);
        !           333:     }
        !           334:     memset(ret, 0, sizeof(xmlSchematronTest));
        !           335:     ret->type = type;
        !           336:     ret->node = node;
        !           337:     ret->test = test;
        !           338:     ret->comp = comp;
        !           339:     ret->report = report;
        !           340:     ret->next = NULL;
        !           341:     if (rule->tests == NULL) {
        !           342:        rule->tests = ret;
        !           343:     } else {
        !           344:         xmlSchematronTestPtr prev = rule->tests;
        !           345: 
        !           346:        while (prev->next != NULL)
        !           347:             prev = prev->next;
        !           348:         prev->next = ret;
        !           349:     }
        !           350:     return (ret);
        !           351: }
        !           352: 
        !           353: /**
        !           354:  * xmlSchematronFreeTests:
        !           355:  * @tests:  a list of tests
        !           356:  *
        !           357:  * Free a list of tests.
        !           358:  */
        !           359: static void
        !           360: xmlSchematronFreeTests(xmlSchematronTestPtr tests) {
        !           361:     xmlSchematronTestPtr next;
        !           362: 
        !           363:     while (tests != NULL) {
        !           364:         next = tests->next;
        !           365:        if (tests->test != NULL)
        !           366:            xmlFree(tests->test);
        !           367:        if (tests->comp != NULL)
        !           368:            xmlXPathFreeCompExpr(tests->comp);
        !           369:        if (tests->report != NULL)
        !           370:            xmlFree(tests->report);
        !           371:        xmlFree(tests);
        !           372:        tests = next;
        !           373:     }
        !           374: }
        !           375: 
        !           376: /**
        !           377:  * xmlSchematronAddRule:
        !           378:  * @ctxt: the schema parsing context
        !           379:  * @schema:  a schema structure
        !           380:  * @node:  the node hosting the rule
        !           381:  * @context: the associated context string
        !           382:  * @report: the associated report string
        !           383:  *
        !           384:  * Add a rule to a schematron
        !           385:  *
        !           386:  * Returns the new pointer or NULL in case of error
        !           387:  */
        !           388: static xmlSchematronRulePtr
        !           389: xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema,
        !           390:                      xmlSchematronPatternPtr pat, xmlNodePtr node,
        !           391:                     xmlChar *context, xmlChar *report)
        !           392: {
        !           393:     xmlSchematronRulePtr ret;
        !           394:     xmlPatternPtr pattern;
        !           395: 
        !           396:     if ((ctxt == NULL) || (schema == NULL) || (node == NULL) ||
        !           397:         (context == NULL))
        !           398:         return(NULL);
        !           399: 
        !           400:     /*
        !           401:      * Try first to compile the pattern
        !           402:      */
        !           403:     pattern = xmlPatterncompile(context, ctxt->dict, XML_PATTERN_XPATH,
        !           404:                                 ctxt->namespaces);
        !           405:     if (pattern == NULL) {
        !           406:        xmlSchematronPErr(ctxt, node,
        !           407:            XML_SCHEMAP_NOROOT,
        !           408:            "Failed to compile context expression %s",
        !           409:            context, NULL);
        !           410:     }
        !           411: 
        !           412:     ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule));
        !           413:     if (ret == NULL) {
        !           414:         xmlSchematronPErrMemory(ctxt, "allocating schema rule", node);
        !           415:         return (NULL);
        !           416:     }
        !           417:     memset(ret, 0, sizeof(xmlSchematronRule));
        !           418:     ret->node = node;
        !           419:     ret->context = context;
        !           420:     ret->pattern = pattern;
        !           421:     ret->report = report;
        !           422:     ret->next = NULL;
        !           423:     if (schema->rules == NULL) {
        !           424:        schema->rules = ret;
        !           425:     } else {
        !           426:         xmlSchematronRulePtr prev = schema->rules;
        !           427: 
        !           428:        while (prev->next != NULL)
        !           429:             prev = prev->next;
        !           430:         prev->next = ret;
        !           431:     }
        !           432:     ret->patnext = NULL;
        !           433:     if (pat->rules == NULL) {
        !           434:        pat->rules = ret;
        !           435:     } else {
        !           436:         xmlSchematronRulePtr prev = pat->rules;
        !           437: 
        !           438:        while (prev->patnext != NULL)
        !           439:             prev = prev->patnext;
        !           440:         prev->patnext = ret;
        !           441:     }
        !           442:     return (ret);
        !           443: }
        !           444: 
        !           445: /**
        !           446:  * xmlSchematronFreeRules:
        !           447:  * @rules:  a list of rules
        !           448:  *
        !           449:  * Free a list of rules.
        !           450:  */
        !           451: static void
        !           452: xmlSchematronFreeRules(xmlSchematronRulePtr rules) {
        !           453:     xmlSchematronRulePtr next;
        !           454: 
        !           455:     while (rules != NULL) {
        !           456:         next = rules->next;
        !           457:        if (rules->tests)
        !           458:            xmlSchematronFreeTests(rules->tests);
        !           459:        if (rules->context != NULL)
        !           460:            xmlFree(rules->context);
        !           461:        if (rules->pattern)
        !           462:            xmlFreePattern(rules->pattern);
        !           463:        if (rules->report != NULL)
        !           464:            xmlFree(rules->report);
        !           465:        xmlFree(rules);
        !           466:        rules = next;
        !           467:     }
        !           468: }
        !           469: 
        !           470: /**
        !           471:  * xmlSchematronAddPattern:
        !           472:  * @ctxt: the schema parsing context
        !           473:  * @schema:  a schema structure
        !           474:  * @node:  the node hosting the pattern
        !           475:  * @id: the id or name of the pattern
        !           476:  *
        !           477:  * Add a pattern to a schematron
        !           478:  *
        !           479:  * Returns the new pointer or NULL in case of error
        !           480:  */
        !           481: static xmlSchematronPatternPtr
        !           482: xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt,
        !           483:                      xmlSchematronPtr schema, xmlNodePtr node, xmlChar *name)
        !           484: {
        !           485:     xmlSchematronPatternPtr ret;
        !           486: 
        !           487:     if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (name == NULL))
        !           488:         return(NULL);
        !           489: 
        !           490:     ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern));
        !           491:     if (ret == NULL) {
        !           492:         xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node);
        !           493:         return (NULL);
        !           494:     }
        !           495:     memset(ret, 0, sizeof(xmlSchematronPattern));
        !           496:     ret->name = name;
        !           497:     ret->next = NULL;
        !           498:     if (schema->patterns == NULL) {
        !           499:        schema->patterns = ret;
        !           500:     } else {
        !           501:         xmlSchematronPatternPtr prev = schema->patterns;
        !           502: 
        !           503:        while (prev->next != NULL)
        !           504:             prev = prev->next;
        !           505:         prev->next = ret;
        !           506:     }
        !           507:     return (ret);
        !           508: }
        !           509: 
        !           510: /**
        !           511:  * xmlSchematronFreePatterns:
        !           512:  * @patterns:  a list of patterns
        !           513:  *
        !           514:  * Free a list of patterns.
        !           515:  */
        !           516: static void
        !           517: xmlSchematronFreePatterns(xmlSchematronPatternPtr patterns) {
        !           518:     xmlSchematronPatternPtr next;
        !           519: 
        !           520:     while (patterns != NULL) {
        !           521:         next = patterns->next;
        !           522:        if (patterns->name != NULL)
        !           523:            xmlFree(patterns->name);
        !           524:        xmlFree(patterns);
        !           525:        patterns = next;
        !           526:     }
        !           527: }
        !           528: 
        !           529: /**
        !           530:  * xmlSchematronNewSchematron:
        !           531:  * @ctxt:  a schema validation context
        !           532:  *
        !           533:  * Allocate a new Schematron structure.
        !           534:  *
        !           535:  * Returns the newly allocated structure or NULL in case or error
        !           536:  */
        !           537: static xmlSchematronPtr
        !           538: xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt)
        !           539: {
        !           540:     xmlSchematronPtr ret;
        !           541: 
        !           542:     ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron));
        !           543:     if (ret == NULL) {
        !           544:         xmlSchematronPErrMemory(ctxt, "allocating schema", NULL);
        !           545:         return (NULL);
        !           546:     }
        !           547:     memset(ret, 0, sizeof(xmlSchematron));
        !           548:     ret->dict = ctxt->dict;
        !           549:     xmlDictReference(ret->dict);
        !           550: 
        !           551:     return (ret);
        !           552: }
        !           553: 
        !           554: /**
        !           555:  * xmlSchematronFree:
        !           556:  * @schema:  a schema structure
        !           557:  *
        !           558:  * Deallocate a Schematron structure.
        !           559:  */
        !           560: void
        !           561: xmlSchematronFree(xmlSchematronPtr schema)
        !           562: {
        !           563:     if (schema == NULL)
        !           564:         return;
        !           565: 
        !           566:     if ((schema->doc != NULL) && (!(schema->preserve)))
        !           567:         xmlFreeDoc(schema->doc);
        !           568: 
        !           569:     if (schema->namespaces != NULL)
        !           570:         xmlFree((char **) schema->namespaces);
        !           571:     
        !           572:     xmlSchematronFreeRules(schema->rules);
        !           573:     xmlSchematronFreePatterns(schema->patterns);
        !           574:     xmlDictFree(schema->dict);
        !           575:     xmlFree(schema);
        !           576: }
        !           577: 
        !           578: /**
        !           579:  * xmlSchematronNewParserCtxt:
        !           580:  * @URL:  the location of the schema
        !           581:  *
        !           582:  * Create an XML Schematrons parse context for that file/resource expected
        !           583:  * to contain an XML Schematrons file.
        !           584:  *
        !           585:  * Returns the parser context or NULL in case of error
        !           586:  */
        !           587: xmlSchematronParserCtxtPtr
        !           588: xmlSchematronNewParserCtxt(const char *URL)
        !           589: {
        !           590:     xmlSchematronParserCtxtPtr ret;
        !           591: 
        !           592:     if (URL == NULL)
        !           593:         return (NULL);
        !           594: 
        !           595:     ret =
        !           596:         (xmlSchematronParserCtxtPtr)
        !           597:         xmlMalloc(sizeof(xmlSchematronParserCtxt));
        !           598:     if (ret == NULL) {
        !           599:         xmlSchematronPErrMemory(NULL, "allocating schema parser context",
        !           600:                                 NULL);
        !           601:         return (NULL);
        !           602:     }
        !           603:     memset(ret, 0, sizeof(xmlSchematronParserCtxt));
        !           604:     ret->type = XML_STRON_CTXT_PARSER;
        !           605:     ret->dict = xmlDictCreate();
        !           606:     ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
        !           607:     ret->includes = NULL;
        !           608:     ret->xctxt = xmlXPathNewContext(NULL);
        !           609:     if (ret->xctxt == NULL) {
        !           610:         xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
        !           611:                                 NULL);
        !           612:        xmlSchematronFreeParserCtxt(ret);
        !           613:         return (NULL);
        !           614:     }
        !           615:     ret->xctxt->flags = XML_XPATH_CHECKNS;
        !           616:     return (ret);
        !           617: }
        !           618: 
        !           619: /**
        !           620:  * xmlSchematronNewMemParserCtxt:
        !           621:  * @buffer:  a pointer to a char array containing the schemas
        !           622:  * @size:  the size of the array
        !           623:  *
        !           624:  * Create an XML Schematrons parse context for that memory buffer expected
        !           625:  * to contain an XML Schematrons file.
        !           626:  *
        !           627:  * Returns the parser context or NULL in case of error
        !           628:  */
        !           629: xmlSchematronParserCtxtPtr
        !           630: xmlSchematronNewMemParserCtxt(const char *buffer, int size)
        !           631: {
        !           632:     xmlSchematronParserCtxtPtr ret;
        !           633: 
        !           634:     if ((buffer == NULL) || (size <= 0))
        !           635:         return (NULL);
        !           636: 
        !           637:     ret =
        !           638:         (xmlSchematronParserCtxtPtr)
        !           639:         xmlMalloc(sizeof(xmlSchematronParserCtxt));
        !           640:     if (ret == NULL) {
        !           641:         xmlSchematronPErrMemory(NULL, "allocating schema parser context",
        !           642:                                 NULL);
        !           643:         return (NULL);
        !           644:     }
        !           645:     memset(ret, 0, sizeof(xmlSchematronParserCtxt));
        !           646:     ret->buffer = buffer;
        !           647:     ret->size = size;
        !           648:     ret->dict = xmlDictCreate();
        !           649:     ret->xctxt = xmlXPathNewContext(NULL);
        !           650:     if (ret->xctxt == NULL) {
        !           651:         xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
        !           652:                                 NULL);
        !           653:        xmlSchematronFreeParserCtxt(ret);
        !           654:         return (NULL);
        !           655:     }
        !           656:     return (ret);
        !           657: }
        !           658: 
        !           659: /**
        !           660:  * xmlSchematronNewDocParserCtxt:
        !           661:  * @doc:  a preparsed document tree
        !           662:  *
        !           663:  * Create an XML Schematrons parse context for that document.
        !           664:  * NB. The document may be modified during the parsing process.
        !           665:  *
        !           666:  * Returns the parser context or NULL in case of error
        !           667:  */
        !           668: xmlSchematronParserCtxtPtr
        !           669: xmlSchematronNewDocParserCtxt(xmlDocPtr doc)
        !           670: {
        !           671:     xmlSchematronParserCtxtPtr ret;
        !           672: 
        !           673:     if (doc == NULL)
        !           674:         return (NULL);
        !           675: 
        !           676:     ret =
        !           677:         (xmlSchematronParserCtxtPtr)
        !           678:         xmlMalloc(sizeof(xmlSchematronParserCtxt));
        !           679:     if (ret == NULL) {
        !           680:         xmlSchematronPErrMemory(NULL, "allocating schema parser context",
        !           681:                                 NULL);
        !           682:         return (NULL);
        !           683:     }
        !           684:     memset(ret, 0, sizeof(xmlSchematronParserCtxt));
        !           685:     ret->doc = doc;
        !           686:     ret->dict = xmlDictCreate();
        !           687:     /* The application has responsibility for the document */
        !           688:     ret->preserve = 1;
        !           689:     ret->xctxt = xmlXPathNewContext(doc);
        !           690:     if (ret->xctxt == NULL) {
        !           691:         xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
        !           692:                                 NULL);
        !           693:        xmlSchematronFreeParserCtxt(ret);
        !           694:         return (NULL);
        !           695:     }
        !           696: 
        !           697:     return (ret);
        !           698: }
        !           699: 
        !           700: /**
        !           701:  * xmlSchematronFreeParserCtxt:
        !           702:  * @ctxt:  the schema parser context
        !           703:  *
        !           704:  * Free the resources associated to the schema parser context
        !           705:  */
        !           706: void
        !           707: xmlSchematronFreeParserCtxt(xmlSchematronParserCtxtPtr ctxt)
        !           708: {
        !           709:     if (ctxt == NULL)
        !           710:         return;
        !           711:     if (ctxt->doc != NULL && !ctxt->preserve)
        !           712:         xmlFreeDoc(ctxt->doc);
        !           713:     if (ctxt->xctxt != NULL) {
        !           714:         xmlXPathFreeContext(ctxt->xctxt);
        !           715:     }
        !           716:     if (ctxt->namespaces != NULL)
        !           717:         xmlFree((char **) ctxt->namespaces);
        !           718:     xmlDictFree(ctxt->dict);
        !           719:     xmlFree(ctxt);
        !           720: }
        !           721: 
        !           722: #if 0
        !           723: /**
        !           724:  * xmlSchematronPushInclude:
        !           725:  * @ctxt:  the schema parser context
        !           726:  * @doc:  the included document
        !           727:  * @cur:  the current include node
        !           728:  *
        !           729:  * Add an included document
        !           730:  */
        !           731: static void
        !           732: xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt,
        !           733:                         xmlDocPtr doc, xmlNodePtr cur)
        !           734: {
        !           735:     if (ctxt->includes == NULL) {
        !           736:         ctxt->maxIncludes = 10;
        !           737:         ctxt->includes = (xmlNodePtr *)
        !           738:            xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr));
        !           739:        if (ctxt->includes == NULL) {
        !           740:            xmlSchematronPErrMemory(NULL, "allocating parser includes",
        !           741:                                    NULL);
        !           742:            return;
        !           743:        }
        !           744:         ctxt->nbIncludes = 0;
        !           745:     } else if (ctxt->nbIncludes + 2 >= ctxt->maxIncludes) {
        !           746:         xmlNodePtr *tmp;
        !           747: 
        !           748:        tmp = (xmlNodePtr *)
        !           749:            xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 *
        !           750:                       sizeof(xmlNodePtr));
        !           751:        if (tmp == NULL) {
        !           752:            xmlSchematronPErrMemory(NULL, "allocating parser includes",
        !           753:                                    NULL);
        !           754:            return;
        !           755:        }
        !           756:         ctxt->includes = tmp;
        !           757:        ctxt->maxIncludes *= 2;
        !           758:     }
        !           759:     ctxt->includes[2 * ctxt->nbIncludes] = cur;
        !           760:     ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc;
        !           761:     ctxt->nbIncludes++;
        !           762: }
        !           763: 
        !           764: /**
        !           765:  * xmlSchematronPopInclude:
        !           766:  * @ctxt:  the schema parser context
        !           767:  *
        !           768:  * Pop an include level. The included document is being freed
        !           769:  *
        !           770:  * Returns the node immediately following the include or NULL if the
        !           771:  *         include list was empty.
        !           772:  */
        !           773: static xmlNodePtr
        !           774: xmlSchematronPopInclude(xmlSchematronParserCtxtPtr ctxt)
        !           775: {
        !           776:     xmlDocPtr doc;
        !           777:     xmlNodePtr ret;
        !           778: 
        !           779:     if (ctxt->nbIncludes <= 0)
        !           780:         return(NULL);
        !           781:     ctxt->nbIncludes--;
        !           782:     doc = (xmlDocPtr) ctxt->includes[2 * ctxt->nbIncludes + 1];
        !           783:     ret = ctxt->includes[2 * ctxt->nbIncludes];
        !           784:     xmlFreeDoc(doc);
        !           785:     if (ret != NULL)
        !           786:        ret = ret->next;
        !           787:     if (ret == NULL)
        !           788:         return(xmlSchematronPopInclude(ctxt));
        !           789:     return(ret);
        !           790: }
        !           791: #endif
        !           792: 
        !           793: /**
        !           794:  * xmlSchematronAddNamespace:
        !           795:  * @ctxt:  the schema parser context
        !           796:  * @prefix:  the namespace prefix
        !           797:  * @ns:  the namespace name
        !           798:  *
        !           799:  * Add a namespace definition in the context
        !           800:  */
        !           801: static void
        !           802: xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt,
        !           803:                           const xmlChar *prefix, const xmlChar *ns)
        !           804: {
        !           805:     if (ctxt->namespaces == NULL) {
        !           806:         ctxt->maxNamespaces = 10;
        !           807:         ctxt->namespaces = (const xmlChar **)
        !           808:            xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *));
        !           809:        if (ctxt->namespaces == NULL) {
        !           810:            xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
        !           811:                                    NULL);
        !           812:            return;
        !           813:        }
        !           814:         ctxt->nbNamespaces = 0;
        !           815:     } else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) {
        !           816:         const xmlChar **tmp;
        !           817: 
        !           818:        tmp = (const xmlChar **)
        !           819:            xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 *
        !           820:                       sizeof(const xmlChar *));
        !           821:        if (tmp == NULL) {
        !           822:            xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
        !           823:                                    NULL);
        !           824:            return;
        !           825:        }
        !           826:         ctxt->namespaces = tmp;
        !           827:        ctxt->maxNamespaces *= 2;
        !           828:     }
        !           829:     ctxt->namespaces[2 * ctxt->nbNamespaces] = 
        !           830:         xmlDictLookup(ctxt->dict, ns, -1);
        !           831:     ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = 
        !           832:         xmlDictLookup(ctxt->dict, prefix, -1);
        !           833:     ctxt->nbNamespaces++;
        !           834:     ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL;
        !           835:     ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL;
        !           836: 
        !           837: }
        !           838: 
        !           839: /**
        !           840:  * xmlSchematronParseRule:
        !           841:  * @ctxt:  a schema validation context
        !           842:  * @rule:  the rule node
        !           843:  *
        !           844:  * parse a rule element
        !           845:  */
        !           846: static void
        !           847: xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt,
        !           848:                        xmlSchematronPatternPtr pattern,
        !           849:                       xmlNodePtr rule)
        !           850: {
        !           851:     xmlNodePtr cur;
        !           852:     int nbChecks = 0;
        !           853:     xmlChar *test;
        !           854:     xmlChar *context;
        !           855:     xmlChar *report;
        !           856:     xmlSchematronRulePtr ruleptr;
        !           857:     xmlSchematronTestPtr testptr;
        !           858: 
        !           859:     if ((ctxt == NULL) || (rule == NULL)) return;
        !           860: 
        !           861:     context = xmlGetNoNsProp(rule, BAD_CAST "context");
        !           862:     if (context == NULL) {
        !           863:        xmlSchematronPErr(ctxt, rule,
        !           864:            XML_SCHEMAP_NOROOT,
        !           865:            "rule has no context attribute",
        !           866:            NULL, NULL);
        !           867:        return;
        !           868:     } else if (context[0] == 0) {
        !           869:        xmlSchematronPErr(ctxt, rule,
        !           870:            XML_SCHEMAP_NOROOT,
        !           871:            "rule has an empty context attribute",
        !           872:            NULL, NULL);
        !           873:        xmlFree(context);
        !           874:        return;
        !           875:     } else {
        !           876:        ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, pattern,
        !           877:                                       rule, context, NULL);
        !           878:        if (ruleptr == NULL) {
        !           879:            xmlFree(context);
        !           880:            return;
        !           881:        }
        !           882:     }
        !           883: 
        !           884:     cur = rule->children;
        !           885:     NEXT_SCHEMATRON(cur);
        !           886:     while (cur != NULL) {
        !           887:        if (IS_SCHEMATRON(cur, "assert")) {
        !           888:            nbChecks++;
        !           889:            test = xmlGetNoNsProp(cur, BAD_CAST "test");
        !           890:            if (test == NULL) {
        !           891:                xmlSchematronPErr(ctxt, cur,
        !           892:                    XML_SCHEMAP_NOROOT,
        !           893:                    "assert has no test attribute",
        !           894:                    NULL, NULL);
        !           895:            } else if (test[0] == 0) {
        !           896:                xmlSchematronPErr(ctxt, cur,
        !           897:                    XML_SCHEMAP_NOROOT,
        !           898:                    "assert has an empty test attribute",
        !           899:                    NULL, NULL);
        !           900:                xmlFree(test);
        !           901:            } else {
        !           902:                /* TODO will need dynamic processing instead */
        !           903:                report = xmlNodeGetContent(cur);
        !           904: 
        !           905:                testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT,
        !           906:                                               ruleptr, cur, test, report);
        !           907:                if (testptr == NULL)
        !           908:                    xmlFree(test);
        !           909:            }
        !           910:        } else if (IS_SCHEMATRON(cur, "report")) {
        !           911:            nbChecks++;
        !           912:            test = xmlGetNoNsProp(cur, BAD_CAST "test");
        !           913:            if (test == NULL) {
        !           914:                xmlSchematronPErr(ctxt, cur,
        !           915:                    XML_SCHEMAP_NOROOT,
        !           916:                    "assert has no test attribute",
        !           917:                    NULL, NULL);
        !           918:            } else if (test[0] == 0) {
        !           919:                xmlSchematronPErr(ctxt, cur,
        !           920:                    XML_SCHEMAP_NOROOT,
        !           921:                    "assert has an empty test attribute",
        !           922:                    NULL, NULL);
        !           923:                xmlFree(test);
        !           924:            } else {
        !           925:                /* TODO will need dynamic processing instead */
        !           926:                report = xmlNodeGetContent(cur);
        !           927: 
        !           928:                testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT,
        !           929:                                               ruleptr, cur, test, report);
        !           930:                if (testptr == NULL)
        !           931:                    xmlFree(test);
        !           932:            }
        !           933:        } else {
        !           934:            xmlSchematronPErr(ctxt, cur,
        !           935:                XML_SCHEMAP_NOROOT,
        !           936:                "Expecting an assert or a report element instead of %s",
        !           937:                cur->name, NULL);
        !           938:        }
        !           939:        cur = cur->next;
        !           940:        NEXT_SCHEMATRON(cur);
        !           941:     }
        !           942:     if (nbChecks == 0) {
        !           943:        xmlSchematronPErr(ctxt, rule,
        !           944:            XML_SCHEMAP_NOROOT,
        !           945:            "rule has no assert nor report element", NULL, NULL);
        !           946:     }
        !           947: }
        !           948: 
        !           949: /**
        !           950:  * xmlSchematronParsePattern:
        !           951:  * @ctxt:  a schema validation context
        !           952:  * @pat:  the pattern node
        !           953:  *
        !           954:  * parse a pattern element
        !           955:  */
        !           956: static void
        !           957: xmlSchematronParsePattern(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr pat)
        !           958: {
        !           959:     xmlNodePtr cur;
        !           960:     xmlSchematronPatternPtr pattern;
        !           961:     int nbRules = 0;
        !           962:     xmlChar *id;
        !           963: 
        !           964:     if ((ctxt == NULL) || (pat == NULL)) return;
        !           965: 
        !           966:     id = xmlGetNoNsProp(pat, BAD_CAST "id");
        !           967:     if (id == NULL) {
        !           968:        id = xmlGetNoNsProp(pat, BAD_CAST "name");
        !           969:     }
        !           970:     pattern = xmlSchematronAddPattern(ctxt, ctxt->schema, pat, id);
        !           971:     if (pattern == NULL) {
        !           972:        if (id != NULL)
        !           973:            xmlFree(id);
        !           974:         return;
        !           975:     }
        !           976:     cur = pat->children;
        !           977:     NEXT_SCHEMATRON(cur);
        !           978:     while (cur != NULL) {
        !           979:        if (IS_SCHEMATRON(cur, "rule")) {
        !           980:            xmlSchematronParseRule(ctxt, pattern, cur);
        !           981:            nbRules++;
        !           982:        } else {
        !           983:            xmlSchematronPErr(ctxt, cur,
        !           984:                XML_SCHEMAP_NOROOT,
        !           985:                "Expecting a rule element instead of %s", cur->name, NULL);
        !           986:        }
        !           987:        cur = cur->next;
        !           988:        NEXT_SCHEMATRON(cur);
        !           989:     }
        !           990:     if (nbRules == 0) {
        !           991:        xmlSchematronPErr(ctxt, pat,
        !           992:            XML_SCHEMAP_NOROOT,
        !           993:            "Pattern has no rule element", NULL, NULL);
        !           994:     }
        !           995: }
        !           996: 
        !           997: #if 0
        !           998: /**
        !           999:  * xmlSchematronLoadInclude:
        !          1000:  * @ctxt:  a schema validation context
        !          1001:  * @cur:  the include element
        !          1002:  *
        !          1003:  * Load the include document, Push the current pointer
        !          1004:  *
        !          1005:  * Returns the updated node pointer
        !          1006:  */
        !          1007: static xmlNodePtr
        !          1008: xmlSchematronLoadInclude(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr cur)
        !          1009: {
        !          1010:     xmlNodePtr ret = NULL;
        !          1011:     xmlDocPtr doc = NULL;
        !          1012:     xmlChar *href = NULL;
        !          1013:     xmlChar *base = NULL;
        !          1014:     xmlChar *URI = NULL;
        !          1015: 
        !          1016:     if ((ctxt == NULL) || (cur == NULL))
        !          1017:         return(NULL);
        !          1018: 
        !          1019:     href = xmlGetNoNsProp(cur, BAD_CAST "href");
        !          1020:     if (href == NULL) {
        !          1021:        xmlSchematronPErr(ctxt, cur,
        !          1022:            XML_SCHEMAP_NOROOT,
        !          1023:            "Include has no href attribute", NULL, NULL);
        !          1024:        return(cur->next);
        !          1025:     }
        !          1026: 
        !          1027:     /* do the URI base composition, load and find the root */
        !          1028:     base = xmlNodeGetBase(cur->doc, cur);
        !          1029:     URI = xmlBuildURI(href, base);
        !          1030:     doc = xmlReadFile((const char *) URI, NULL, SCHEMATRON_PARSE_OPTIONS);
        !          1031:     if (doc == NULL) {
        !          1032:        xmlSchematronPErr(ctxt, cur,
        !          1033:                      XML_SCHEMAP_FAILED_LOAD,
        !          1034:                      "could not load include '%s'.\n",
        !          1035:                      URI, NULL);
        !          1036:        goto done;
        !          1037:     }
        !          1038:     ret = xmlDocGetRootElement(doc);
        !          1039:     if (ret == NULL) {
        !          1040:        xmlSchematronPErr(ctxt, cur,
        !          1041:                      XML_SCHEMAP_FAILED_LOAD,
        !          1042:                      "could not find root from include '%s'.\n",
        !          1043:                      URI, NULL);
        !          1044:        goto done;
        !          1045:     }
        !          1046: 
        !          1047:     /* Success, push the include for rollback on exit */
        !          1048:     xmlSchematronPushInclude(ctxt, doc, cur);
        !          1049: 
        !          1050: done:
        !          1051:     if (ret == NULL) {
        !          1052:         if (doc != NULL)
        !          1053:            xmlFreeDoc(doc);
        !          1054:     }
        !          1055:     xmlFree(href);
        !          1056:     if (base != NULL)
        !          1057:         xmlFree(base);
        !          1058:     if (URI != NULL)
        !          1059:         xmlFree(URI);
        !          1060:     return(ret);
        !          1061: }
        !          1062: #endif
        !          1063: 
        !          1064: /**
        !          1065:  * xmlSchematronParse:
        !          1066:  * @ctxt:  a schema validation context
        !          1067:  *
        !          1068:  * parse a schema definition resource and build an internal
        !          1069:  * XML Shema struture which can be used to validate instances.
        !          1070:  *
        !          1071:  * Returns the internal XML Schematron structure built from the resource or
        !          1072:  *         NULL in case of error
        !          1073:  */
        !          1074: xmlSchematronPtr
        !          1075: xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt)
        !          1076: {
        !          1077:     xmlSchematronPtr ret = NULL;
        !          1078:     xmlDocPtr doc;
        !          1079:     xmlNodePtr root, cur;
        !          1080:     int preserve = 0;
        !          1081: 
        !          1082:     if (ctxt == NULL)
        !          1083:         return (NULL);
        !          1084: 
        !          1085:     ctxt->nberrors = 0;
        !          1086: 
        !          1087:     /*
        !          1088:      * First step is to parse the input document into an DOM/Infoset
        !          1089:      */
        !          1090:     if (ctxt->URL != NULL) {
        !          1091:         doc = xmlReadFile((const char *) ctxt->URL, NULL,
        !          1092:                          SCHEMATRON_PARSE_OPTIONS);
        !          1093:         if (doc == NULL) {
        !          1094:            xmlSchematronPErr(ctxt, NULL,
        !          1095:                          XML_SCHEMAP_FAILED_LOAD,
        !          1096:                           "xmlSchematronParse: could not load '%s'.\n",
        !          1097:                           ctxt->URL, NULL);
        !          1098:             return (NULL);
        !          1099:         }
        !          1100:        ctxt->preserve = 0;
        !          1101:     } else if (ctxt->buffer != NULL) {
        !          1102:         doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
        !          1103:                            SCHEMATRON_PARSE_OPTIONS);
        !          1104:         if (doc == NULL) {
        !          1105:            xmlSchematronPErr(ctxt, NULL,
        !          1106:                          XML_SCHEMAP_FAILED_PARSE,
        !          1107:                           "xmlSchematronParse: could not parse.\n",
        !          1108:                           NULL, NULL);
        !          1109:             return (NULL);
        !          1110:         }
        !          1111:         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
        !          1112:         ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1);
        !          1113:        ctxt->preserve = 0;
        !          1114:     } else if (ctxt->doc != NULL) {
        !          1115:         doc = ctxt->doc;
        !          1116:        preserve = 1;
        !          1117:        ctxt->preserve = 1;
        !          1118:     } else {
        !          1119:        xmlSchematronPErr(ctxt, NULL,
        !          1120:                      XML_SCHEMAP_NOTHING_TO_PARSE,
        !          1121:                      "xmlSchematronParse: could not parse.\n",
        !          1122:                      NULL, NULL);
        !          1123:         return (NULL);
        !          1124:     }
        !          1125: 
        !          1126:     /*
        !          1127:      * Then extract the root and Schematron parse it
        !          1128:      */
        !          1129:     root = xmlDocGetRootElement(doc);
        !          1130:     if (root == NULL) {
        !          1131:        xmlSchematronPErr(ctxt, (xmlNodePtr) doc,
        !          1132:                      XML_SCHEMAP_NOROOT,
        !          1133:                      "The schema has no document element.\n", NULL, NULL);
        !          1134:        if (!preserve) {
        !          1135:            xmlFreeDoc(doc);
        !          1136:        }
        !          1137:         return (NULL);
        !          1138:     }
        !          1139: 
        !          1140:     if (!IS_SCHEMATRON(root, "schema")) {
        !          1141:        xmlSchematronPErr(ctxt, root,
        !          1142:            XML_SCHEMAP_NOROOT,
        !          1143:            "The XML document '%s' is not a XML schematron document",
        !          1144:            ctxt->URL, NULL);
        !          1145:        goto exit;
        !          1146:     }
        !          1147:     ret = xmlSchematronNewSchematron(ctxt);
        !          1148:     if (ret == NULL)
        !          1149:         goto exit;
        !          1150:     ctxt->schema = ret;
        !          1151: 
        !          1152:     /*
        !          1153:      * scan the schema elements
        !          1154:      */
        !          1155:     cur = root->children;
        !          1156:     NEXT_SCHEMATRON(cur);
        !          1157:     if (IS_SCHEMATRON(cur, "title")) {
        !          1158:         xmlChar *title = xmlNodeGetContent(cur);
        !          1159:        if (title != NULL) {
        !          1160:            ret->title = xmlDictLookup(ret->dict, title, -1);
        !          1161:            xmlFree(title);
        !          1162:        }
        !          1163:        cur = cur->next;
        !          1164:        NEXT_SCHEMATRON(cur);
        !          1165:     }
        !          1166:     while (IS_SCHEMATRON(cur, "ns")) {
        !          1167:         xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix");
        !          1168:         xmlChar *uri = xmlGetNoNsProp(cur, BAD_CAST "uri");
        !          1169:        if ((uri == NULL) || (uri[0] == 0)) {
        !          1170:            xmlSchematronPErr(ctxt, cur,
        !          1171:                XML_SCHEMAP_NOROOT,
        !          1172:                "ns element has no uri", NULL, NULL);
        !          1173:        }
        !          1174:        if ((prefix == NULL) || (prefix[0] == 0)) {
        !          1175:            xmlSchematronPErr(ctxt, cur,
        !          1176:                XML_SCHEMAP_NOROOT,
        !          1177:                "ns element has no prefix", NULL, NULL);
        !          1178:        }
        !          1179:        if ((prefix) && (uri)) {
        !          1180:            xmlXPathRegisterNs(ctxt->xctxt, prefix, uri);
        !          1181:            xmlSchematronAddNamespace(ctxt, prefix, uri);
        !          1182:            ret->nbNs++;
        !          1183:        }
        !          1184:        if (uri)
        !          1185:            xmlFree(uri);
        !          1186:        if (prefix)
        !          1187:            xmlFree(prefix);
        !          1188:        cur = cur->next;
        !          1189:        NEXT_SCHEMATRON(cur);
        !          1190:     }
        !          1191:     while (cur != NULL) {
        !          1192:        if (IS_SCHEMATRON(cur, "pattern")) {
        !          1193:            xmlSchematronParsePattern(ctxt, cur);
        !          1194:            ret->nbPattern++;
        !          1195:        } else {
        !          1196:            xmlSchematronPErr(ctxt, cur,
        !          1197:                XML_SCHEMAP_NOROOT,
        !          1198:                "Expecting a pattern element instead of %s", cur->name, NULL);
        !          1199:        }
        !          1200:        cur = cur->next;
        !          1201:        NEXT_SCHEMATRON(cur);
        !          1202:     }
        !          1203:     if (ret->nbPattern == 0) {
        !          1204:        xmlSchematronPErr(ctxt, root,
        !          1205:            XML_SCHEMAP_NOROOT,
        !          1206:            "The schematron document '%s' has no pattern",
        !          1207:            ctxt->URL, NULL);
        !          1208:        goto exit;
        !          1209:     }
        !          1210:     /* the original document must be kept for reporting */
        !          1211:     ret->doc = doc;
        !          1212:     if (preserve) {
        !          1213:            ret->preserve = 1;
        !          1214:     }
        !          1215:     preserve = 1;
        !          1216: 
        !          1217: exit:
        !          1218:     if (!preserve) {
        !          1219:        xmlFreeDoc(doc);
        !          1220:     }
        !          1221:     if (ret != NULL) {
        !          1222:        if (ctxt->nberrors != 0) {
        !          1223:            xmlSchematronFree(ret);
        !          1224:            ret = NULL;
        !          1225:        } else {
        !          1226:            ret->namespaces = ctxt->namespaces;
        !          1227:            ret->nbNamespaces = ctxt->nbNamespaces;
        !          1228:            ctxt->namespaces = NULL;
        !          1229:        }
        !          1230:     }
        !          1231:     return (ret);
        !          1232: }
        !          1233: 
        !          1234: /************************************************************************
        !          1235:  *                                                                     *
        !          1236:  *             Schematrontron Reports handler                          *
        !          1237:  *                                                                     *
        !          1238:  ************************************************************************/
        !          1239: 
        !          1240: static xmlNodePtr
        !          1241: xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt,
        !          1242:                      xmlNodePtr cur, const xmlChar *xpath) {
        !          1243:     xmlNodePtr node = NULL;
        !          1244:     xmlXPathObjectPtr ret;
        !          1245: 
        !          1246:     if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL))
        !          1247:         return(NULL);
        !          1248: 
        !          1249:     ctxt->xctxt->doc = cur->doc;
        !          1250:     ctxt->xctxt->node = cur;
        !          1251:     ret = xmlXPathEval(xpath, ctxt->xctxt);
        !          1252:     if (ret == NULL)
        !          1253:         return(NULL);
        !          1254: 
        !          1255:     if ((ret->type == XPATH_NODESET) &&
        !          1256:         (ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0))
        !          1257:        node = ret->nodesetval->nodeTab[0];
        !          1258: 
        !          1259:     xmlXPathFreeObject(ret);
        !          1260:     return(node);
        !          1261: }
        !          1262: 
        !          1263: /**
        !          1264:  * xmlSchematronReportOutput:
        !          1265:  * @ctxt: the validation context
        !          1266:  * @cur: the current node tested
        !          1267:  * @msg: the message output
        !          1268:  *
        !          1269:  * Output part of the report to whatever channel the user selected
        !          1270:  */
        !          1271: static void
        !          1272: xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
        !          1273:                           xmlNodePtr cur ATTRIBUTE_UNUSED,
        !          1274:                           const char *msg) {
        !          1275:     /* TODO */
        !          1276:     fprintf(stderr, "%s", msg);
        !          1277: }
        !          1278: 
        !          1279: /**
        !          1280:  * xmlSchematronFormatReport:
        !          1281:  * @ctxt:  the validation context
        !          1282:  * @test: the test node
        !          1283:  * @cur: the current node tested
        !          1284:  *
        !          1285:  * Build the string being reported to the user.
        !          1286:  *
        !          1287:  * Returns a report string or NULL in case of error. The string needs
        !          1288:  *         to be deallocated by teh caller
        !          1289:  */
        !          1290: static xmlChar *
        !          1291: xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, 
        !          1292:                          xmlNodePtr test, xmlNodePtr cur) {
        !          1293:     xmlChar *ret = NULL;
        !          1294:     xmlNodePtr child, node;
        !          1295: 
        !          1296:     if ((test == NULL) || (cur == NULL))
        !          1297:         return(ret);
        !          1298: 
        !          1299:     child = test->children;
        !          1300:     while (child != NULL) {
        !          1301:         if ((child->type == XML_TEXT_NODE) ||
        !          1302:            (child->type == XML_CDATA_SECTION_NODE))
        !          1303:            ret = xmlStrcat(ret, child->content);
        !          1304:        else if (IS_SCHEMATRON(child, "name")) {
        !          1305:            xmlChar *path;
        !          1306: 
        !          1307:            path = xmlGetNoNsProp(child, BAD_CAST "path");
        !          1308: 
        !          1309:             node = cur;
        !          1310:            if (path != NULL) {
        !          1311:                node = xmlSchematronGetNode(ctxt, cur, path);
        !          1312:                if (node == NULL)
        !          1313:                    node = cur;
        !          1314:                xmlFree(path);
        !          1315:            }
        !          1316: 
        !          1317:            if ((node->ns == NULL) || (node->ns->prefix == NULL)) 
        !          1318:                ret = xmlStrcat(ret, node->name);
        !          1319:            else {
        !          1320:                ret = xmlStrcat(ret, node->ns->prefix);
        !          1321:                ret = xmlStrcat(ret, BAD_CAST ":");
        !          1322:                ret = xmlStrcat(ret, node->name);
        !          1323:            }
        !          1324:        } else {
        !          1325:            child = child->next;
        !          1326:            continue;
        !          1327:        }
        !          1328: 
        !          1329:        /*
        !          1330:         * remove superfluous \n
        !          1331:         */
        !          1332:        if (ret != NULL) {
        !          1333:            int len = xmlStrlen(ret);
        !          1334:            xmlChar c;
        !          1335: 
        !          1336:            if (len > 0) {
        !          1337:                c = ret[len - 1];
        !          1338:                if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) {
        !          1339:                    while ((c == ' ') || (c == '\n') ||
        !          1340:                           (c == '\r') || (c == '\t')) {
        !          1341:                        len--;
        !          1342:                        if (len == 0)
        !          1343:                            break;
        !          1344:                        c = ret[len - 1];
        !          1345:                    }
        !          1346:                    ret[len] = ' ';
        !          1347:                    ret[len + 1] = 0;
        !          1348:                }
        !          1349:            }
        !          1350:        }
        !          1351: 
        !          1352:         child = child->next;
        !          1353:     }
        !          1354:     return(ret);
        !          1355: }
        !          1356: 
        !          1357: /**
        !          1358:  * xmlSchematronReportSuccess:
        !          1359:  * @ctxt:  the validation context
        !          1360:  * @test: the compiled test
        !          1361:  * @cur: the current node tested
        !          1362:  * @success: boolean value for the result
        !          1363:  *
        !          1364:  * called from the validation engine when an assert or report test have
        !          1365:  * been done.
        !          1366:  */
        !          1367: static void
        !          1368: xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt, 
        !          1369:                   xmlSchematronTestPtr test, xmlNodePtr cur, xmlSchematronPatternPtr pattern, int success) {
        !          1370:     if ((ctxt == NULL) || (cur == NULL) || (test == NULL))
        !          1371:         return;
        !          1372:     /* if quiet and not SVRL report only failures */
        !          1373:     if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) &&
        !          1374:         ((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) &&
        !          1375:        (test->type == XML_SCHEMATRON_REPORT))
        !          1376:         return;
        !          1377:     if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
        !          1378:         TODO
        !          1379:     } else {
        !          1380:         xmlChar *path;
        !          1381:        char msg[1000];
        !          1382:        long line;
        !          1383:        const xmlChar *report = NULL;
        !          1384: 
        !          1385:         if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) ||
        !          1386:            ((test->type == XML_SCHEMATRON_ASSERT) & (success)))
        !          1387:            return;
        !          1388:        line = xmlGetLineNo(cur);
        !          1389:        path = xmlGetNodePath(cur);
        !          1390:        if (path == NULL)
        !          1391:            path = (xmlChar *) cur->name;
        !          1392: #if 0
        !          1393:        if ((test->report != NULL) && (test->report[0] != 0))
        !          1394:            report = test->report;
        !          1395: #endif
        !          1396:        if (test->node != NULL)
        !          1397:             report = xmlSchematronFormatReport(ctxt, test->node, cur);
        !          1398:        if (report == NULL) {
        !          1399:            if (test->type == XML_SCHEMATRON_ASSERT) {
        !          1400:             report = xmlStrdup((const xmlChar *) "node failed assert");
        !          1401:            } else {
        !          1402:             report = xmlStrdup((const xmlChar *) "node failed report");
        !          1403:            }
        !          1404:            }
        !          1405:            snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path,
        !          1406:                     line, (const char *) report);
        !          1407: 
        !          1408:     if (ctxt->flags & XML_SCHEMATRON_OUT_ERROR) {
        !          1409:         xmlStructuredErrorFunc schannel = NULL;
        !          1410:         xmlGenericErrorFunc channel = NULL;
        !          1411:         void *data = NULL;
        !          1412: 
        !          1413:         if (ctxt != NULL) {
        !          1414:             if (ctxt->serror != NULL)
        !          1415:                 schannel = ctxt->serror;
        !          1416:             else
        !          1417:                 channel = ctxt->error;
        !          1418:             data = ctxt->userData;
        !          1419:        }
        !          1420: 
        !          1421:         __xmlRaiseError(schannel, channel, data,
        !          1422:                         NULL, cur, XML_FROM_SCHEMATRONV,
        !          1423:                         (test->type == XML_SCHEMATRON_ASSERT)?XML_SCHEMATRONV_ASSERT:XML_SCHEMATRONV_REPORT,
        !          1424:                         XML_ERR_ERROR, NULL, line,
        !          1425:                         (pattern == NULL)?NULL:((const char *) pattern->name),
        !          1426:                         (const char *) path,
        !          1427:                         (const char *) report, 0, 0,
        !          1428:                         "%s", msg);
        !          1429:     } else {
        !          1430:        xmlSchematronReportOutput(ctxt, cur, &msg[0]);
        !          1431:     }
        !          1432: 
        !          1433:     xmlFree((char *) report);
        !          1434: 
        !          1435:        if ((path != NULL) && (path != (xmlChar *) cur->name))
        !          1436:            xmlFree(path);
        !          1437:     }
        !          1438: }
        !          1439: 
        !          1440: /**
        !          1441:  * xmlSchematronReportPattern:
        !          1442:  * @ctxt:  the validation context
        !          1443:  * @pattern: the current pattern
        !          1444:  *
        !          1445:  * called from the validation engine when starting to check a pattern
        !          1446:  */
        !          1447: static void
        !          1448: xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt, 
        !          1449:                           xmlSchematronPatternPtr pattern) {
        !          1450:     if ((ctxt == NULL) || (pattern == NULL))
        !          1451:         return;
        !          1452:     if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || (ctxt->flags & XML_SCHEMATRON_OUT_ERROR)) /* Error gives pattern name as part of error */
        !          1453:         return;
        !          1454:     if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
        !          1455:         TODO
        !          1456:     } else {
        !          1457:        char msg[1000];
        !          1458: 
        !          1459:        if (pattern->name == NULL)
        !          1460:            return;
        !          1461:        snprintf(msg, 999, "Pattern: %s\n", (const char *) pattern->name);
        !          1462:        xmlSchematronReportOutput(ctxt, NULL, &msg[0]);
        !          1463:     }
        !          1464: }
        !          1465: 
        !          1466: 
        !          1467: /************************************************************************
        !          1468:  *                                                                     *
        !          1469:  *             Validation against a Schematrontron                             *
        !          1470:  *                                                                     *
        !          1471:  ************************************************************************/
        !          1472: 
        !          1473: /**
        !          1474:  * xmlSchematronSetValidStructuredErrors:
        !          1475:  * @ctxt:  a Schematron validation context
        !          1476:  * @serror:  the structured error function
        !          1477:  * @ctx: the functions context
        !          1478:  *
        !          1479:  * Set the structured error callback
        !          1480:  */
        !          1481: void
        !          1482: xmlSchematronSetValidStructuredErrors(xmlSchematronValidCtxtPtr ctxt,
        !          1483:                                       xmlStructuredErrorFunc serror, void *ctx)
        !          1484: {
        !          1485:     if (ctxt == NULL)
        !          1486:         return;
        !          1487:     ctxt->serror = serror;
        !          1488:     ctxt->error = NULL;
        !          1489:     ctxt->warning = NULL;
        !          1490:     ctxt->userData = ctx;
        !          1491: }
        !          1492: 
        !          1493: /**
        !          1494:  * xmlSchematronNewValidCtxt:
        !          1495:  * @schema:  a precompiled XML Schematrons
        !          1496:  * @options: a set of xmlSchematronValidOptions
        !          1497:  *
        !          1498:  * Create an XML Schematrons validation context based on the given schema.
        !          1499:  *
        !          1500:  * Returns the validation context or NULL in case of error
        !          1501:  */
        !          1502: xmlSchematronValidCtxtPtr
        !          1503: xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options)
        !          1504: {
        !          1505:     int i;
        !          1506:     xmlSchematronValidCtxtPtr ret;
        !          1507: 
        !          1508:     ret = (xmlSchematronValidCtxtPtr) xmlMalloc(sizeof(xmlSchematronValidCtxt));
        !          1509:     if (ret == NULL) {
        !          1510:         xmlSchematronVErrMemory(NULL, "allocating validation context",
        !          1511:                                 NULL);
        !          1512:         return (NULL);
        !          1513:     }
        !          1514:     memset(ret, 0, sizeof(xmlSchematronValidCtxt));
        !          1515:     ret->type = XML_STRON_CTXT_VALIDATOR;
        !          1516:     ret->schema = schema;
        !          1517:     ret->xctxt = xmlXPathNewContext(NULL);
        !          1518:     ret->flags = options;
        !          1519:     if (ret->xctxt == NULL) {
        !          1520:         xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
        !          1521:                                 NULL);
        !          1522:        xmlSchematronFreeValidCtxt(ret);
        !          1523:         return (NULL);
        !          1524:     }
        !          1525:     for (i = 0;i < schema->nbNamespaces;i++) {
        !          1526:         if ((schema->namespaces[2 * i] == NULL) ||
        !          1527:             (schema->namespaces[2 * i + 1] == NULL))
        !          1528:            break;
        !          1529:        xmlXPathRegisterNs(ret->xctxt, schema->namespaces[2 * i + 1],
        !          1530:                           schema->namespaces[2 * i]);
        !          1531:     }
        !          1532:     return (ret);
        !          1533: }
        !          1534: 
        !          1535: /**
        !          1536:  * xmlSchematronFreeValidCtxt:
        !          1537:  * @ctxt:  the schema validation context
        !          1538:  *
        !          1539:  * Free the resources associated to the schema validation context
        !          1540:  */
        !          1541: void
        !          1542: xmlSchematronFreeValidCtxt(xmlSchematronValidCtxtPtr ctxt)
        !          1543: {
        !          1544:     if (ctxt == NULL)
        !          1545:         return;
        !          1546:     if (ctxt->xctxt != NULL)
        !          1547:         xmlXPathFreeContext(ctxt->xctxt);
        !          1548:     if (ctxt->dict != NULL)
        !          1549:         xmlDictFree(ctxt->dict);
        !          1550:     xmlFree(ctxt);
        !          1551: }
        !          1552: 
        !          1553: static xmlNodePtr
        !          1554: xmlSchematronNextNode(xmlNodePtr cur) {
        !          1555:     if (cur->children != NULL) {
        !          1556:        /*
        !          1557:         * Do not descend on entities declarations
        !          1558:         */
        !          1559:        if (cur->children->type != XML_ENTITY_DECL) {
        !          1560:            cur = cur->children;
        !          1561:            /*
        !          1562:             * Skip DTDs
        !          1563:             */
        !          1564:            if (cur->type != XML_DTD_NODE)
        !          1565:                return(cur);
        !          1566:        }
        !          1567:     }
        !          1568: 
        !          1569:     while (cur->next != NULL) {
        !          1570:        cur = cur->next;
        !          1571:        if ((cur->type != XML_ENTITY_DECL) &&
        !          1572:            (cur->type != XML_DTD_NODE))
        !          1573:            return(cur);
        !          1574:     }
        !          1575:     
        !          1576:     do {
        !          1577:        cur = cur->parent;
        !          1578:        if (cur == NULL) break;
        !          1579:        if (cur->type == XML_DOCUMENT_NODE) return(NULL);
        !          1580:        if (cur->next != NULL) {
        !          1581:            cur = cur->next;
        !          1582:            return(cur);
        !          1583:        }
        !          1584:     } while (cur != NULL);
        !          1585:     return(cur);
        !          1586: }
        !          1587: 
        !          1588: /**
        !          1589:  * xmlSchematronRunTest:
        !          1590:  * @ctxt:  the schema validation context
        !          1591:  * @test:  the current test
        !          1592:  * @instance:  the document instace tree 
        !          1593:  * @cur:  the current node in the instance
        !          1594:  *
        !          1595:  * Validate a rule against a tree instance at a given position
        !          1596:  *
        !          1597:  * Returns 1 in case of success, 0 if error and -1 in case of internal error
        !          1598:  */
        !          1599: static int
        !          1600: xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt,
        !          1601:      xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur, xmlSchematronPatternPtr pattern)
        !          1602: {
        !          1603:     xmlXPathObjectPtr ret;
        !          1604:     int failed;
        !          1605: 
        !          1606:     failed = 0;
        !          1607:     ctxt->xctxt->doc = instance;
        !          1608:     ctxt->xctxt->node = cur;
        !          1609:     ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt);
        !          1610:     if (ret == NULL) {
        !          1611:        failed = 1;
        !          1612:     } else {
        !          1613:         switch (ret->type) {
        !          1614:            case XPATH_XSLT_TREE:
        !          1615:            case XPATH_NODESET:
        !          1616:                if ((ret->nodesetval == NULL) ||
        !          1617:                    (ret->nodesetval->nodeNr == 0))
        !          1618:                    failed = 1;
        !          1619:                break;
        !          1620:            case XPATH_BOOLEAN:
        !          1621:                failed = !ret->boolval;
        !          1622:                break;
        !          1623:            case XPATH_NUMBER:
        !          1624:                if ((xmlXPathIsNaN(ret->floatval)) ||
        !          1625:                    (ret->floatval == 0.0))
        !          1626:                    failed = 1;
        !          1627:                break;
        !          1628:            case XPATH_STRING:
        !          1629:                if ((ret->stringval == NULL) ||
        !          1630:                    (ret->stringval[0] == 0))
        !          1631:                    failed = 1;
        !          1632:                break;
        !          1633:            case XPATH_UNDEFINED:
        !          1634:            case XPATH_POINT:
        !          1635:            case XPATH_RANGE:
        !          1636:            case XPATH_LOCATIONSET:
        !          1637:            case XPATH_USERS:
        !          1638:                failed = 1;
        !          1639:                break;
        !          1640:        }
        !          1641:        xmlXPathFreeObject(ret);
        !          1642:     }
        !          1643:     if ((failed) && (test->type == XML_SCHEMATRON_ASSERT))
        !          1644:         ctxt->nberrors++;
        !          1645:     else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT))
        !          1646:         ctxt->nberrors++;
        !          1647: 
        !          1648:     xmlSchematronReportSuccess(ctxt, test, cur, pattern, !failed);
        !          1649: 
        !          1650:     return(!failed);
        !          1651: }
        !          1652: 
        !          1653: /**
        !          1654:  * xmlSchematronValidateDoc:
        !          1655:  * @ctxt:  the schema validation context
        !          1656:  * @instance:  the document instace tree 
        !          1657:  *
        !          1658:  * Validate a tree instance against the schematron
        !          1659:  *
        !          1660:  * Returns 0 in case of success, -1 in case of internal error
        !          1661:  *         and an error count otherwise.
        !          1662:  */
        !          1663: int
        !          1664: xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance)
        !          1665: {
        !          1666:     xmlNodePtr cur, root;
        !          1667:     xmlSchematronPatternPtr pattern;
        !          1668:     xmlSchematronRulePtr rule;
        !          1669:     xmlSchematronTestPtr test;
        !          1670: 
        !          1671:     if ((ctxt == NULL) || (ctxt->schema == NULL) ||
        !          1672:         (ctxt->schema->rules == NULL) || (instance == NULL))
        !          1673:         return(-1);
        !          1674:     ctxt->nberrors = 0;
        !          1675:     root = xmlDocGetRootElement(instance);
        !          1676:     if (root == NULL) {
        !          1677:         TODO
        !          1678:        ctxt->nberrors++;
        !          1679:        return(1);
        !          1680:     }
        !          1681:     if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) ||
        !          1682:         (ctxt->flags == 0)) {
        !          1683:        /*
        !          1684:         * we are just trying to assert the validity of the document,
        !          1685:         * speed primes over the output, run in a single pass
        !          1686:         */
        !          1687:        cur = root;
        !          1688:        while (cur != NULL) {
        !          1689:            rule = ctxt->schema->rules;
        !          1690:            while (rule != NULL) {
        !          1691:                if (xmlPatternMatch(rule->pattern, cur) == 1) {
        !          1692:                    test = rule->tests;
        !          1693:                    while (test != NULL) {
        !          1694:                        xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern);
        !          1695:                        test = test->next;
        !          1696:                    }
        !          1697:                }
        !          1698:                rule = rule->next;
        !          1699:            }
        !          1700:            
        !          1701:            cur = xmlSchematronNextNode(cur);
        !          1702:        }
        !          1703:     } else {
        !          1704:         /*
        !          1705:         * Process all contexts one at a time
        !          1706:         */
        !          1707:        pattern = ctxt->schema->patterns;
        !          1708:        
        !          1709:        while (pattern != NULL) {
        !          1710:            xmlSchematronReportPattern(ctxt, pattern);
        !          1711: 
        !          1712:            /*
        !          1713:             * TODO convert the pattern rule to a direct XPath and
        !          1714:             * compute directly instead of using the pattern matching
        !          1715:             * over the full document... 
        !          1716:             * Check the exact semantic
        !          1717:             */
        !          1718:            cur = root;
        !          1719:            while (cur != NULL) {
        !          1720:                rule = pattern->rules;
        !          1721:                while (rule != NULL) {
        !          1722:                    if (xmlPatternMatch(rule->pattern, cur) == 1) {
        !          1723:                        test = rule->tests;
        !          1724:                        while (test != NULL) {
        !          1725:                            xmlSchematronRunTest(ctxt, test, instance, cur, pattern);
        !          1726:                            test = test->next;
        !          1727:                        }
        !          1728:                    }
        !          1729:                    rule = rule->patnext;
        !          1730:                }
        !          1731:                
        !          1732:                cur = xmlSchematronNextNode(cur);
        !          1733:            }
        !          1734:            pattern = pattern->next;
        !          1735:        }
        !          1736:     }
        !          1737:     return(ctxt->nberrors);
        !          1738: }
        !          1739: 
        !          1740: #ifdef STANDALONE
        !          1741: int
        !          1742: main(void)
        !          1743: {
        !          1744:     int ret;
        !          1745:     xmlDocPtr instance;
        !          1746:     xmlSchematronParserCtxtPtr pctxt;
        !          1747:     xmlSchematronValidCtxtPtr vctxt;
        !          1748:     xmlSchematronPtr schema = NULL;
        !          1749: 
        !          1750:     pctxt = xmlSchematronNewParserCtxt("tst.sct");
        !          1751:     if (pctxt == NULL) {
        !          1752:         fprintf(stderr, "failed to build schematron parser\n");
        !          1753:     } else {
        !          1754:         schema = xmlSchematronParse(pctxt);
        !          1755:        if (schema == NULL) {
        !          1756:            fprintf(stderr, "failed to compile schematron\n");
        !          1757:        }
        !          1758:        xmlSchematronFreeParserCtxt(pctxt);
        !          1759:     }
        !          1760:     instance = xmlReadFile("tst.sct", NULL,
        !          1761:                            XML_PARSE_NOENT | XML_PARSE_NOCDATA);
        !          1762:     if (instance == NULL) {
        !          1763:        fprintf(stderr, "failed to parse instance\n");
        !          1764:     }
        !          1765:     if ((schema != NULL) && (instance != NULL)) {
        !          1766:         vctxt = xmlSchematronNewValidCtxt(schema);
        !          1767:        if (vctxt == NULL) {
        !          1768:            fprintf(stderr, "failed to build schematron validator\n");
        !          1769:        } else {
        !          1770:            ret = xmlSchematronValidateDoc(vctxt, instance);
        !          1771:            xmlSchematronFreeValidCtxt(vctxt);
        !          1772:        }
        !          1773:     }
        !          1774:     xmlSchematronFree(schema);
        !          1775:     xmlFreeDoc(instance);
        !          1776: 
        !          1777:     xmlCleanupParser();
        !          1778:     xmlMemoryDump();
        !          1779: 
        !          1780:     return (0);
        !          1781: }
        !          1782: #endif
        !          1783: #define bottom_schematron
        !          1784: #include "elfgcchack.h"
        !          1785: #endif /* LIBXML_SCHEMATRON_ENABLED */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>