DriveHQ Start Menu
Cloud Drive Mapping
Folder Sync
Cloud Backup
True Drop Box
FTP/SFTP Hosting
Group Account
DriveHQ Start Menu
Online File Server
My Storage
|
Manage Shares
|
Publishes
|
Drop Boxes
|
Group Account
WebDAV Drive Mapping
Cloud Drive Home
|
WebDAV Guide
|
Drive Mapping Tool
|
Drive Mapping URL
Complete Data Backup
Backup Guide
|
Online Backup Tool
|
Cloud-to-Cloud Backup
FTP, Email & Web Service
FTP Home
|
FTP Hosting FAQ
|
Email Hosting
|
EmailManager
|
Web Hosting
Help & Resources
About
|
Enterprise Service
|
Partnership
|
Comparisons
|
Support
Quick Links
Security and Privacy
Download Software
Service Manual
Use Cases
Group Account
Online Help
Blog
Contact
Cloud Surveillance
Sign Up
Login
Features
Business Features
Online File Server
FTP Hosting
Cloud Drive Mapping
Cloud File Backup
Email Backup & Hosting
Cloud File Sharing
Folder Synchronization
Group Management
True Drop Box
Full-text Search
AD Integration/SSO
Mobile Access
IP Camera & DVR Solution
More...
Personal Features
Personal Cloud Drive
Backup All Devices
Mobile APPs
Personal Web Hosting
Sub-Account (for Kids)
Home/PC/Kids Monitoring
More...
Software
DriveHQ Drive Mapping Tool
DriveHQ FileManager
DriveHQ Online Backup
DriveHQ Mobile Apps
Pricing
Business Plans & Pricing
Personal Plans & Pricing
Price Comparison with Others
Feature Comparison with Others
Install Mobile App
Sign up
Creating account...
Invalid character in username! Only 0-9, a-z, A-Z, _, -, . allowed.
Username is required!
Invalid email address!
E-mail is required!
Password is required!
Password is invalid!
Password and confirmation do not match.
Confirm password is required!
I accept
Membership Agreement
Please read the Membership Agreement and check "I accept"!
Free Quick Sign-up
Sign-up Page
Log in
Signing in...
Username or e-mail address is required!
Password is required!
Keep me logged in
Quick Login
Forgot Password
Up
Upload
Download
Share
Publish
New Folder
New File
Copy
Cut
Delete
Paste
Rate
Upgrade
Rotate
Effect
Edit
Slide
History
/* * schematron.c : implementation of the Schematron schema validity checking * * See Copyright for the status of this software. * * Daniel Veillard
*/ /* * TODO: * + double check the semantic, especially * - multiple rules applying in a single pattern/node * - the semantic of libxml2 patterns vs. XSLT production referenced * by the spec. * + export of results in SVRL * + full parsing and coverage of the spec, conformance of the input to the * spec * + divergences between the draft and the ISO proposed standard :-( * + hook and test include * + try and compare with the XSLT version */ #define IN_LIBXML #include "libxml.h" #ifdef LIBXML_SCHEMATRON_ENABLED #include
#include
#include
#include
#include
#include
#include
#include
#define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT #define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron" #define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron" static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS; static const xmlChar *xmlOldSchematronNs = SCT_OLD_NS; #define IS_SCHEMATRON(node, elem) \ ((node != NULL) && (node->type == XML_ELEMENT_NODE ) && \ (node->ns != NULL) && \ (xmlStrEqual(node->name, (const xmlChar *) elem)) && \ ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \ (xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) #define NEXT_SCHEMATRON(node) \ while (node != NULL) { \ if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) && \ ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \ (xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) \ break; \ node = node->next; \ } /** * TODO: * * macro to flag unimplemented blocks */ #define TODO \ xmlGenericError(xmlGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__); typedef enum { XML_SCHEMATRON_ASSERT=1, XML_SCHEMATRON_REPORT=2 } xmlSchematronTestType; /** * _xmlSchematronTest: * * A Schematrons test, either an assert or a report */ typedef struct _xmlSchematronTest xmlSchematronTest; typedef xmlSchematronTest *xmlSchematronTestPtr; struct _xmlSchematronTest { xmlSchematronTestPtr next; /* the next test in the list */ xmlSchematronTestType type; /* the test type */ xmlNodePtr node; /* the node in the tree */ xmlChar *test; /* the expression to test */ xmlXPathCompExprPtr comp; /* the compiled expression */ xmlChar *report; /* the message to report */ }; /** * _xmlSchematronRule: * * A Schematrons rule */ typedef struct _xmlSchematronRule xmlSchematronRule; typedef xmlSchematronRule *xmlSchematronRulePtr; struct _xmlSchematronRule { xmlSchematronRulePtr next; /* the next rule in the list */ xmlSchematronRulePtr patnext;/* the next rule in the pattern list */ xmlNodePtr node; /* the node in the tree */ xmlChar *context; /* the context evaluation rule */ xmlSchematronTestPtr tests; /* the list of tests */ xmlPatternPtr pattern; /* the compiled pattern associated */ xmlChar *report; /* the message to report */ }; /** * _xmlSchematronPattern: * * A Schematrons pattern */ typedef struct _xmlSchematronPattern xmlSchematronPattern; typedef xmlSchematronPattern *xmlSchematronPatternPtr; struct _xmlSchematronPattern { xmlSchematronPatternPtr next;/* the next pattern in the list */ xmlSchematronRulePtr rules; /* the list of rules */ xmlChar *name; /* the name of the pattern */ }; /** * _xmlSchematron: * * A Schematrons definition */ struct _xmlSchematron { const xmlChar *name; /* schema name */ int preserve; /* was the document passed by the user */ xmlDocPtr doc; /* pointer to the parsed document */ int flags; /* specific to this schematron */ void *_private; /* unused by the library */ xmlDictPtr dict; /* the dictionnary used internally */ const xmlChar *title; /* the title if any */ int nbNs; /* the number of namespaces */ int nbPattern; /* the number of patterns */ xmlSchematronPatternPtr patterns;/* the patterns found */ xmlSchematronRulePtr rules; /* the rules gathered */ int nbNamespaces; /* number of namespaces in the array */ int maxNamespaces; /* size of the array */ const xmlChar **namespaces; /* the array of namespaces */ }; /** * xmlSchematronValidCtxt: * * A Schematrons validation context */ struct _xmlSchematronValidCtxt { int type; int flags; /* an or of xmlSchematronValidOptions */ xmlDictPtr dict; int nberrors; int err; xmlSchematronPtr schema; xmlXPathContextPtr xctxt; FILE *outputFile; /* if using XML_SCHEMATRON_OUT_FILE */ xmlBufferPtr outputBuffer; /* if using XML_SCHEMATRON_OUT_BUFFER */ xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */ xmlOutputCloseCallback ioclose; void *ioctx; }; struct _xmlSchematronParserCtxt { int type; const xmlChar *URL; xmlDocPtr doc; int preserve; /* Whether the doc should be freed */ const char *buffer; int size; xmlDictPtr dict; /* dictionnary for interned string names */ int nberrors; int err; xmlXPathContextPtr xctxt; /* the XPath context used for compilation */ xmlSchematronPtr schema; int nbNamespaces; /* number of namespaces in the array */ int maxNamespaces; /* size of the array */ const xmlChar **namespaces; /* the array of namespaces */ int nbIncludes; /* number of includes in the array */ int maxIncludes; /* size of the array */ xmlNodePtr *includes; /* the array of includes */ /* error rreporting data */ void *userData; /* user specific data block */ xmlSchematronValidityErrorFunc error;/* the callback in case of errors */ xmlSchematronValidityWarningFunc warning;/* callback in case of warning */ xmlStructuredErrorFunc serror; /* the structured function */ }; #define XML_STRON_CTXT_PARSER 1 #define XML_STRON_CTXT_VALIDATOR 2 /************************************************************************ * * * Error reporting * * * ************************************************************************/ /** * xmlSchematronPErrMemory: * @node: a context node * @extra: extra informations * * Handle an out of memory condition */ static void xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt, const char *extra, xmlNodePtr node) { if (ctxt != NULL) ctxt->nberrors++; __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL, extra); } /** * xmlSchematronPErr: * @ctxt: the parsing context * @node: the context node * @error: the error code * @msg: the error message * @str1: extra data * @str2: extra data * * Handle a parser error */ static void xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error, const char *msg, const xmlChar * str1, const xmlChar * str2) { xmlGenericErrorFunc channel = NULL; xmlStructuredErrorFunc schannel = NULL; void *data = NULL; if (ctxt != NULL) { ctxt->nberrors++; channel = ctxt->error; data = ctxt->userData; schannel = ctxt->serror; } __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, error, XML_ERR_ERROR, NULL, 0, (const char *) str1, (const char *) str2, NULL, 0, 0, msg, str1, str2); } /** * xmlSchematronVTypeErrMemory: * @node: a context node * @extra: extra informations * * Handle an out of memory condition */ static void xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt, const char *extra, xmlNodePtr node) { if (ctxt != NULL) { ctxt->nberrors++; ctxt->err = XML_SCHEMAV_INTERNAL; } __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, extra); } /************************************************************************ * * * Parsing and compilation of the Schematrontrons * * * ************************************************************************/ /** * xmlSchematronAddTest: * @ctxt: the schema parsing context * @type: the type of test * @rule: the parent rule * @node: the node hosting the test * @test: the associated test * @report: the associated report string * * Add a test to a schematron * * Returns the new pointer or NULL in case of error */ static xmlSchematronTestPtr xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt, xmlSchematronTestType type, xmlSchematronRulePtr rule, xmlNodePtr node, xmlChar *test, xmlChar *report) { xmlSchematronTestPtr ret; xmlXPathCompExprPtr comp; if ((ctxt == NULL) || (rule == NULL) || (node == NULL) || (test == NULL)) return(NULL); /* * try first to compile the test expression */ comp = xmlXPathCtxtCompile(ctxt->xctxt, test); if (comp == NULL) { xmlSchematronPErr(ctxt, node, XML_SCHEMAP_NOROOT, "Failed to compile test expression %s", test, NULL); return(NULL); } ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest)); if (ret == NULL) { xmlSchematronPErrMemory(ctxt, "allocating schema test", node); return (NULL); } memset(ret, 0, sizeof(xmlSchematronTest)); ret->type = type; ret->node = node; ret->test = test; ret->comp = comp; ret->report = report; ret->next = NULL; if (rule->tests == NULL) { rule->tests = ret; } else { xmlSchematronTestPtr prev = rule->tests; while (prev->next != NULL) prev = prev->next; prev->next = ret; } return (ret); } /** * xmlSchematronFreeTests: * @tests: a list of tests * * Free a list of tests. */ static void xmlSchematronFreeTests(xmlSchematronTestPtr tests) { xmlSchematronTestPtr next; while (tests != NULL) { next = tests->next; if (tests->test != NULL) xmlFree(tests->test); if (tests->comp != NULL) xmlXPathFreeCompExpr(tests->comp); if (tests->report != NULL) xmlFree(tests->report); xmlFree(tests); tests = next; } } /** * xmlSchematronAddRule: * @ctxt: the schema parsing context * @schema: a schema structure * @node: the node hosting the rule * @context: the associated context string * @report: the associated report string * * Add a rule to a schematron * * Returns the new pointer or NULL in case of error */ static xmlSchematronRulePtr xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema, xmlSchematronPatternPtr pat, xmlNodePtr node, xmlChar *context, xmlChar *report) { xmlSchematronRulePtr ret; xmlPatternPtr pattern; if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (context == NULL)) return(NULL); /* * Try first to compile the pattern */ pattern = xmlPatterncompile(context, ctxt->dict, XML_PATTERN_XPATH, ctxt->namespaces); if (pattern == NULL) { xmlSchematronPErr(ctxt, node, XML_SCHEMAP_NOROOT, "Failed to compile context expression %s", context, NULL); } ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule)); if (ret == NULL) { xmlSchematronPErrMemory(ctxt, "allocating schema rule", node); return (NULL); } memset(ret, 0, sizeof(xmlSchematronRule)); ret->node = node; ret->context = context; ret->pattern = pattern; ret->report = report; ret->next = NULL; if (schema->rules == NULL) { schema->rules = ret; } else { xmlSchematronRulePtr prev = schema->rules; while (prev->next != NULL) prev = prev->next; prev->next = ret; } ret->patnext = NULL; if (pat->rules == NULL) { pat->rules = ret; } else { xmlSchematronRulePtr prev = pat->rules; while (prev->patnext != NULL) prev = prev->patnext; prev->patnext = ret; } return (ret); } /** * xmlSchematronFreeRules: * @rules: a list of rules * * Free a list of rules. */ static void xmlSchematronFreeRules(xmlSchematronRulePtr rules) { xmlSchematronRulePtr next; while (rules != NULL) { next = rules->next; if (rules->tests) xmlSchematronFreeTests(rules->tests); if (rules->context != NULL) xmlFree(rules->context); if (rules->pattern) xmlFreePattern(rules->pattern); if (rules->report != NULL) xmlFree(rules->report); xmlFree(rules); rules = next; } } /** * xmlSchematronAddPattern: * @ctxt: the schema parsing context * @schema: a schema structure * @node: the node hosting the pattern * @id: the id or name of the pattern * * Add a pattern to a schematron * * Returns the new pointer or NULL in case of error */ static xmlSchematronPatternPtr xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema, xmlNodePtr node, xmlChar *name) { xmlSchematronPatternPtr ret; if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (name == NULL)) return(NULL); ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern)); if (ret == NULL) { xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node); return (NULL); } memset(ret, 0, sizeof(xmlSchematronPattern)); ret->name = name; ret->next = NULL; if (schema->patterns == NULL) { schema->patterns = ret; } else { xmlSchematronPatternPtr prev = schema->patterns; while (prev->next != NULL) prev = prev->next; prev->next = ret; } return (ret); } /** * xmlSchematronFreePatterns: * @patterns: a list of patterns * * Free a list of patterns. */ static void xmlSchematronFreePatterns(xmlSchematronPatternPtr patterns) { xmlSchematronPatternPtr next; while (patterns != NULL) { next = patterns->next; if (patterns->name != NULL) xmlFree(patterns->name); xmlFree(patterns); patterns = next; } } /** * xmlSchematronNewSchematron: * @ctxt: a schema validation context * * Allocate a new Schematron structure. * * Returns the newly allocated structure or NULL in case or error */ static xmlSchematronPtr xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt) { xmlSchematronPtr ret; ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron)); if (ret == NULL) { xmlSchematronPErrMemory(ctxt, "allocating schema", NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematron)); ret->dict = ctxt->dict; xmlDictReference(ret->dict); return (ret); } /** * xmlSchematronFree: * @schema: a schema structure * * Deallocate a Schematron structure. */ void xmlSchematronFree(xmlSchematronPtr schema) { if (schema == NULL) return; if ((schema->doc != NULL) && (!(schema->preserve))) xmlFreeDoc(schema->doc); if (schema->namespaces != NULL) xmlFree((char **) schema->namespaces); xmlSchematronFreeRules(schema->rules); xmlSchematronFreePatterns(schema->patterns); xmlDictFree(schema->dict); xmlFree(schema); } /** * xmlSchematronNewParserCtxt: * @URL: the location of the schema * * Create an XML Schematrons parse context for that file/resource expected * to contain an XML Schematrons file. * * Returns the parser context or NULL in case of error */ xmlSchematronParserCtxtPtr xmlSchematronNewParserCtxt(const char *URL) { xmlSchematronParserCtxtPtr ret; if (URL == NULL) return (NULL); ret = (xmlSchematronParserCtxtPtr) xmlMalloc(sizeof(xmlSchematronParserCtxt)); if (ret == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser context", NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronParserCtxt)); ret->type = XML_STRON_CTXT_PARSER; ret->dict = xmlDictCreate(); ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1); ret->includes = NULL; ret->xctxt = xmlXPathNewContext(NULL); if (ret->xctxt == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", NULL); xmlSchematronFreeParserCtxt(ret); return (NULL); } ret->xctxt->flags = XML_XPATH_CHECKNS; return (ret); } /** * xmlSchematronNewMemParserCtxt: * @buffer: a pointer to a char array containing the schemas * @size: the size of the array * * Create an XML Schematrons parse context for that memory buffer expected * to contain an XML Schematrons file. * * Returns the parser context or NULL in case of error */ xmlSchematronParserCtxtPtr xmlSchematronNewMemParserCtxt(const char *buffer, int size) { xmlSchematronParserCtxtPtr ret; if ((buffer == NULL) || (size <= 0)) return (NULL); ret = (xmlSchematronParserCtxtPtr) xmlMalloc(sizeof(xmlSchematronParserCtxt)); if (ret == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser context", NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronParserCtxt)); ret->buffer = buffer; ret->size = size; ret->dict = xmlDictCreate(); ret->xctxt = xmlXPathNewContext(NULL); if (ret->xctxt == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", NULL); xmlSchematronFreeParserCtxt(ret); return (NULL); } return (ret); } /** * xmlSchematronNewDocParserCtxt: * @doc: a preparsed document tree * * Create an XML Schematrons parse context for that document. * NB. The document may be modified during the parsing process. * * Returns the parser context or NULL in case of error */ xmlSchematronParserCtxtPtr xmlSchematronNewDocParserCtxt(xmlDocPtr doc) { xmlSchematronParserCtxtPtr ret; if (doc == NULL) return (NULL); ret = (xmlSchematronParserCtxtPtr) xmlMalloc(sizeof(xmlSchematronParserCtxt)); if (ret == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser context", NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronParserCtxt)); ret->doc = doc; ret->dict = xmlDictCreate(); /* The application has responsibility for the document */ ret->preserve = 1; ret->xctxt = xmlXPathNewContext(doc); if (ret->xctxt == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", NULL); xmlSchematronFreeParserCtxt(ret); return (NULL); } return (ret); } /** * xmlSchematronFreeParserCtxt: * @ctxt: the schema parser context * * Free the resources associated to the schema parser context */ void xmlSchematronFreeParserCtxt(xmlSchematronParserCtxtPtr ctxt) { if (ctxt == NULL) return; if (ctxt->doc != NULL && !ctxt->preserve) xmlFreeDoc(ctxt->doc); if (ctxt->xctxt != NULL) { xmlXPathFreeContext(ctxt->xctxt); } if (ctxt->namespaces != NULL) xmlFree((char **) ctxt->namespaces); xmlDictFree(ctxt->dict); xmlFree(ctxt); } /** * xmlSchematronPushInclude: * @ctxt: the schema parser context * @doc: the included document * @cur: the current include node * * Add an included document */ #if 0 static void xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr cur) { if (ctxt->includes == NULL) { ctxt->maxIncludes = 10; ctxt->includes = (xmlNodePtr *) xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr)); if (ctxt->includes == NULL) { xmlSchematronPErrMemory(NULL, "allocating parser includes", NULL); return; } ctxt->nbIncludes = 0; } else if (ctxt->nbIncludes + 2 >= ctxt->maxIncludes) { xmlNodePtr *tmp; tmp = (xmlNodePtr *) xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 * sizeof(xmlNodePtr)); if (tmp == NULL) { xmlSchematronPErrMemory(NULL, "allocating parser includes", NULL); return; } ctxt->includes = tmp; ctxt->maxIncludes *= 2; } ctxt->includes[2 * ctxt->nbIncludes] = cur; ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc; ctxt->nbIncludes++; } #endif /** * xmlSchematronPopInclude: * @ctxt: the schema parser context * * Pop an include level. The included document is being freed * * Returns the node immediately following the include or NULL if the * include list was empty. */ static xmlNodePtr xmlSchematronPopInclude(xmlSchematronParserCtxtPtr ctxt) { xmlDocPtr doc; xmlNodePtr ret; if (ctxt->nbIncludes <= 0) return(NULL); ctxt->nbIncludes--; doc = (xmlDocPtr) ctxt->includes[2 * ctxt->nbIncludes + 1]; ret = ctxt->includes[2 * ctxt->nbIncludes]; xmlFreeDoc(doc); if (ret != NULL) ret = ret->next; if (ret == NULL) return(xmlSchematronPopInclude(ctxt)); return(ret); } /** * xmlSchematronAddNamespace: * @ctxt: the schema parser context * @prefix: the namespace prefix * @ns: the namespace name * * Add a namespace definition in the context */ static void xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt, const xmlChar *prefix, const xmlChar *ns) { if (ctxt->namespaces == NULL) { ctxt->maxNamespaces = 10; ctxt->namespaces = (const xmlChar **) xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *)); if (ctxt->namespaces == NULL) { xmlSchematronPErrMemory(NULL, "allocating parser namespaces", NULL); return; } ctxt->nbNamespaces = 0; } else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) { const xmlChar **tmp; tmp = (const xmlChar **) xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 * sizeof(const xmlChar *)); if (tmp == NULL) { xmlSchematronPErrMemory(NULL, "allocating parser namespaces", NULL); return; } ctxt->namespaces = tmp; ctxt->maxNamespaces *= 2; } ctxt->namespaces[2 * ctxt->nbNamespaces] = xmlDictLookup(ctxt->dict, ns, -1); ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = xmlDictLookup(ctxt->dict, prefix, -1); ctxt->nbNamespaces++; ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL; ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL; } /** * xmlSchematronParseRule: * @ctxt: a schema validation context * @rule: the rule node * * parse a rule element */ static void xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPatternPtr pattern, xmlNodePtr rule) { xmlNodePtr cur; int nbChecks = 0; xmlChar *test; xmlChar *context; xmlChar *report; xmlSchematronRulePtr ruleptr; xmlSchematronTestPtr testptr; if ((ctxt == NULL) || (rule == NULL)) return; context = xmlGetNoNsProp(rule, BAD_CAST "context"); if (context == NULL) { xmlSchematronPErr(ctxt, rule, XML_SCHEMAP_NOROOT, "rule has no context attribute", NULL, NULL); return; } else if (context[0] == 0) { xmlSchematronPErr(ctxt, rule, XML_SCHEMAP_NOROOT, "rule has an empty context attribute", NULL, NULL); xmlFree(context); return; } else { ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, pattern, rule, context, NULL); if (ruleptr == NULL) { xmlFree(context); return; } } cur = rule->children; NEXT_SCHEMATRON(cur); while (cur != NULL) { if (IS_SCHEMATRON(cur, "assert")) { nbChecks++; test = xmlGetNoNsProp(cur, BAD_CAST "test"); if (test == NULL) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "assert has no test attribute", NULL, NULL); } else if (test[0] == 0) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "assert has an empty test attribute", NULL, NULL); xmlFree(test); } else { /* TODO will need dynamic processing instead */ report = xmlNodeGetContent(cur); testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT, ruleptr, cur, test, report); if (testptr == NULL) xmlFree(test); } } else if (IS_SCHEMATRON(cur, "report")) { nbChecks++; test = xmlGetNoNsProp(cur, BAD_CAST "test"); if (test == NULL) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "assert has no test attribute", NULL, NULL); } else if (test[0] == 0) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "assert has an empty test attribute", NULL, NULL); xmlFree(test); } else { /* TODO will need dynamic processing instead */ report = xmlNodeGetContent(cur); testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT, ruleptr, cur, test, report); if (testptr == NULL) xmlFree(test); } } else { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "Expecting an assert or a report element instead of %s", cur->name, NULL); } cur = cur->next; NEXT_SCHEMATRON(cur); } if (nbChecks == 0) { xmlSchematronPErr(ctxt, rule, XML_SCHEMAP_NOROOT, "rule has no assert nor report element", NULL, NULL); } } /** * xmlSchematronParsePattern: * @ctxt: a schema validation context * @pat: the pattern node * * parse a pattern element */ static void xmlSchematronParsePattern(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr pat) { xmlNodePtr cur; xmlSchematronPatternPtr pattern; int nbRules = 0; xmlChar *id; if ((ctxt == NULL) || (pat == NULL)) return; id = xmlGetNoNsProp(pat, BAD_CAST "id"); if (id == NULL) { id = xmlGetNoNsProp(pat, BAD_CAST "name"); } pattern = xmlSchematronAddPattern(ctxt, ctxt->schema, pat, id); if (pattern == NULL) { if (id != NULL) xmlFree(id); return; } cur = pat->children; NEXT_SCHEMATRON(cur); while (cur != NULL) { if (IS_SCHEMATRON(cur, "rule")) { xmlSchematronParseRule(ctxt, pattern, cur); nbRules++; } else { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "Expecting a rule element instead of %s", cur->name, NULL); } cur = cur->next; NEXT_SCHEMATRON(cur); } if (nbRules == 0) { xmlSchematronPErr(ctxt, pat, XML_SCHEMAP_NOROOT, "Pattern has no rule element", NULL, NULL); } } /** * xmlSchematronLoadInclude: * @ctxt: a schema validation context * @cur: the include element * * Load the include document, Push the current pointer * * Returns the updated node pointer */ #if 0 static xmlNodePtr xmlSchematronLoadInclude(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr cur) { xmlNodePtr ret = NULL; xmlDocPtr doc = NULL; xmlChar *href = NULL; xmlChar *base = NULL; xmlChar *URI = NULL; if ((ctxt == NULL) || (cur == NULL)) return(NULL); href = xmlGetNoNsProp(cur, BAD_CAST "href"); if (href == NULL) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "Include has no href attribute", NULL, NULL); return(cur->next); } /* do the URI base composition, load and find the root */ base = xmlNodeGetBase(cur->doc, cur); URI = xmlBuildURI(href, base); doc = xmlReadFile((const char *) URI, NULL, SCHEMATRON_PARSE_OPTIONS); if (doc == NULL) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_FAILED_LOAD, "could not load include '%s'.\n", URI, NULL); goto done; } ret = xmlDocGetRootElement(doc); if (ret == NULL) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_FAILED_LOAD, "could not find root from include '%s'.\n", URI, NULL); goto done; } /* Success, push the include for rollback on exit */ xmlSchematronPushInclude(ctxt, doc, cur); done: if (ret == NULL) { if (doc != NULL) xmlFreeDoc(doc); } xmlFree(href); if (base != NULL) xmlFree(base); if (URI != NULL) xmlFree(URI); return(ret); } #endif /** * xmlSchematronParse: * @ctxt: a schema validation context * * parse a schema definition resource and build an internal * XML Shema struture which can be used to validate instances. * * Returns the internal XML Schematron structure built from the resource or * NULL in case of error */ xmlSchematronPtr xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt) { xmlSchematronPtr ret = NULL; xmlDocPtr doc; xmlNodePtr root, cur; int preserve = 0; if (ctxt == NULL) return (NULL); ctxt->nberrors = 0; /* * First step is to parse the input document into an DOM/Infoset */ if (ctxt->URL != NULL) { doc = xmlReadFile((const char *) ctxt->URL, NULL, SCHEMATRON_PARSE_OPTIONS); if (doc == NULL) { xmlSchematronPErr(ctxt, NULL, XML_SCHEMAP_FAILED_LOAD, "xmlSchematronParse: could not load '%s'.\n", ctxt->URL, NULL); return (NULL); } ctxt->preserve = 0; } else if (ctxt->buffer != NULL) { doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL, SCHEMATRON_PARSE_OPTIONS); if (doc == NULL) { xmlSchematronPErr(ctxt, NULL, XML_SCHEMAP_FAILED_PARSE, "xmlSchematronParse: could not parse.\n", NULL, NULL); return (NULL); } doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1); ctxt->preserve = 0; } else if (ctxt->doc != NULL) { doc = ctxt->doc; preserve = 1; ctxt->preserve = 1; } else { xmlSchematronPErr(ctxt, NULL, XML_SCHEMAP_NOTHING_TO_PARSE, "xmlSchematronParse: could not parse.\n", NULL, NULL); return (NULL); } /* * Then extract the root and Schematron parse it */ root = xmlDocGetRootElement(doc); if (root == NULL) { xmlSchematronPErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAP_NOROOT, "The schema has no document element.\n", NULL, NULL); if (!preserve) { xmlFreeDoc(doc); } return (NULL); } if (!IS_SCHEMATRON(root, "schema")) { xmlSchematronPErr(ctxt, root, XML_SCHEMAP_NOROOT, "The XML document '%s' is not a XML schematron document", ctxt->URL, NULL); goto exit; } ret = xmlSchematronNewSchematron(ctxt); if (ret == NULL) goto exit; ctxt->schema = ret; /* * scan the schema elements */ cur = root->children; NEXT_SCHEMATRON(cur); if (IS_SCHEMATRON(cur, "title")) { xmlChar *title = xmlNodeGetContent(cur); if (title != NULL) { ret->title = xmlDictLookup(ret->dict, title, -1); xmlFree(title); } cur = cur->next; NEXT_SCHEMATRON(cur); } while (IS_SCHEMATRON(cur, "ns")) { xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix"); xmlChar *uri = xmlGetNoNsProp(cur, BAD_CAST "uri"); if ((uri == NULL) || (uri[0] == 0)) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "ns element has no uri", NULL, NULL); } if ((prefix == NULL) || (prefix[0] == 0)) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "ns element has no prefix", NULL, NULL); } if ((prefix) && (uri)) { xmlXPathRegisterNs(ctxt->xctxt, prefix, uri); xmlSchematronAddNamespace(ctxt, prefix, uri); ret->nbNs++; } if (uri) xmlFree(uri); if (prefix) xmlFree(prefix); cur = cur->next; NEXT_SCHEMATRON(cur); } while (cur != NULL) { if (IS_SCHEMATRON(cur, "pattern")) { xmlSchematronParsePattern(ctxt, cur); ret->nbPattern++; } else { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "Expecting a pattern element instead of %s", cur->name, NULL); } cur = cur->next; NEXT_SCHEMATRON(cur); } if (ret->nbPattern == 0) { xmlSchematronPErr(ctxt, root, XML_SCHEMAP_NOROOT, "The schematron document '%s' has no pattern", ctxt->URL, NULL); goto exit; } /* the original document must be kept for reporting */ ret->doc = doc; preserve = 1; exit: if (!preserve) { xmlFreeDoc(doc); } if (ret != NULL) { if (ctxt->nberrors != 0) { xmlSchematronFree(ret); ret = NULL; } else { ret->namespaces = ctxt->namespaces; ret->nbNamespaces = ctxt->nbNamespaces; ctxt->namespaces = NULL; } } return (ret); } /************************************************************************ * * * Schematrontron Reports handler * * * ************************************************************************/ static xmlNodePtr xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt, xmlNodePtr cur, const xmlChar *xpath) { xmlNodePtr node = NULL; xmlXPathObjectPtr ret; if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL)) return(NULL); ctxt->xctxt->doc = cur->doc; ctxt->xctxt->node = cur; ret = xmlXPathEval(xpath, ctxt->xctxt); if (ret == NULL) return(NULL); if ((ret->type == XPATH_NODESET) && (ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0)) node = ret->nodesetval->nodeTab[0]; xmlXPathFreeObject(ret); return(node); } /** * xmlSchematronReportOutput: * @ctxt: the validation context * @cur: the current node tested * @msg: the message output * * Output part of the report to whatever channel the user selected */ static void xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr cur ATTRIBUTE_UNUSED, const char *msg) { /* TODO */ fprintf(stderr, "%s", msg); } /** * xmlSchematronFormatReport: * @ctxt: the validation context * @test: the test node * @cur: the current node tested * * Build the string being reported to the user. * * Returns a report string or NULL in case of error. The string needs * to be deallocated by teh caller */ static xmlChar * xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, xmlNodePtr test, xmlNodePtr cur) { xmlChar *ret = NULL; xmlNodePtr child, node; if ((test == NULL) || (cur == NULL)) return(ret); child = test->children; while (child != NULL) { if ((child->type == XML_TEXT_NODE) || (child->type == XML_CDATA_SECTION_NODE)) ret = xmlStrcat(ret, child->content); else if (IS_SCHEMATRON(child, "name")) { xmlChar *path; path = xmlGetNoNsProp(child, BAD_CAST "path"); node = cur; if (path != NULL) { node = xmlSchematronGetNode(ctxt, cur, path); if (node == NULL) node = cur; xmlFree(path); } if ((node->ns == NULL) || (node->ns->prefix == NULL)) ret = xmlStrcat(ret, node->name); else { ret = xmlStrcat(ret, node->ns->prefix); ret = xmlStrcat(ret, BAD_CAST ":"); ret = xmlStrcat(ret, node->name); } } else { child = child->next; continue; } /* * remove superfluous \n */ if (ret != NULL) { int len = xmlStrlen(ret); xmlChar c; if (len > 0) { c = ret[len - 1]; if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) { while ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) { len--; if (len == 0) break; c = ret[len - 1]; } ret[len] = ' '; ret[len + 1] = 0; } } } child = child->next; } return(ret); } /** * xmlSchematronReportSuccess: * @ctxt: the validation context * @test: the compiled test * @cur: the current node tested * @success: boolean value for the result * * called from the validation engine when an assert or report test have * been done. */ static void xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt, xmlSchematronTestPtr test, xmlNodePtr cur, int success) { if ((ctxt == NULL) || (cur == NULL) || (test == NULL)) return; /* if quiet and not SVRL report only failures */ if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) && ((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) && (test->type == XML_SCHEMATRON_REPORT)) return; if (ctxt->flags & XML_SCHEMATRON_OUT_XML) { TODO } else { xmlChar *path; char msg[1000]; long line; const xmlChar *report = NULL; if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) || ((test->type == XML_SCHEMATRON_ASSERT) & (success))) return; line = xmlGetLineNo(cur); path = xmlGetNodePath(cur); if (path == NULL) path = (xmlChar *) cur->name; #if 0 if ((test->report != NULL) && (test->report[0] != 0)) report = test->report; #endif if (test->node != NULL) report = xmlSchematronFormatReport(ctxt, test->node, cur); if (report == NULL) { if (test->type == XML_SCHEMATRON_ASSERT) { snprintf(msg, 999, "%s line %ld: node failed assert\n", (const char *) path, line); } else { snprintf(msg, 999, "%s line %ld: node failed report\n", (const char *) path, line); } } else { snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path, line, (const char *) report); xmlFree((char *) report); } xmlSchematronReportOutput(ctxt, cur, &msg[0]); if ((path != NULL) && (path != (xmlChar *) cur->name)) xmlFree(path); } } /** * xmlSchematronReportPattern: * @ctxt: the validation context * @pattern: the current pattern * * called from the validation engine when starting to check a pattern */ static void xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt, xmlSchematronPatternPtr pattern) { if ((ctxt == NULL) || (pattern == NULL)) return; if (ctxt->flags & XML_SCHEMATRON_OUT_QUIET) return; if (ctxt->flags & XML_SCHEMATRON_OUT_XML) { TODO } else { char msg[1000]; if (pattern->name == NULL) return; snprintf(msg, 999, "Pattern: %s\n", (const char *) pattern->name); xmlSchematronReportOutput(ctxt, NULL, &msg[0]); } } /************************************************************************ * * * Validation against a Schematrontron * * * ************************************************************************/ /** * xmlSchematronNewValidCtxt: * @schema: a precompiled XML Schematrons * @options: a set of xmlSchematronValidOptions * * Create an XML Schematrons validation context based on the given schema. * * Returns the validation context or NULL in case of error */ xmlSchematronValidCtxtPtr xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options) { int i; xmlSchematronValidCtxtPtr ret; ret = (xmlSchematronValidCtxtPtr) xmlMalloc(sizeof(xmlSchematronValidCtxt)); if (ret == NULL) { xmlSchematronVErrMemory(NULL, "allocating validation context", NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronValidCtxt)); ret->type = XML_STRON_CTXT_VALIDATOR; ret->schema = schema; ret->xctxt = xmlXPathNewContext(NULL); ret->flags = options; if (ret->xctxt == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", NULL); xmlSchematronFreeValidCtxt(ret); return (NULL); } for (i = 0;i < schema->nbNamespaces;i++) { if ((schema->namespaces[2 * i] == NULL) || (schema->namespaces[2 * i + 1] == NULL)) break; xmlXPathRegisterNs(ret->xctxt, schema->namespaces[2 * i + 1], schema->namespaces[2 * i]); } return (ret); } /** * xmlSchematronFreeValidCtxt: * @ctxt: the schema validation context * * Free the resources associated to the schema validation context */ void xmlSchematronFreeValidCtxt(xmlSchematronValidCtxtPtr ctxt) { if (ctxt == NULL) return; if (ctxt->xctxt != NULL) xmlXPathFreeContext(ctxt->xctxt); if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); xmlFree(ctxt); } static xmlNodePtr xmlSchematronNextNode(xmlNodePtr cur) { if (cur->children != NULL) { /* * Do not descend on entities declarations */ if (cur->children->type != XML_ENTITY_DECL) { cur = cur->children; /* * Skip DTDs */ if (cur->type != XML_DTD_NODE) return(cur); } } while (cur->next != NULL) { cur = cur->next; if ((cur->type != XML_ENTITY_DECL) && (cur->type != XML_DTD_NODE)) return(cur); } do { cur = cur->parent; if (cur == NULL) break; if (cur->type == XML_DOCUMENT_NODE) return(NULL); if (cur->next != NULL) { cur = cur->next; return(cur); } } while (cur != NULL); return(cur); } /** * xmlSchematronRunTest: * @ctxt: the schema validation context * @test: the current test * @instance: the document instace tree * @cur: the current node in the instance * * Validate a rule against a tree instance at a given position * * Returns 1 in case of success, 0 if error and -1 in case of internal error */ static int xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt, xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur) { xmlXPathObjectPtr ret; int failed; failed = 0; ctxt->xctxt->doc = instance; ctxt->xctxt->node = cur; ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt); if (ret == NULL) { failed = 1; } else { switch (ret->type) { case XPATH_XSLT_TREE: case XPATH_NODESET: if ((ret->nodesetval == NULL) || (ret->nodesetval->nodeNr == 0)) failed = 1; break; case XPATH_BOOLEAN: failed = !ret->boolval; break; case XPATH_NUMBER: if ((xmlXPathIsNaN(ret->floatval)) || (ret->floatval == 0.0)) failed = 1; break; case XPATH_STRING: if ((ret->stringval == NULL) || (ret->stringval[0] == 0)) failed = 1; break; case XPATH_UNDEFINED: case XPATH_POINT: case XPATH_RANGE: case XPATH_LOCATIONSET: case XPATH_USERS: failed = 1; break; } xmlXPathFreeObject(ret); } if ((failed) && (test->type == XML_SCHEMATRON_ASSERT)) ctxt->nberrors++; else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT)) ctxt->nberrors++; xmlSchematronReportSuccess(ctxt, test, cur, !failed); return(!failed); } /** * xmlSchematronValidateDoc: * @ctxt: the schema validation context * @instance: the document instace tree * * Validate a tree instance against the schematron * * Returns 0 in case of success, -1 in case of internal error * and an error count otherwise. */ int xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance) { xmlNodePtr cur, root; xmlSchematronPatternPtr pattern; xmlSchematronRulePtr rule; xmlSchematronTestPtr test; if ((ctxt == NULL) || (ctxt->schema == NULL) || (ctxt->schema->rules == NULL) || (instance == NULL)) return(-1); ctxt->nberrors = 0; root = xmlDocGetRootElement(instance); if (root == NULL) { TODO ctxt->nberrors++; return(1); } if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || (ctxt->flags == 0)) { /* * we are just trying to assert the validity of the document, * speed primes over the output, run in a single pass */ cur = root; while (cur != NULL) { rule = ctxt->schema->rules; while (rule != NULL) { if (xmlPatternMatch(rule->pattern, cur) == 1) { test = rule->tests; while (test != NULL) { xmlSchematronRunTest(ctxt, test, instance, cur); test = test->next; } } rule = rule->next; } cur = xmlSchematronNextNode(cur); } } else { /* * Process all contexts one at a time */ pattern = ctxt->schema->patterns; while (pattern != NULL) { xmlSchematronReportPattern(ctxt, pattern); /* * TODO convert the pattern rule to a direct XPath and * compute directly instead of using the pattern matching * over the full document... * Check the exact semantic */ cur = root; while (cur != NULL) { rule = pattern->rules; while (rule != NULL) { if (xmlPatternMatch(rule->pattern, cur) == 1) { test = rule->tests; while (test != NULL) { xmlSchematronRunTest(ctxt, test, instance, cur); test = test->next; } } rule = rule->patnext; } cur = xmlSchematronNextNode(cur); } pattern = pattern->next; } } return(ctxt->nberrors); } #ifdef STANDALONE int main(void) { int ret; xmlDocPtr instance; xmlSchematronParserCtxtPtr pctxt; xmlSchematronValidCtxtPtr vctxt; xmlSchematronPtr schema = NULL; pctxt = xmlSchematronNewParserCtxt("tst.sct"); if (pctxt == NULL) { fprintf(stderr, "failed to build schematron parser\n"); } else { schema = xmlSchematronParse(pctxt); if (schema == NULL) { fprintf(stderr, "failed to compile schematron\n"); } xmlSchematronFreeParserCtxt(pctxt); } instance = xmlReadFile("tst.sct", NULL, XML_PARSE_NOENT | XML_PARSE_NOCDATA); if (instance == NULL) { fprintf(stderr, "failed to parse instance\n"); } if ((schema != NULL) && (instance != NULL)) { vctxt = xmlSchematronNewValidCtxt(schema); if (vctxt == NULL) { fprintf(stderr, "failed to build schematron validator\n"); } else { ret = xmlSchematronValidateDoc(vctxt, instance); xmlSchematronFreeValidCtxt(vctxt); } } xmlSchematronFree(schema); xmlFreeDoc(instance); xmlCleanupParser(); xmlMemoryDump(); return (0); } #endif #define bottom_schematron #include "elfgcchack.h" #endif /* LIBXML_SCHEMATRON_ENABLED */
schematron.c
Page URL
File URL
Prev
80/114
Next
Download
( 45 KB )
Note: The DriveHQ service banners will NOT be displayed if the file owner is a paid member.
Comments
Total ratings:
0
Average rating:
Not Rated
Would you like to comment?
Join DriveHQ
for a free account, or
Logon
if you are already a member.