Newer
Older
/*
* schematron.c : implementation of the Schematron schema validity checking
*
* See Copyright for the status of this software.
*
* Daniel Veillard <daniel@veillard.com>
*/
/*
* 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 <string.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/uri.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/pattern.h>
#include <libxml/schematron.h>
#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;
/**
* _xmlSchematronLet:
*
* A Schematron let variable
*/
typedef struct _xmlSchematronLet xmlSchematronLet;
typedef xmlSchematronLet *xmlSchematronLetPtr;
struct _xmlSchematronLet {
xmlSchematronLetPtr next; /* the next let variable in the list */
xmlChar *name; /* the name of the variable */
xmlXPathCompExprPtr comp; /* the compiled expression */
};
/**
* _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 */
xmlSchematronLetPtr lets; /* the list of let variables */
};
/**
* _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 dictionary used internally */
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 */
#ifdef LIBXML_OUTPUT_ENABLED
xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */
xmlOutputCloseCallback ioclose;
void *ioctx;
/* error reporting 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 */
};
struct _xmlSchematronParserCtxt {
int type;
const xmlChar *URL;
xmlDocPtr doc;
int preserve; /* Whether the doc should be freed */
const char *buffer;
int size;
xmlDictPtr dict; /* dictionary 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 reporting 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
/************************************************************************
************************************************************************/
/**
* xmlSchematronPErrMemory:
* @node: a context node
*
* 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 LIBXML_ATTR_FORMAT(4,0)
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;
}
__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
*
* 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) {
} 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;
}
}
/**
* xmlSchematronFreeLets:
* @lets: a list of let variables
*
* Free a list of let variables.
*/
static void
xmlSchematronFreeLets(xmlSchematronLetPtr lets) {
xmlSchematronLetPtr next;
while (lets != NULL) {
next = lets->next;
if (lets->name != NULL)
xmlFree(lets->name);
if (lets->comp != NULL)
xmlXPathFreeCompExpr(lets->comp);
xmlFree(lets);
lets = 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,
{
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) {
} else {
xmlSchematronRulePtr prev = schema->rules;
while (prev->next != NULL)
prev = prev->next;
prev->next = ret;
}
ret->patnext = NULL;
if (pat->rules == NULL) {
} 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);
if (rules->lets != NULL)
xmlSchematronFreeLets(rules->lets);
}
}
/**
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
* 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) {
} 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;
}
}
/**
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
* 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)
xmlSchematronFreeRules(schema->rules);
xmlSchematronFreePatterns(schema->patterns);
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
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);
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
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);
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
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);
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)
xmlDictFree(ctxt->dict);
xmlFree(ctxt);
}
#if 0
/**
* xmlSchematronPushInclude:
* @ctxt: the schema parser context
* @doc: the included document
* @cur: the current include node
*
* Add an included document
*/
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;
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
}
ctxt->includes[2 * ctxt->nbIncludes] = cur;
ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc;
ctxt->nbIncludes++;
}
/**
* 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)
if (ret == NULL)
return(xmlSchematronPopInclude(ctxt));
return(ret);
}
#endif
/**
* 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;
}
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;
}
/**
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
* xmlSchematronParseTestReportMsg:
* @ctxt: the schema parser context
* @con: the assert or report node
*
* Format the message content of the assert or report test
*/
static void
xmlSchematronParseTestReportMsg(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr con)
{
xmlNodePtr child;
xmlXPathCompExprPtr comp;
child = con->children;
while (child != NULL) {
if ((child->type == XML_TEXT_NODE) ||
(child->type == XML_CDATA_SECTION_NODE))
/* Do Nothing */
{}
else if (IS_SCHEMATRON(child, "name")) {
/* Do Nothing */
} else if (IS_SCHEMATRON(child, "value-of")) {
xmlChar *select;
select = xmlGetNoNsProp(child, BAD_CAST "select");
if (select == NULL) {
xmlSchematronPErr(ctxt, child,
XML_SCHEMAV_ATTRINVALID,
"value-of has no select attribute",
NULL, NULL);
} else {
/*
* try first to compile the test expression
*/
comp = xmlXPathCtxtCompile(ctxt->xctxt, select);
if (comp == NULL) {
xmlSchematronPErr(ctxt, child,
XML_SCHEMAV_ATTRINVALID,
"Failed to compile select expression %s",
select, NULL);
}
xmlXPathFreeCompExpr(comp);
}
xmlFree(select);
}
child = child->next;
continue;
}
}
/**
* xmlSchematronParseRule:
* @ctxt: a schema validation context
* @rule: the rule node
*
* parse a rule element
*/
static void
xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt,
xmlSchematronPatternPtr pattern,
{
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, "let")) {
xmlXPathCompExprPtr var_comp;
xmlSchematronLetPtr let;
name = xmlGetNoNsProp(cur, BAD_CAST "name");
if (name == NULL) {
xmlSchematronPErr(ctxt, cur,
XML_SCHEMAP_NOROOT,
"let has no name attribute",
NULL, NULL);
return;
} else if (name[0] == 0) {
xmlSchematronPErr(ctxt, cur,
XML_SCHEMAP_NOROOT,
"let has an empty name attribute",
NULL, NULL);
xmlFree(name);
return;
}
value = xmlGetNoNsProp(cur, BAD_CAST "value");
if (value == NULL) {