mirror of
https://gitlab.gnome.org/GNOME/libxml2
synced 2025-03-28 21:33:13 +00:00
Add let variable tag support
This commit is contained in:
parent
2cc93f7754
commit
e5cdb02d64
170
schematron.c
170
schematron.c
@ -76,6 +76,19 @@ typedef enum {
|
|||||||
XML_SCHEMATRON_REPORT=2
|
XML_SCHEMATRON_REPORT=2
|
||||||
} xmlSchematronTestType;
|
} 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:
|
* _xmlSchematronTest:
|
||||||
*
|
*
|
||||||
@ -107,6 +120,7 @@ struct _xmlSchematronRule {
|
|||||||
xmlSchematronTestPtr tests; /* the list of tests */
|
xmlSchematronTestPtr tests; /* the list of tests */
|
||||||
xmlPatternPtr pattern; /* the compiled pattern associated */
|
xmlPatternPtr pattern; /* the compiled pattern associated */
|
||||||
xmlChar *report; /* the message to report */
|
xmlChar *report; /* the message to report */
|
||||||
|
xmlSchematronLetPtr lets; /* the list of let variables */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -376,6 +390,27 @@ xmlSchematronFreeTests(xmlSchematronTestPtr tests) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
* xmlSchematronAddRule:
|
||||||
* @ctxt: the schema parsing context
|
* @ctxt: the schema parsing context
|
||||||
@ -423,6 +458,7 @@ xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema,
|
|||||||
ret->pattern = pattern;
|
ret->pattern = pattern;
|
||||||
ret->report = report;
|
ret->report = report;
|
||||||
ret->next = NULL;
|
ret->next = NULL;
|
||||||
|
ret->lets = NULL;
|
||||||
if (schema->rules == NULL) {
|
if (schema->rules == NULL) {
|
||||||
schema->rules = ret;
|
schema->rules = ret;
|
||||||
} else {
|
} else {
|
||||||
@ -465,6 +501,8 @@ xmlSchematronFreeRules(xmlSchematronRulePtr rules) {
|
|||||||
xmlFreePattern(rules->pattern);
|
xmlFreePattern(rules->pattern);
|
||||||
if (rules->report != NULL)
|
if (rules->report != NULL)
|
||||||
xmlFree(rules->report);
|
xmlFree(rules->report);
|
||||||
|
if (rules->lets != NULL)
|
||||||
|
xmlSchematronFreeLets(rules->lets);
|
||||||
xmlFree(rules);
|
xmlFree(rules);
|
||||||
rules = next;
|
rules = next;
|
||||||
}
|
}
|
||||||
@ -907,6 +945,8 @@ xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt,
|
|||||||
xmlChar *test;
|
xmlChar *test;
|
||||||
xmlChar *context;
|
xmlChar *context;
|
||||||
xmlChar *report;
|
xmlChar *report;
|
||||||
|
xmlChar *name;
|
||||||
|
xmlChar *value;
|
||||||
xmlSchematronRulePtr ruleptr;
|
xmlSchematronRulePtr ruleptr;
|
||||||
xmlSchematronTestPtr testptr;
|
xmlSchematronTestPtr testptr;
|
||||||
|
|
||||||
@ -938,7 +978,63 @@ xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt,
|
|||||||
cur = rule->children;
|
cur = rule->children;
|
||||||
NEXT_SCHEMATRON(cur);
|
NEXT_SCHEMATRON(cur);
|
||||||
while (cur != NULL) {
|
while (cur != NULL) {
|
||||||
if (IS_SCHEMATRON(cur, "assert")) {
|
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) {
|
||||||
|
xmlSchematronPErr(ctxt, cur,
|
||||||
|
XML_SCHEMAP_NOROOT,
|
||||||
|
"let has no value attribute",
|
||||||
|
NULL, NULL);
|
||||||
|
return;
|
||||||
|
} else if (value[0] == 0) {
|
||||||
|
xmlSchematronPErr(ctxt, cur,
|
||||||
|
XML_SCHEMAP_NOROOT,
|
||||||
|
"let has an empty value attribute",
|
||||||
|
NULL, NULL);
|
||||||
|
xmlFree(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_comp = xmlXPathCtxtCompile(ctxt->xctxt, value);
|
||||||
|
if (var_comp == NULL) {
|
||||||
|
xmlSchematronPErr(ctxt, cur,
|
||||||
|
XML_SCHEMAP_NOROOT,
|
||||||
|
"Failed to compile let expression %s",
|
||||||
|
value, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let = (xmlSchematronLetPtr) malloc(sizeof(xmlSchematronLet));
|
||||||
|
let->name = name;
|
||||||
|
let->comp = var_comp;
|
||||||
|
let->next = NULL;
|
||||||
|
|
||||||
|
/* add new let variable to the beginning of the list */
|
||||||
|
if (ruleptr->lets != NULL) {
|
||||||
|
let->next = ruleptr->lets;
|
||||||
|
}
|
||||||
|
ruleptr->lets = let;
|
||||||
|
|
||||||
|
xmlFree(value);
|
||||||
|
} else if (IS_SCHEMATRON(cur, "assert")) {
|
||||||
nbChecks++;
|
nbChecks++;
|
||||||
test = xmlGetNoNsProp(cur, BAD_CAST "test");
|
test = xmlGetNoNsProp(cur, BAD_CAST "test");
|
||||||
if (test == NULL) {
|
if (test == NULL) {
|
||||||
@ -1755,6 +1851,65 @@ xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt,
|
|||||||
return(!failed);
|
return(!failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xmlSchematronRegisterVariables:
|
||||||
|
* @ctxt: the schema validation context
|
||||||
|
* @let: the list of let variables
|
||||||
|
* @instance: the document instance tree
|
||||||
|
* @cur: the current node
|
||||||
|
*
|
||||||
|
* Registers a list of let variables to the current context of @cur
|
||||||
|
*
|
||||||
|
* Returns -1 in case of errors, otherwise 0
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xmlSchematronRegisterVariables(xmlXPathContextPtr ctxt, xmlSchematronLetPtr let,
|
||||||
|
xmlDocPtr instance, xmlNodePtr cur)
|
||||||
|
{
|
||||||
|
xmlXPathObjectPtr let_eval;
|
||||||
|
|
||||||
|
ctxt->doc = instance;
|
||||||
|
ctxt->node = cur;
|
||||||
|
while (let != NULL) {
|
||||||
|
let_eval = xmlXPathCompiledEval(let->comp, ctxt);
|
||||||
|
if (let_eval == NULL) {
|
||||||
|
xmlGenericError(xmlGenericErrorContext,
|
||||||
|
"Evaluation of compiled expression failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(xmlXPathRegisterVariableNS(ctxt, let->name, NULL, let_eval)) {
|
||||||
|
xmlGenericError(xmlGenericErrorContext,
|
||||||
|
"Registering a let variable failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
let = let->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xmlSchematronUnregisterVariables:
|
||||||
|
* @ctxt: the schema validation context
|
||||||
|
* @let: the list of let variables
|
||||||
|
*
|
||||||
|
* Unregisters a list of let variables from the context
|
||||||
|
*
|
||||||
|
* Returns -1 in case of errors, otherwise 0
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xmlSchematronUnregisterVariables(xmlXPathContextPtr ctxt, xmlSchematronLetPtr let)
|
||||||
|
{
|
||||||
|
while (let != NULL) {
|
||||||
|
if (xmlXPathRegisterVariableNS(ctxt, let->name, NULL, NULL)) {
|
||||||
|
xmlGenericError(xmlGenericErrorContext,
|
||||||
|
"Unregistering a let variable failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
let = let->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xmlSchematronValidateDoc:
|
* xmlSchematronValidateDoc:
|
||||||
* @ctxt: the schema validation context
|
* @ctxt: the schema validation context
|
||||||
@ -1795,10 +1950,18 @@ xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance)
|
|||||||
while (rule != NULL) {
|
while (rule != NULL) {
|
||||||
if (xmlPatternMatch(rule->pattern, cur) == 1) {
|
if (xmlPatternMatch(rule->pattern, cur) == 1) {
|
||||||
test = rule->tests;
|
test = rule->tests;
|
||||||
|
|
||||||
|
if (xmlSchematronRegisterVariables(ctxt->xctxt, rule->lets, instance, cur))
|
||||||
|
return -1;
|
||||||
|
|
||||||
while (test != NULL) {
|
while (test != NULL) {
|
||||||
xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern);
|
xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern);
|
||||||
test = test->next;
|
test = test->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xmlSchematronUnregisterVariables(ctxt->xctxt, rule->lets))
|
||||||
|
return -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
rule = rule->next;
|
rule = rule->next;
|
||||||
}
|
}
|
||||||
@ -1826,10 +1989,15 @@ xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance)
|
|||||||
while (rule != NULL) {
|
while (rule != NULL) {
|
||||||
if (xmlPatternMatch(rule->pattern, cur) == 1) {
|
if (xmlPatternMatch(rule->pattern, cur) == 1) {
|
||||||
test = rule->tests;
|
test = rule->tests;
|
||||||
|
xmlSchematronRegisterVariables(ctxt->xctxt, rule->lets,
|
||||||
|
instance, cur);
|
||||||
|
|
||||||
while (test != NULL) {
|
while (test != NULL) {
|
||||||
xmlSchematronRunTest(ctxt, test, instance, cur, pattern);
|
xmlSchematronRunTest(ctxt, test, instance, cur, pattern);
|
||||||
test = test->next;
|
test = test->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xmlSchematronUnregisterVariables(ctxt->xctxt, rule->lets);
|
||||||
}
|
}
|
||||||
rule = rule->patnext;
|
rule = rule->patnext;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user