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

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) {                                              \
1.1.1.2 ! misho      56:        if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) &&  \
1.1       misho      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:  */
1.1.1.2 ! misho      68: #define TODO                                                           \
1.1       misho      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
1.1.1.2 ! misho     243:  *
1.1       misho     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);
1.1.1.2 ! misho     571: 
1.1       misho     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:     }
1.1.1.2 ! misho     829:     ctxt->namespaces[2 * ctxt->nbNamespaces] =
1.1       misho     830:         xmlDictLookup(ctxt->dict, ns, -1);
1.1.1.2 ! misho     831:     ctxt->namespaces[2 * ctxt->nbNamespaces + 1] =
1.1       misho     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 *
1.1.1.2 ! misho    1291: xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt,
1.1       misho    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: 
1.1.1.2 ! misho    1317:            if ((node->ns == NULL) || (node->ns->prefix == NULL))
1.1       misho    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
1.1.1.2 ! misho    1368: xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt,
1.1       misho    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
1.1.1.2 ! misho    1448: xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt,
1.1       misho    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:     }
1.1.1.2 ! misho    1575: 
1.1       misho    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
1.1.1.2 ! misho    1592:  * @instance:  the document instace tree
1.1       misho    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
1.1.1.2 ! misho    1656:  * @instance:  the document instace tree
1.1       misho    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:            }
1.1.1.2 ! misho    1700: 
1.1       misho    1701:            cur = xmlSchematronNextNode(cur);
                   1702:        }
                   1703:     } else {
                   1704:         /*
                   1705:         * Process all contexts one at a time
                   1706:         */
                   1707:        pattern = ctxt->schema->patterns;
1.1.1.2 ! misho    1708: 
1.1       misho    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
1.1.1.2 ! misho    1715:             * over the full document...
1.1       misho    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:                }
1.1.1.2 ! misho    1731: 
1.1       misho    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>