/**
 * xmlSchematronLoadInclude:
 * @ctxt:  a schema validation context
 * @cur:  the include element
 *
 * Load the include document, Push the current pointer
 *
 * Returns the updated node pointer
 */
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);
    }
    if (href == NULL)
        xmlFree(href);
    if (base == NULL)
        xmlFree(base);
    if (URI == NULL)
        xmlFree(URI);
    return(ret);
}
Esempio n. 2
0
/**
 * 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);
}
Esempio n. 3
0
/**
 * 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);
    }
}
Esempio n. 4
0
/**
 * 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);
}
Esempio n. 5
0
/**
 * 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);
    }
}
Esempio n. 6
0
/**
 * 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;
    if (preserve) {
	    ret->preserve = 1;
    }
    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);
}