ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

schematron.c
Go to the documentation of this file.
00001 /*
00002  * schematron.c : implementation of the Schematron schema validity checking
00003  *
00004  * See Copyright for the status of this software.
00005  *
00006  * Daniel Veillard <daniel@veillard.com>
00007  */
00008 
00009 /*
00010  * TODO:
00011  * + double check the semantic, especially
00012  *        - multiple rules applying in a single pattern/node
00013  *        - the semantic of libxml2 patterns vs. XSLT production referenced
00014  *          by the spec.
00015  * + export of results in SVRL
00016  * + full parsing and coverage of the spec, conformance of the input to the
00017  *   spec
00018  * + divergences between the draft and the ISO proposed standard :-(
00019  * + hook and test include
00020  * + try and compare with the XSLT version
00021  */
00022 
00023 #define IN_LIBXML
00024 #include "libxml.h"
00025 
00026 #ifdef LIBXML_SCHEMATRON_ENABLED
00027 
00028 #include <string.h>
00029 #include <libxml/parser.h>
00030 #include <libxml/tree.h>
00031 #include <libxml/uri.h>
00032 #include <libxml/xpath.h>
00033 #include <libxml/xpathInternals.h>
00034 #include <libxml/pattern.h>
00035 #include <libxml/schematron.h>
00036 
00037 #define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT
00038 
00039 #define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron"
00040 
00041 #define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron"
00042 
00043 
00044 static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS;
00045 static const xmlChar *xmlOldSchematronNs = SCT_OLD_NS;
00046 
00047 #define IS_SCHEMATRON(node, elem)                   \
00048    ((node != NULL) && (node->type == XML_ELEMENT_NODE ) &&      \
00049     (node->ns != NULL) &&                       \
00050     (xmlStrEqual(node->name, (const xmlChar *) elem)) &&        \
00051     ((xmlStrEqual(node->ns->href, xmlSchematronNs)) ||          \
00052      (xmlStrEqual(node->ns->href, xmlOldSchematronNs))))
00053 
00054 #define NEXT_SCHEMATRON(node)                       \
00055    while (node != NULL) {                       \
00056        if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) &&   \
00057            ((xmlStrEqual(node->ns->href, xmlSchematronNs)) ||       \
00058         (xmlStrEqual(node->ns->href, xmlOldSchematronNs))))     \
00059        break;                           \
00060        node = node->next;                       \
00061    }
00062 
00068 #define TODO                                \
00069     xmlGenericError(xmlGenericErrorContext,             \
00070         "Unimplemented block at %s:%d\n",               \
00071             __FILE__, __LINE__);
00072 
00073 typedef enum {
00074     XML_SCHEMATRON_ASSERT=1,
00075     XML_SCHEMATRON_REPORT=2
00076 } xmlSchematronTestType;
00077 
00083 typedef struct _xmlSchematronTest xmlSchematronTest;
00084 typedef xmlSchematronTest *xmlSchematronTestPtr;
00085 struct _xmlSchematronTest {
00086     xmlSchematronTestPtr next;  /* the next test in the list */
00087     xmlSchematronTestType type; /* the test type */
00088     xmlNodePtr node;        /* the node in the tree */
00089     xmlChar *test;      /* the expression to test */
00090     xmlXPathCompExprPtr comp;   /* the compiled expression */
00091     xmlChar *report;        /* the message to report */
00092 };
00093 
00099 typedef struct _xmlSchematronRule xmlSchematronRule;
00100 typedef xmlSchematronRule *xmlSchematronRulePtr;
00101 struct _xmlSchematronRule {
00102     xmlSchematronRulePtr next;  /* the next rule in the list */
00103     xmlSchematronRulePtr patnext;/* the next rule in the pattern list */
00104     xmlNodePtr node;        /* the node in the tree */
00105     xmlChar *context;       /* the context evaluation rule */
00106     xmlSchematronTestPtr tests; /* the list of tests */
00107     xmlPatternPtr pattern;  /* the compiled pattern associated */
00108     xmlChar *report;        /* the message to report */
00109 };
00110 
00116 typedef struct _xmlSchematronPattern xmlSchematronPattern;
00117 typedef xmlSchematronPattern *xmlSchematronPatternPtr;
00118 struct _xmlSchematronPattern {
00119     xmlSchematronPatternPtr next;/* the next pattern in the list */
00120     xmlSchematronRulePtr rules; /* the list of rules */
00121     xmlChar *name;      /* the name of the pattern */
00122 };
00123 
00129 struct _xmlSchematron {
00130     const xmlChar *name;    /* schema name */
00131     int preserve;       /* was the document passed by the user */
00132     xmlDocPtr doc;      /* pointer to the parsed document */
00133     int flags;          /* specific to this schematron */
00134 
00135     void *_private;     /* unused by the library */
00136     xmlDictPtr dict;        /* the dictionnary used internally */
00137 
00138     const xmlChar *title;   /* the title if any */
00139 
00140     int nbNs;           /* the number of namespaces */
00141 
00142     int nbPattern;      /* the number of patterns */
00143     xmlSchematronPatternPtr patterns;/* the patterns found */
00144     xmlSchematronRulePtr rules; /* the rules gathered */
00145     int nbNamespaces;       /* number of namespaces in the array */
00146     int maxNamespaces;      /* size of the array */
00147     const xmlChar **namespaces; /* the array of namespaces */
00148 };
00149 
00155 struct _xmlSchematronValidCtxt {
00156     int type;
00157     int flags;          /* an or of xmlSchematronValidOptions */
00158 
00159     xmlDictPtr dict;
00160     int nberrors;
00161     int err;
00162 
00163     xmlSchematronPtr schema;
00164     xmlXPathContextPtr xctxt;
00165 
00166     FILE *outputFile;       /* if using XML_SCHEMATRON_OUT_FILE */
00167     xmlBufferPtr outputBuffer;  /* if using XML_SCHEMATRON_OUT_BUFFER */
00168     xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */
00169     xmlOutputCloseCallback  ioclose;
00170     void *ioctx;
00171 
00172     /* error reporting data */
00173     void *userData;                      /* user specific data block */
00174     xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
00175     xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
00176     xmlStructuredErrorFunc serror;       /* the structured function */
00177 };
00178 
00179 struct _xmlSchematronParserCtxt {
00180     int type;
00181     const xmlChar *URL;
00182     xmlDocPtr doc;
00183     int preserve;               /* Whether the doc should be freed  */
00184     const char *buffer;
00185     int size;
00186 
00187     xmlDictPtr dict;            /* dictionnary for interned string names */
00188 
00189     int nberrors;
00190     int err;
00191     xmlXPathContextPtr xctxt;   /* the XPath context used for compilation */
00192     xmlSchematronPtr schema;
00193 
00194     int nbNamespaces;       /* number of namespaces in the array */
00195     int maxNamespaces;      /* size of the array */
00196     const xmlChar **namespaces; /* the array of namespaces */
00197 
00198     int nbIncludes;     /* number of includes in the array */
00199     int maxIncludes;        /* size of the array */
00200     xmlNodePtr *includes;   /* the array of includes */
00201 
00202     /* error reporting data */
00203     void *userData;                      /* user specific data block */
00204     xmlSchematronValidityErrorFunc error;/* the callback in case of errors */
00205     xmlSchematronValidityWarningFunc warning;/* callback in case of warning */
00206     xmlStructuredErrorFunc serror;       /* the structured function */
00207 };
00208 
00209 #define XML_STRON_CTXT_PARSER 1
00210 #define XML_STRON_CTXT_VALIDATOR 2
00211 
00212 /************************************************************************
00213  *                                  *
00214  *          Error reporting                 *
00215  *                                  *
00216  ************************************************************************/
00217 
00225 static void
00226 xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt,
00227                         const char *extra, xmlNodePtr node)
00228 {
00229     if (ctxt != NULL)
00230         ctxt->nberrors++;
00231     __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
00232                      extra);
00233 }
00234 
00246 static void
00247 xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error,
00248               const char *msg, const xmlChar * str1, const xmlChar * str2)
00249 {
00250     xmlGenericErrorFunc channel = NULL;
00251     xmlStructuredErrorFunc schannel = NULL;
00252     void *data = NULL;
00253 
00254     if (ctxt != NULL) {
00255         ctxt->nberrors++;
00256         channel = ctxt->error;
00257         data = ctxt->userData;
00258     schannel = ctxt->serror;
00259     }
00260     __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
00261                     error, XML_ERR_ERROR, NULL, 0,
00262                     (const char *) str1, (const char *) str2, NULL, 0, 0,
00263                     msg, str1, str2);
00264 }
00265 
00273 static void
00274 xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt,
00275                         const char *extra, xmlNodePtr node)
00276 {
00277     if (ctxt != NULL) {
00278         ctxt->nberrors++;
00279         ctxt->err = XML_SCHEMAV_INTERNAL;
00280     }
00281     __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
00282                      extra);
00283 }
00284 
00285 /************************************************************************
00286  *                                  *
00287  *      Parsing and compilation of the Schematrontrons      *
00288  *                                  *
00289  ************************************************************************/
00290 
00304 static xmlSchematronTestPtr
00305 xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt,
00306                      xmlSchematronTestType type,
00307                      xmlSchematronRulePtr rule,
00308                      xmlNodePtr node, xmlChar *test, xmlChar *report)
00309 {
00310     xmlSchematronTestPtr ret;
00311     xmlXPathCompExprPtr comp;
00312 
00313     if ((ctxt == NULL) || (rule == NULL) || (node == NULL) ||
00314         (test == NULL))
00315         return(NULL);
00316 
00317     /*
00318      * try first to compile the test expression
00319      */
00320     comp = xmlXPathCtxtCompile(ctxt->xctxt, test);
00321     if (comp == NULL) {
00322     xmlSchematronPErr(ctxt, node,
00323         XML_SCHEMAP_NOROOT,
00324         "Failed to compile test expression %s",
00325         test, NULL);
00326     return(NULL);
00327     }
00328 
00329     ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest));
00330     if (ret == NULL) {
00331         xmlSchematronPErrMemory(ctxt, "allocating schema test", node);
00332         return (NULL);
00333     }
00334     memset(ret, 0, sizeof(xmlSchematronTest));
00335     ret->type = type;
00336     ret->node = node;
00337     ret->test = test;
00338     ret->comp = comp;
00339     ret->report = report;
00340     ret->next = NULL;
00341     if (rule->tests == NULL) {
00342     rule->tests = ret;
00343     } else {
00344         xmlSchematronTestPtr prev = rule->tests;
00345 
00346     while (prev->next != NULL)
00347          prev = prev->next;
00348         prev->next = ret;
00349     }
00350     return (ret);
00351 }
00352 
00359 static void
00360 xmlSchematronFreeTests(xmlSchematronTestPtr tests) {
00361     xmlSchematronTestPtr next;
00362 
00363     while (tests != NULL) {
00364         next = tests->next;
00365     if (tests->test != NULL)
00366         xmlFree(tests->test);
00367     if (tests->comp != NULL)
00368         xmlXPathFreeCompExpr(tests->comp);
00369     if (tests->report != NULL)
00370         xmlFree(tests->report);
00371     xmlFree(tests);
00372     tests = next;
00373     }
00374 }
00375 
00388 static xmlSchematronRulePtr
00389 xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema,
00390                      xmlSchematronPatternPtr pat, xmlNodePtr node,
00391              xmlChar *context, xmlChar *report)
00392 {
00393     xmlSchematronRulePtr ret;
00394     xmlPatternPtr pattern;
00395 
00396     if ((ctxt == NULL) || (schema == NULL) || (node == NULL) ||
00397         (context == NULL))
00398         return(NULL);
00399 
00400     /*
00401      * Try first to compile the pattern
00402      */
00403     pattern = xmlPatterncompile(context, ctxt->dict, XML_PATTERN_XPATH,
00404                                 ctxt->namespaces);
00405     if (pattern == NULL) {
00406     xmlSchematronPErr(ctxt, node,
00407         XML_SCHEMAP_NOROOT,
00408         "Failed to compile context expression %s",
00409         context, NULL);
00410     }
00411 
00412     ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule));
00413     if (ret == NULL) {
00414         xmlSchematronPErrMemory(ctxt, "allocating schema rule", node);
00415         return (NULL);
00416     }
00417     memset(ret, 0, sizeof(xmlSchematronRule));
00418     ret->node = node;
00419     ret->context = context;
00420     ret->pattern = pattern;
00421     ret->report = report;
00422     ret->next = NULL;
00423     if (schema->rules == NULL) {
00424     schema->rules = ret;
00425     } else {
00426         xmlSchematronRulePtr prev = schema->rules;
00427 
00428     while (prev->next != NULL)
00429          prev = prev->next;
00430         prev->next = ret;
00431     }
00432     ret->patnext = NULL;
00433     if (pat->rules == NULL) {
00434     pat->rules = ret;
00435     } else {
00436         xmlSchematronRulePtr prev = pat->rules;
00437 
00438     while (prev->patnext != NULL)
00439          prev = prev->patnext;
00440         prev->patnext = ret;
00441     }
00442     return (ret);
00443 }
00444 
00451 static void
00452 xmlSchematronFreeRules(xmlSchematronRulePtr rules) {
00453     xmlSchematronRulePtr next;
00454 
00455     while (rules != NULL) {
00456         next = rules->next;
00457     if (rules->tests)
00458         xmlSchematronFreeTests(rules->tests);
00459     if (rules->context != NULL)
00460         xmlFree(rules->context);
00461     if (rules->pattern)
00462         xmlFreePattern(rules->pattern);
00463     if (rules->report != NULL)
00464         xmlFree(rules->report);
00465     xmlFree(rules);
00466     rules = next;
00467     }
00468 }
00469 
00481 static xmlSchematronPatternPtr
00482 xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt,
00483                      xmlSchematronPtr schema, xmlNodePtr node, xmlChar *name)
00484 {
00485     xmlSchematronPatternPtr ret;
00486 
00487     if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (name == NULL))
00488         return(NULL);
00489 
00490     ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern));
00491     if (ret == NULL) {
00492         xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node);
00493         return (NULL);
00494     }
00495     memset(ret, 0, sizeof(xmlSchematronPattern));
00496     ret->name = name;
00497     ret->next = NULL;
00498     if (schema->patterns == NULL) {
00499     schema->patterns = ret;
00500     } else {
00501         xmlSchematronPatternPtr prev = schema->patterns;
00502 
00503     while (prev->next != NULL)
00504          prev = prev->next;
00505         prev->next = ret;
00506     }
00507     return (ret);
00508 }
00509 
00516 static void
00517 xmlSchematronFreePatterns(xmlSchematronPatternPtr patterns) {
00518     xmlSchematronPatternPtr next;
00519 
00520     while (patterns != NULL) {
00521         next = patterns->next;
00522     if (patterns->name != NULL)
00523         xmlFree(patterns->name);
00524     xmlFree(patterns);
00525     patterns = next;
00526     }
00527 }
00528 
00537 static xmlSchematronPtr
00538 xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt)
00539 {
00540     xmlSchematronPtr ret;
00541 
00542     ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron));
00543     if (ret == NULL) {
00544         xmlSchematronPErrMemory(ctxt, "allocating schema", NULL);
00545         return (NULL);
00546     }
00547     memset(ret, 0, sizeof(xmlSchematron));
00548     ret->dict = ctxt->dict;
00549     xmlDictReference(ret->dict);
00550 
00551     return (ret);
00552 }
00553 
00560 void
00561 xmlSchematronFree(xmlSchematronPtr schema)
00562 {
00563     if (schema == NULL)
00564         return;
00565 
00566     if ((schema->doc != NULL) && (!(schema->preserve)))
00567         xmlFreeDoc(schema->doc);
00568 
00569     if (schema->namespaces != NULL)
00570         xmlFree((char **) schema->namespaces);
00571     
00572     xmlSchematronFreeRules(schema->rules);
00573     xmlSchematronFreePatterns(schema->patterns);
00574     xmlDictFree(schema->dict);
00575     xmlFree(schema);
00576 }
00577 
00587 xmlSchematronParserCtxtPtr
00588 xmlSchematronNewParserCtxt(const char *URL)
00589 {
00590     xmlSchematronParserCtxtPtr ret;
00591 
00592     if (URL == NULL)
00593         return (NULL);
00594 
00595     ret =
00596         (xmlSchematronParserCtxtPtr)
00597         xmlMalloc(sizeof(xmlSchematronParserCtxt));
00598     if (ret == NULL) {
00599         xmlSchematronPErrMemory(NULL, "allocating schema parser context",
00600                                 NULL);
00601         return (NULL);
00602     }
00603     memset(ret, 0, sizeof(xmlSchematronParserCtxt));
00604     ret->type = XML_STRON_CTXT_PARSER;
00605     ret->dict = xmlDictCreate();
00606     ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
00607     ret->includes = NULL;
00608     ret->xctxt = xmlXPathNewContext(NULL);
00609     if (ret->xctxt == NULL) {
00610         xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
00611                                 NULL);
00612     xmlSchematronFreeParserCtxt(ret);
00613         return (NULL);
00614     }
00615     ret->xctxt->flags = XML_XPATH_CHECKNS;
00616     return (ret);
00617 }
00618 
00629 xmlSchematronParserCtxtPtr
00630 xmlSchematronNewMemParserCtxt(const char *buffer, int size)
00631 {
00632     xmlSchematronParserCtxtPtr ret;
00633 
00634     if ((buffer == NULL) || (size <= 0))
00635         return (NULL);
00636 
00637     ret =
00638         (xmlSchematronParserCtxtPtr)
00639         xmlMalloc(sizeof(xmlSchematronParserCtxt));
00640     if (ret == NULL) {
00641         xmlSchematronPErrMemory(NULL, "allocating schema parser context",
00642                                 NULL);
00643         return (NULL);
00644     }
00645     memset(ret, 0, sizeof(xmlSchematronParserCtxt));
00646     ret->buffer = buffer;
00647     ret->size = size;
00648     ret->dict = xmlDictCreate();
00649     ret->xctxt = xmlXPathNewContext(NULL);
00650     if (ret->xctxt == NULL) {
00651         xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
00652                                 NULL);
00653     xmlSchematronFreeParserCtxt(ret);
00654         return (NULL);
00655     }
00656     return (ret);
00657 }
00658 
00668 xmlSchematronParserCtxtPtr
00669 xmlSchematronNewDocParserCtxt(xmlDocPtr doc)
00670 {
00671     xmlSchematronParserCtxtPtr ret;
00672 
00673     if (doc == NULL)
00674         return (NULL);
00675 
00676     ret =
00677         (xmlSchematronParserCtxtPtr)
00678         xmlMalloc(sizeof(xmlSchematronParserCtxt));
00679     if (ret == NULL) {
00680         xmlSchematronPErrMemory(NULL, "allocating schema parser context",
00681                                 NULL);
00682         return (NULL);
00683     }
00684     memset(ret, 0, sizeof(xmlSchematronParserCtxt));
00685     ret->doc = doc;
00686     ret->dict = xmlDictCreate();
00687     /* The application has responsibility for the document */
00688     ret->preserve = 1;
00689     ret->xctxt = xmlXPathNewContext(doc);
00690     if (ret->xctxt == NULL) {
00691         xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
00692                                 NULL);
00693     xmlSchematronFreeParserCtxt(ret);
00694         return (NULL);
00695     }
00696 
00697     return (ret);
00698 }
00699 
00706 void
00707 xmlSchematronFreeParserCtxt(xmlSchematronParserCtxtPtr ctxt)
00708 {
00709     if (ctxt == NULL)
00710         return;
00711     if (ctxt->doc != NULL && !ctxt->preserve)
00712         xmlFreeDoc(ctxt->doc);
00713     if (ctxt->xctxt != NULL) {
00714         xmlXPathFreeContext(ctxt->xctxt);
00715     }
00716     if (ctxt->namespaces != NULL)
00717         xmlFree((char **) ctxt->namespaces);
00718     xmlDictFree(ctxt->dict);
00719     xmlFree(ctxt);
00720 }
00721 
00722 #if 0
00723 
00731 static void
00732 xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt,
00733                         xmlDocPtr doc, xmlNodePtr cur)
00734 {
00735     if (ctxt->includes == NULL) {
00736         ctxt->maxIncludes = 10;
00737         ctxt->includes = (xmlNodePtr *)
00738         xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr));
00739     if (ctxt->includes == NULL) {
00740         xmlSchematronPErrMemory(NULL, "allocating parser includes",
00741                     NULL);
00742         return;
00743     }
00744         ctxt->nbIncludes = 0;
00745     } else if (ctxt->nbIncludes + 2 >= ctxt->maxIncludes) {
00746         xmlNodePtr *tmp;
00747 
00748     tmp = (xmlNodePtr *)
00749         xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 *
00750                    sizeof(xmlNodePtr));
00751     if (tmp == NULL) {
00752         xmlSchematronPErrMemory(NULL, "allocating parser includes",
00753                     NULL);
00754         return;
00755     }
00756         ctxt->includes = tmp;
00757     ctxt->maxIncludes *= 2;
00758     }
00759     ctxt->includes[2 * ctxt->nbIncludes] = cur;
00760     ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc;
00761     ctxt->nbIncludes++;
00762 }
00763 
00773 static xmlNodePtr
00774 xmlSchematronPopInclude(xmlSchematronParserCtxtPtr ctxt)
00775 {
00776     xmlDocPtr doc;
00777     xmlNodePtr ret;
00778 
00779     if (ctxt->nbIncludes <= 0)
00780         return(NULL);
00781     ctxt->nbIncludes--;
00782     doc = (xmlDocPtr) ctxt->includes[2 * ctxt->nbIncludes + 1];
00783     ret = ctxt->includes[2 * ctxt->nbIncludes];
00784     xmlFreeDoc(doc);
00785     if (ret != NULL)
00786     ret = ret->next;
00787     if (ret == NULL)
00788         return(xmlSchematronPopInclude(ctxt));
00789     return(ret);
00790 }
00791 #endif
00792 
00801 static void
00802 xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt,
00803                           const xmlChar *prefix, const xmlChar *ns)
00804 {
00805     if (ctxt->namespaces == NULL) {
00806         ctxt->maxNamespaces = 10;
00807         ctxt->namespaces = (const xmlChar **)
00808         xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *));
00809     if (ctxt->namespaces == NULL) {
00810         xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
00811                     NULL);
00812         return;
00813     }
00814         ctxt->nbNamespaces = 0;
00815     } else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) {
00816         const xmlChar **tmp;
00817 
00818     tmp = (const xmlChar **)
00819         xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 *
00820                    sizeof(const xmlChar *));
00821     if (tmp == NULL) {
00822         xmlSchematronPErrMemory(NULL, "allocating parser namespaces",
00823                     NULL);
00824         return;
00825     }
00826         ctxt->namespaces = tmp;
00827     ctxt->maxNamespaces *= 2;
00828     }
00829     ctxt->namespaces[2 * ctxt->nbNamespaces] = 
00830         xmlDictLookup(ctxt->dict, ns, -1);
00831     ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = 
00832         xmlDictLookup(ctxt->dict, prefix, -1);
00833     ctxt->nbNamespaces++;
00834     ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL;
00835     ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL;
00836 
00837 }
00838 
00846 static void
00847 xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt,
00848                        xmlSchematronPatternPtr pattern,
00849                xmlNodePtr rule)
00850 {
00851     xmlNodePtr cur;
00852     int nbChecks = 0;
00853     xmlChar *test;
00854     xmlChar *context;
00855     xmlChar *report;
00856     xmlSchematronRulePtr ruleptr;
00857     xmlSchematronTestPtr testptr;
00858 
00859     if ((ctxt == NULL) || (rule == NULL)) return;
00860 
00861     context = xmlGetNoNsProp(rule, BAD_CAST "context");
00862     if (context == NULL) {
00863     xmlSchematronPErr(ctxt, rule,
00864         XML_SCHEMAP_NOROOT,
00865         "rule has no context attribute",
00866         NULL, NULL);
00867     return;
00868     } else if (context[0] == 0) {
00869     xmlSchematronPErr(ctxt, rule,
00870         XML_SCHEMAP_NOROOT,
00871         "rule has an empty context attribute",
00872         NULL, NULL);
00873     xmlFree(context);
00874     return;
00875     } else {
00876     ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, pattern,
00877                                    rule, context, NULL);
00878     if (ruleptr == NULL) {
00879         xmlFree(context);
00880         return;
00881     }
00882     }
00883 
00884     cur = rule->children;
00885     NEXT_SCHEMATRON(cur);
00886     while (cur != NULL) {
00887     if (IS_SCHEMATRON(cur, "assert")) {
00888         nbChecks++;
00889         test = xmlGetNoNsProp(cur, BAD_CAST "test");
00890         if (test == NULL) {
00891         xmlSchematronPErr(ctxt, cur,
00892             XML_SCHEMAP_NOROOT,
00893             "assert has no test attribute",
00894             NULL, NULL);
00895         } else if (test[0] == 0) {
00896         xmlSchematronPErr(ctxt, cur,
00897             XML_SCHEMAP_NOROOT,
00898             "assert has an empty test attribute",
00899             NULL, NULL);
00900         xmlFree(test);
00901         } else {
00902         /* TODO will need dynamic processing instead */
00903         report = xmlNodeGetContent(cur);
00904 
00905         testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT,
00906                                        ruleptr, cur, test, report);
00907         if (testptr == NULL)
00908             xmlFree(test);
00909         }
00910     } else if (IS_SCHEMATRON(cur, "report")) {
00911         nbChecks++;
00912         test = xmlGetNoNsProp(cur, BAD_CAST "test");
00913         if (test == NULL) {
00914         xmlSchematronPErr(ctxt, cur,
00915             XML_SCHEMAP_NOROOT,
00916             "assert has no test attribute",
00917             NULL, NULL);
00918         } else if (test[0] == 0) {
00919         xmlSchematronPErr(ctxt, cur,
00920             XML_SCHEMAP_NOROOT,
00921             "assert has an empty test attribute",
00922             NULL, NULL);
00923         xmlFree(test);
00924         } else {
00925         /* TODO will need dynamic processing instead */
00926         report = xmlNodeGetContent(cur);
00927 
00928         testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT,
00929                                        ruleptr, cur, test, report);
00930         if (testptr == NULL)
00931             xmlFree(test);
00932         }
00933     } else {
00934         xmlSchematronPErr(ctxt, cur,
00935         XML_SCHEMAP_NOROOT,
00936         "Expecting an assert or a report element instead of %s",
00937         cur->name, NULL);
00938     }
00939     cur = cur->next;
00940     NEXT_SCHEMATRON(cur);
00941     }
00942     if (nbChecks == 0) {
00943     xmlSchematronPErr(ctxt, rule,
00944         XML_SCHEMAP_NOROOT,
00945         "rule has no assert nor report element", NULL, NULL);
00946     }
00947 }
00948 
00956 static void
00957 xmlSchematronParsePattern(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr pat)
00958 {
00959     xmlNodePtr cur;
00960     xmlSchematronPatternPtr pattern;
00961     int nbRules = 0;
00962     xmlChar *id;
00963 
00964     if ((ctxt == NULL) || (pat == NULL)) return;
00965 
00966     id = xmlGetNoNsProp(pat, BAD_CAST "id");
00967     if (id == NULL) {
00968     id = xmlGetNoNsProp(pat, BAD_CAST "name");
00969     }
00970     pattern = xmlSchematronAddPattern(ctxt, ctxt->schema, pat, id);
00971     if (pattern == NULL) {
00972     if (id != NULL)
00973         xmlFree(id);
00974         return;
00975     }
00976     cur = pat->children;
00977     NEXT_SCHEMATRON(cur);
00978     while (cur != NULL) {
00979     if (IS_SCHEMATRON(cur, "rule")) {
00980         xmlSchematronParseRule(ctxt, pattern, cur);
00981         nbRules++;
00982     } else {
00983         xmlSchematronPErr(ctxt, cur,
00984         XML_SCHEMAP_NOROOT,
00985         "Expecting a rule element instead of %s", cur->name, NULL);
00986     }
00987     cur = cur->next;
00988     NEXT_SCHEMATRON(cur);
00989     }
00990     if (nbRules == 0) {
00991     xmlSchematronPErr(ctxt, pat,
00992         XML_SCHEMAP_NOROOT,
00993         "Pattern has no rule element", NULL, NULL);
00994     }
00995 }
00996 
00997 #if 0
00998 
01007 static xmlNodePtr
01008 xmlSchematronLoadInclude(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr cur)
01009 {
01010     xmlNodePtr ret = NULL;
01011     xmlDocPtr doc = NULL;
01012     xmlChar *href = NULL;
01013     xmlChar *base = NULL;
01014     xmlChar *URI = NULL;
01015 
01016     if ((ctxt == NULL) || (cur == NULL))
01017         return(NULL);
01018 
01019     href = xmlGetNoNsProp(cur, BAD_CAST "href");
01020     if (href == NULL) {
01021     xmlSchematronPErr(ctxt, cur,
01022         XML_SCHEMAP_NOROOT,
01023         "Include has no href attribute", NULL, NULL);
01024     return(cur->next);
01025     }
01026 
01027     /* do the URI base composition, load and find the root */
01028     base = xmlNodeGetBase(cur->doc, cur);
01029     URI = xmlBuildURI(href, base);
01030     doc = xmlReadFile((const char *) URI, NULL, SCHEMATRON_PARSE_OPTIONS);
01031     if (doc == NULL) {
01032     xmlSchematronPErr(ctxt, cur,
01033               XML_SCHEMAP_FAILED_LOAD,
01034               "could not load include '%s'.\n",
01035               URI, NULL);
01036     goto done;
01037     }
01038     ret = xmlDocGetRootElement(doc);
01039     if (ret == NULL) {
01040     xmlSchematronPErr(ctxt, cur,
01041               XML_SCHEMAP_FAILED_LOAD,
01042               "could not find root from include '%s'.\n",
01043               URI, NULL);
01044     goto done;
01045     }
01046 
01047     /* Success, push the include for rollback on exit */
01048     xmlSchematronPushInclude(ctxt, doc, cur);
01049 
01050 done:
01051     if (ret == NULL) {
01052         if (doc != NULL)
01053         xmlFreeDoc(doc);
01054     }
01055     xmlFree(href);
01056     if (base != NULL)
01057         xmlFree(base);
01058     if (URI != NULL)
01059         xmlFree(URI);
01060     return(ret);
01061 }
01062 #endif
01063 
01074 xmlSchematronPtr
01075 xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt)
01076 {
01077     xmlSchematronPtr ret = NULL;
01078     xmlDocPtr doc;
01079     xmlNodePtr root, cur;
01080     int preserve = 0;
01081 
01082     if (ctxt == NULL)
01083         return (NULL);
01084 
01085     ctxt->nberrors = 0;
01086 
01087     /*
01088      * First step is to parse the input document into an DOM/Infoset
01089      */
01090     if (ctxt->URL != NULL) {
01091         doc = xmlReadFile((const char *) ctxt->URL, NULL,
01092                       SCHEMATRON_PARSE_OPTIONS);
01093         if (doc == NULL) {
01094         xmlSchematronPErr(ctxt, NULL,
01095               XML_SCHEMAP_FAILED_LOAD,
01096                           "xmlSchematronParse: could not load '%s'.\n",
01097                           ctxt->URL, NULL);
01098             return (NULL);
01099         }
01100     ctxt->preserve = 0;
01101     } else if (ctxt->buffer != NULL) {
01102         doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
01103                         SCHEMATRON_PARSE_OPTIONS);
01104         if (doc == NULL) {
01105         xmlSchematronPErr(ctxt, NULL,
01106               XML_SCHEMAP_FAILED_PARSE,
01107                           "xmlSchematronParse: could not parse.\n",
01108                           NULL, NULL);
01109             return (NULL);
01110         }
01111         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
01112         ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1);
01113     ctxt->preserve = 0;
01114     } else if (ctxt->doc != NULL) {
01115         doc = ctxt->doc;
01116     preserve = 1;
01117     ctxt->preserve = 1;
01118     } else {
01119     xmlSchematronPErr(ctxt, NULL,
01120               XML_SCHEMAP_NOTHING_TO_PARSE,
01121               "xmlSchematronParse: could not parse.\n",
01122               NULL, NULL);
01123         return (NULL);
01124     }
01125 
01126     /*
01127      * Then extract the root and Schematron parse it
01128      */
01129     root = xmlDocGetRootElement(doc);
01130     if (root == NULL) {
01131     xmlSchematronPErr(ctxt, (xmlNodePtr) doc,
01132               XML_SCHEMAP_NOROOT,
01133               "The schema has no document element.\n", NULL, NULL);
01134     if (!preserve) {
01135         xmlFreeDoc(doc);
01136     }
01137         return (NULL);
01138     }
01139 
01140     if (!IS_SCHEMATRON(root, "schema")) {
01141     xmlSchematronPErr(ctxt, root,
01142         XML_SCHEMAP_NOROOT,
01143         "The XML document '%s' is not a XML schematron document",
01144         ctxt->URL, NULL);
01145     goto exit;
01146     }
01147     ret = xmlSchematronNewSchematron(ctxt);
01148     if (ret == NULL)
01149         goto exit;
01150     ctxt->schema = ret;
01151 
01152     /*
01153      * scan the schema elements
01154      */
01155     cur = root->children;
01156     NEXT_SCHEMATRON(cur);
01157     if (IS_SCHEMATRON(cur, "title")) {
01158         xmlChar *title = xmlNodeGetContent(cur);
01159     if (title != NULL) {
01160         ret->title = xmlDictLookup(ret->dict, title, -1);
01161         xmlFree(title);
01162     }
01163     cur = cur->next;
01164     NEXT_SCHEMATRON(cur);
01165     }
01166     while (IS_SCHEMATRON(cur, "ns")) {
01167         xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix");
01168         xmlChar *uri = xmlGetNoNsProp(cur, BAD_CAST "uri");
01169     if ((uri == NULL) || (uri[0] == 0)) {
01170         xmlSchematronPErr(ctxt, cur,
01171         XML_SCHEMAP_NOROOT,
01172         "ns element has no uri", NULL, NULL);
01173     }
01174     if ((prefix == NULL) || (prefix[0] == 0)) {
01175         xmlSchematronPErr(ctxt, cur,
01176         XML_SCHEMAP_NOROOT,
01177         "ns element has no prefix", NULL, NULL);
01178     }
01179     if ((prefix) && (uri)) {
01180         xmlXPathRegisterNs(ctxt->xctxt, prefix, uri);
01181         xmlSchematronAddNamespace(ctxt, prefix, uri);
01182         ret->nbNs++;
01183     }
01184     if (uri)
01185         xmlFree(uri);
01186     if (prefix)
01187         xmlFree(prefix);
01188     cur = cur->next;
01189     NEXT_SCHEMATRON(cur);
01190     }
01191     while (cur != NULL) {
01192     if (IS_SCHEMATRON(cur, "pattern")) {
01193         xmlSchematronParsePattern(ctxt, cur);
01194         ret->nbPattern++;
01195     } else {
01196         xmlSchematronPErr(ctxt, cur,
01197         XML_SCHEMAP_NOROOT,
01198         "Expecting a pattern element instead of %s", cur->name, NULL);
01199     }
01200     cur = cur->next;
01201     NEXT_SCHEMATRON(cur);
01202     }
01203     if (ret->nbPattern == 0) {
01204     xmlSchematronPErr(ctxt, root,
01205         XML_SCHEMAP_NOROOT,
01206         "The schematron document '%s' has no pattern",
01207         ctxt->URL, NULL);
01208     goto exit;
01209     }
01210     /* the original document must be kept for reporting */
01211     ret->doc = doc;
01212     if (preserve) {
01213         ret->preserve = 1;
01214     }
01215     preserve = 1;
01216 
01217 exit:
01218     if (!preserve) {
01219     xmlFreeDoc(doc);
01220     }
01221     if (ret != NULL) {
01222     if (ctxt->nberrors != 0) {
01223         xmlSchematronFree(ret);
01224         ret = NULL;
01225     } else {
01226         ret->namespaces = ctxt->namespaces;
01227         ret->nbNamespaces = ctxt->nbNamespaces;
01228         ctxt->namespaces = NULL;
01229     }
01230     }
01231     return (ret);
01232 }
01233 
01234 /************************************************************************
01235  *                                  *
01236  *      Schematrontron Reports handler              *
01237  *                                  *
01238  ************************************************************************/
01239 
01240 static xmlNodePtr
01241 xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt,
01242                      xmlNodePtr cur, const xmlChar *xpath) {
01243     xmlNodePtr node = NULL;
01244     xmlXPathObjectPtr ret;
01245 
01246     if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL))
01247         return(NULL);
01248 
01249     ctxt->xctxt->doc = cur->doc;
01250     ctxt->xctxt->node = cur;
01251     ret = xmlXPathEval(xpath, ctxt->xctxt);
01252     if (ret == NULL)
01253         return(NULL);
01254 
01255     if ((ret->type == XPATH_NODESET) &&
01256         (ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0))
01257     node = ret->nodesetval->nodeTab[0];
01258 
01259     xmlXPathFreeObject(ret);
01260     return(node);
01261 }
01262 
01271 static void
01272 xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
01273                           xmlNodePtr cur ATTRIBUTE_UNUSED,
01274                           const char *msg) {
01275     /* TODO */
01276     fprintf(stderr, "%s", msg);
01277 }
01278 
01290 static xmlChar *
01291 xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, 
01292               xmlNodePtr test, xmlNodePtr cur) {
01293     xmlChar *ret = NULL;
01294     xmlNodePtr child, node;
01295 
01296     if ((test == NULL) || (cur == NULL))
01297         return(ret);
01298 
01299     child = test->children;
01300     while (child != NULL) {
01301         if ((child->type == XML_TEXT_NODE) ||
01302         (child->type == XML_CDATA_SECTION_NODE))
01303         ret = xmlStrcat(ret, child->content);
01304     else if (IS_SCHEMATRON(child, "name")) {
01305         xmlChar *path;
01306 
01307         path = xmlGetNoNsProp(child, BAD_CAST "path");
01308 
01309             node = cur;
01310         if (path != NULL) {
01311             node = xmlSchematronGetNode(ctxt, cur, path);
01312         if (node == NULL)
01313             node = cur;
01314         xmlFree(path);
01315         }
01316 
01317         if ((node->ns == NULL) || (node->ns->prefix == NULL)) 
01318             ret = xmlStrcat(ret, node->name);
01319         else {
01320             ret = xmlStrcat(ret, node->ns->prefix);
01321             ret = xmlStrcat(ret, BAD_CAST ":");
01322             ret = xmlStrcat(ret, node->name);
01323         }
01324     } else {
01325         child = child->next;
01326         continue;
01327     }
01328 
01329     /*
01330      * remove superfluous \n
01331      */
01332     if (ret != NULL) {
01333         int len = xmlStrlen(ret);
01334         xmlChar c;
01335 
01336         if (len > 0) {
01337         c = ret[len - 1];
01338         if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) {
01339             while ((c == ' ') || (c == '\n') ||
01340                    (c == '\r') || (c == '\t')) {
01341             len--;
01342             if (len == 0)
01343                 break;
01344             c = ret[len - 1];
01345             }
01346             ret[len] = ' ';
01347             ret[len + 1] = 0;
01348         }
01349         }
01350     }
01351 
01352         child = child->next;
01353     }
01354     return(ret);
01355 }
01356 
01367 static void
01368 xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt, 
01369            xmlSchematronTestPtr test, xmlNodePtr cur, xmlSchematronPatternPtr pattern, int success) {
01370     if ((ctxt == NULL) || (cur == NULL) || (test == NULL))
01371         return;
01372     /* if quiet and not SVRL report only failures */
01373     if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) &&
01374         ((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) &&
01375     (test->type == XML_SCHEMATRON_REPORT))
01376         return;
01377     if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
01378         TODO
01379     } else {
01380         xmlChar *path;
01381     char msg[1000];
01382     long line;
01383     const xmlChar *report = NULL;
01384 
01385         if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) ||
01386         ((test->type == XML_SCHEMATRON_ASSERT) & (success)))
01387         return;
01388     line = xmlGetLineNo(cur);
01389     path = xmlGetNodePath(cur);
01390     if (path == NULL)
01391         path = (xmlChar *) cur->name;
01392 #if 0
01393     if ((test->report != NULL) && (test->report[0] != 0))
01394         report = test->report;
01395 #endif
01396     if (test->node != NULL)
01397             report = xmlSchematronFormatReport(ctxt, test->node, cur);
01398     if (report == NULL) {
01399         if (test->type == XML_SCHEMATRON_ASSERT) {
01400             report = xmlStrdup((const xmlChar *) "node failed assert");
01401         } else {
01402             report = xmlStrdup((const xmlChar *) "node failed report");
01403         }
01404         }
01405         snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path,
01406              line, (const char *) report);
01407 
01408     if (ctxt->flags & XML_SCHEMATRON_OUT_ERROR) {
01409         xmlStructuredErrorFunc schannel = NULL;
01410         xmlGenericErrorFunc channel = NULL;
01411         void *data = NULL;
01412 
01413         if (ctxt != NULL) {
01414             if (ctxt->serror != NULL)
01415                 schannel = ctxt->serror;
01416             else
01417                 channel = ctxt->error;
01418             data = ctxt->userData;
01419     }
01420 
01421         __xmlRaiseError(schannel, channel, data,
01422                         NULL, cur, XML_FROM_SCHEMATRONV,
01423                         (test->type == XML_SCHEMATRON_ASSERT)?XML_SCHEMATRONV_ASSERT:XML_SCHEMATRONV_REPORT,
01424                         XML_ERR_ERROR, NULL, line,
01425                         (pattern == NULL)?NULL:((const char *) pattern->name),
01426                         (const char *) path,
01427                         (const char *) report, 0, 0,
01428                         "%s", msg);
01429     } else {
01430     xmlSchematronReportOutput(ctxt, cur, &msg[0]);
01431     }
01432 
01433     xmlFree((char *) report);
01434 
01435     if ((path != NULL) && (path != (xmlChar *) cur->name))
01436         xmlFree(path);
01437     }
01438 }
01439 
01447 static void
01448 xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt, 
01449                xmlSchematronPatternPtr pattern) {
01450     if ((ctxt == NULL) || (pattern == NULL))
01451         return;
01452     if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || (ctxt->flags & XML_SCHEMATRON_OUT_ERROR)) /* Error gives pattern name as part of error */
01453         return;
01454     if (ctxt->flags & XML_SCHEMATRON_OUT_XML) {
01455         TODO
01456     } else {
01457     char msg[1000];
01458 
01459     if (pattern->name == NULL)
01460         return;
01461     snprintf(msg, 999, "Pattern: %s\n", (const char *) pattern->name);
01462     xmlSchematronReportOutput(ctxt, NULL, &msg[0]);
01463     }
01464 }
01465 
01466 
01467 /************************************************************************
01468  *                                  *
01469  *      Validation against a Schematrontron             *
01470  *                                  *
01471  ************************************************************************/
01472 
01481 void
01482 xmlSchematronSetValidStructuredErrors(xmlSchematronValidCtxtPtr ctxt,
01483                                       xmlStructuredErrorFunc serror, void *ctx)
01484 {
01485     if (ctxt == NULL)
01486         return;
01487     ctxt->serror = serror;
01488     ctxt->error = NULL;
01489     ctxt->warning = NULL;
01490     ctxt->userData = ctx;
01491 }
01492 
01502 xmlSchematronValidCtxtPtr
01503 xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options)
01504 {
01505     int i;
01506     xmlSchematronValidCtxtPtr ret;
01507 
01508     ret = (xmlSchematronValidCtxtPtr) xmlMalloc(sizeof(xmlSchematronValidCtxt));
01509     if (ret == NULL) {
01510         xmlSchematronVErrMemory(NULL, "allocating validation context",
01511                                 NULL);
01512         return (NULL);
01513     }
01514     memset(ret, 0, sizeof(xmlSchematronValidCtxt));
01515     ret->type = XML_STRON_CTXT_VALIDATOR;
01516     ret->schema = schema;
01517     ret->xctxt = xmlXPathNewContext(NULL);
01518     ret->flags = options;
01519     if (ret->xctxt == NULL) {
01520         xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context",
01521                                 NULL);
01522     xmlSchematronFreeValidCtxt(ret);
01523         return (NULL);
01524     }
01525     for (i = 0;i < schema->nbNamespaces;i++) {
01526         if ((schema->namespaces[2 * i] == NULL) ||
01527             (schema->namespaces[2 * i + 1] == NULL))
01528         break;
01529     xmlXPathRegisterNs(ret->xctxt, schema->namespaces[2 * i + 1],
01530                        schema->namespaces[2 * i]);
01531     }
01532     return (ret);
01533 }
01534 
01541 void
01542 xmlSchematronFreeValidCtxt(xmlSchematronValidCtxtPtr ctxt)
01543 {
01544     if (ctxt == NULL)
01545         return;
01546     if (ctxt->xctxt != NULL)
01547         xmlXPathFreeContext(ctxt->xctxt);
01548     if (ctxt->dict != NULL)
01549         xmlDictFree(ctxt->dict);
01550     xmlFree(ctxt);
01551 }
01552 
01553 static xmlNodePtr
01554 xmlSchematronNextNode(xmlNodePtr cur) {
01555     if (cur->children != NULL) {
01556     /*
01557      * Do not descend on entities declarations
01558      */
01559     if (cur->children->type != XML_ENTITY_DECL) {
01560         cur = cur->children;
01561         /*
01562          * Skip DTDs
01563          */
01564         if (cur->type != XML_DTD_NODE)
01565         return(cur);
01566     }
01567     }
01568 
01569     while (cur->next != NULL) {
01570     cur = cur->next;
01571     if ((cur->type != XML_ENTITY_DECL) &&
01572         (cur->type != XML_DTD_NODE))
01573         return(cur);
01574     }
01575     
01576     do {
01577     cur = cur->parent;
01578     if (cur == NULL) break;
01579     if (cur->type == XML_DOCUMENT_NODE) return(NULL);
01580     if (cur->next != NULL) {
01581         cur = cur->next;
01582         return(cur);
01583     }
01584     } while (cur != NULL);
01585     return(cur);
01586 }
01587 
01599 static int
01600 xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt,
01601      xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur, xmlSchematronPatternPtr pattern)
01602 {
01603     xmlXPathObjectPtr ret;
01604     int failed;
01605 
01606     failed = 0;
01607     ctxt->xctxt->doc = instance;
01608     ctxt->xctxt->node = cur;
01609     ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt);
01610     if (ret == NULL) {
01611     failed = 1;
01612     } else {
01613         switch (ret->type) {
01614         case XPATH_XSLT_TREE:
01615         case XPATH_NODESET:
01616         if ((ret->nodesetval == NULL) ||
01617             (ret->nodesetval->nodeNr == 0))
01618             failed = 1;
01619         break;
01620         case XPATH_BOOLEAN:
01621         failed = !ret->boolval;
01622         break;
01623         case XPATH_NUMBER:
01624         if ((xmlXPathIsNaN(ret->floatval)) ||
01625             (ret->floatval == 0.0))
01626             failed = 1;
01627         break;
01628         case XPATH_STRING:
01629         if ((ret->stringval == NULL) ||
01630             (ret->stringval[0] == 0))
01631             failed = 1;
01632         break;
01633         case XPATH_UNDEFINED:
01634         case XPATH_POINT:
01635         case XPATH_RANGE:
01636         case XPATH_LOCATIONSET:
01637         case XPATH_USERS:
01638         failed = 1;
01639         break;
01640     }
01641     xmlXPathFreeObject(ret);
01642     }
01643     if ((failed) && (test->type == XML_SCHEMATRON_ASSERT))
01644         ctxt->nberrors++;
01645     else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT))
01646         ctxt->nberrors++;
01647 
01648     xmlSchematronReportSuccess(ctxt, test, cur, pattern, !failed);
01649 
01650     return(!failed);
01651 }
01652 
01663 int
01664 xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance)
01665 {
01666     xmlNodePtr cur, root;
01667     xmlSchematronPatternPtr pattern;
01668     xmlSchematronRulePtr rule;
01669     xmlSchematronTestPtr test;
01670 
01671     if ((ctxt == NULL) || (ctxt->schema == NULL) ||
01672         (ctxt->schema->rules == NULL) || (instance == NULL))
01673         return(-1);
01674     ctxt->nberrors = 0;
01675     root = xmlDocGetRootElement(instance);
01676     if (root == NULL) {
01677         TODO
01678     ctxt->nberrors++;
01679     return(1);
01680     }
01681     if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) ||
01682         (ctxt->flags == 0)) {
01683     /*
01684      * we are just trying to assert the validity of the document,
01685      * speed primes over the output, run in a single pass
01686      */
01687     cur = root;
01688     while (cur != NULL) {
01689         rule = ctxt->schema->rules;
01690         while (rule != NULL) {
01691         if (xmlPatternMatch(rule->pattern, cur) == 1) {
01692             test = rule->tests;
01693             while (test != NULL) {
01694             xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern);
01695             test = test->next;
01696             }
01697         }
01698         rule = rule->next;
01699         }
01700         
01701         cur = xmlSchematronNextNode(cur);
01702     }
01703     } else {
01704         /*
01705      * Process all contexts one at a time
01706      */
01707     pattern = ctxt->schema->patterns;
01708     
01709     while (pattern != NULL) {
01710         xmlSchematronReportPattern(ctxt, pattern);
01711 
01712         /*
01713          * TODO convert the pattern rule to a direct XPath and
01714          * compute directly instead of using the pattern matching
01715          * over the full document... 
01716          * Check the exact semantic
01717          */
01718         cur = root;
01719         while (cur != NULL) {
01720         rule = pattern->rules;
01721         while (rule != NULL) {
01722             if (xmlPatternMatch(rule->pattern, cur) == 1) {
01723             test = rule->tests;
01724             while (test != NULL) {
01725                 xmlSchematronRunTest(ctxt, test, instance, cur, pattern);
01726                 test = test->next;
01727             }
01728             }
01729             rule = rule->patnext;
01730         }
01731         
01732         cur = xmlSchematronNextNode(cur);
01733         }
01734         pattern = pattern->next;
01735     }
01736     }
01737     return(ctxt->nberrors);
01738 }
01739 
01740 #ifdef STANDALONE
01741 int
01742 main(void)
01743 {
01744     int ret;
01745     xmlDocPtr instance;
01746     xmlSchematronParserCtxtPtr pctxt;
01747     xmlSchematronValidCtxtPtr vctxt;
01748     xmlSchematronPtr schema = NULL;
01749 
01750     pctxt = xmlSchematronNewParserCtxt("tst.sct");
01751     if (pctxt == NULL) {
01752         fprintf(stderr, "failed to build schematron parser\n");
01753     } else {
01754         schema = xmlSchematronParse(pctxt);
01755     if (schema == NULL) {
01756         fprintf(stderr, "failed to compile schematron\n");
01757     }
01758     xmlSchematronFreeParserCtxt(pctxt);
01759     }
01760     instance = xmlReadFile("tst.sct", NULL,
01761                            XML_PARSE_NOENT | XML_PARSE_NOCDATA);
01762     if (instance == NULL) {
01763     fprintf(stderr, "failed to parse instance\n");
01764     }
01765     if ((schema != NULL) && (instance != NULL)) {
01766         vctxt = xmlSchematronNewValidCtxt(schema);
01767     if (vctxt == NULL) {
01768         fprintf(stderr, "failed to build schematron validator\n");
01769     } else {
01770         ret = xmlSchematronValidateDoc(vctxt, instance);
01771         xmlSchematronFreeValidCtxt(vctxt);
01772     }
01773     }
01774     xmlSchematronFree(schema);
01775     xmlFreeDoc(instance);
01776 
01777     xmlCleanupParser();
01778     xmlMemoryDump();
01779 
01780     return (0);
01781 }
01782 #endif
01783 #define bottom_schematron
01784 #include "elfgcchack.h"
01785 #endif /* LIBXML_SCHEMATRON_ENABLED */

Generated on Sun May 27 2012 04:34:33 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.