mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2024-10-26 12:25:09 +03:00
a bit of work done in the train back. added one of the include tests
* relaxng.c: a bit of work done in the train back. * test/relaxng/*: added one of the include tests Daniel
This commit is contained in:
parent
80ec90acf1
commit
a9d912de79
@ -1,3 +1,8 @@
|
||||
Sat Feb 1 19:44:58 CET 2003 Daniel Veillard <daniel@veillard.com>
|
||||
|
||||
* relaxng.c: a bit of work done in the train back.
|
||||
* test/relaxng/*: added one of the include tests
|
||||
|
||||
Thu Jan 30 14:06:55 CET 2003 Daniel Veillard <daniel@veillard.com>
|
||||
|
||||
* relaxng: more work done in the train
|
||||
|
378
relaxng.c
378
relaxng.c
@ -67,6 +67,9 @@ typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
|
||||
typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
|
||||
typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
|
||||
|
||||
typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
|
||||
typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
|
||||
|
||||
typedef enum {
|
||||
XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
|
||||
XML_RELAXNG_COMBINE_CHOICE, /* choice */
|
||||
@ -135,6 +138,7 @@ struct _xmlRelaxNG {
|
||||
xmlHashTablePtr defs; /* define */
|
||||
xmlHashTablePtr refs; /* references */
|
||||
xmlHashTablePtr documents; /* all the documents loaded */
|
||||
xmlHashTablePtr includes; /* all the includes loaded */
|
||||
void *_private; /* unused by the library for users or bindings */
|
||||
};
|
||||
|
||||
@ -164,6 +168,7 @@ struct _xmlRelaxNGParserCtxt {
|
||||
xmlHashTablePtr interleaves; /* keep track of all the interleaves */
|
||||
|
||||
xmlHashTablePtr documents; /* all the documents loaded */
|
||||
xmlHashTablePtr includes; /* all the includes loaded */
|
||||
xmlChar *URL;
|
||||
xmlDocPtr document;
|
||||
|
||||
@ -171,10 +176,16 @@ struct _xmlRelaxNGParserCtxt {
|
||||
int size;
|
||||
|
||||
/* the document stack */
|
||||
xmlRelaxNGDocumentPtr doc; /* Current parsed Node */
|
||||
xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
|
||||
int docNr; /* Depth of the parsing stack */
|
||||
int docMax; /* Max depth of the parsing stack */
|
||||
xmlRelaxNGDocumentPtr *docTab; /* array of docs */
|
||||
|
||||
/* the include stack */
|
||||
xmlRelaxNGIncludePtr inc; /* Current parsed include */
|
||||
int incNr; /* Depth of the include parsing stack */
|
||||
int incMax; /* Max depth of the parsing stack */
|
||||
xmlRelaxNGIncludePtr *incTab; /* array of incs */
|
||||
};
|
||||
|
||||
#define FLAGS_IGNORABLE 1
|
||||
@ -238,6 +249,18 @@ struct _xmlRelaxNGValidCtxt {
|
||||
int flags; /* validation flags */
|
||||
};
|
||||
|
||||
/**
|
||||
* xmlRelaxNGInclude:
|
||||
*
|
||||
* Structure associated to a RelaxNGs document element
|
||||
*/
|
||||
struct _xmlRelaxNGInclude {
|
||||
xmlChar *href; /* the normalized href value */
|
||||
xmlDocPtr doc; /* the associated XML document */
|
||||
xmlRelaxNGDefinePtr content;/* the definitions */
|
||||
xmlRelaxNGPtr schema; /* the schema */
|
||||
};
|
||||
|
||||
/**
|
||||
* xmlRelaxNGDocument:
|
||||
*
|
||||
@ -335,6 +358,27 @@ xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
|
||||
xmlFree(docu);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlRelaxNGFreeInclude:
|
||||
* @incl: a include structure
|
||||
*
|
||||
* Deallocate a RelaxNG include structure.
|
||||
*/
|
||||
static void
|
||||
xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
|
||||
{
|
||||
if (incl == NULL)
|
||||
return;
|
||||
|
||||
if (incl->href != NULL)
|
||||
xmlFree(incl->href);
|
||||
if (incl->doc != NULL)
|
||||
xmlFreeDoc(incl->doc);
|
||||
if (incl->schema != NULL)
|
||||
xmlRelaxNGFree(incl->schema);
|
||||
xmlFree(incl);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlRelaxNGNewRelaxNG:
|
||||
* @ctxt: a Relax-NG validation context (optional)
|
||||
@ -379,6 +423,9 @@ xmlRelaxNGFree(xmlRelaxNGPtr schema)
|
||||
if (schema->documents != NULL)
|
||||
xmlHashFree(schema->documents, (xmlHashDeallocator)
|
||||
xmlRelaxNGFreeDocument);
|
||||
if (schema->includes != NULL)
|
||||
xmlHashFree(schema->includes, (xmlHashDeallocator)
|
||||
xmlRelaxNGFreeInclude);
|
||||
|
||||
xmlFree(schema);
|
||||
}
|
||||
@ -674,6 +721,266 @@ xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state)
|
||||
static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
xmlDocPtr doc);
|
||||
|
||||
/**
|
||||
* xmlRelaxNGIncludePush:
|
||||
* @ctxt: the parser context
|
||||
* @value: the element doc
|
||||
*
|
||||
* Pushes a new include on top of the include stack
|
||||
*
|
||||
* Returns 0 in case of error, the index in the stack otherwise
|
||||
*/
|
||||
static int
|
||||
xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
xmlRelaxNGIncludePtr value)
|
||||
{
|
||||
if (ctxt->incTab == NULL) {
|
||||
ctxt->incMax = 4;
|
||||
ctxt->incNr = 0;
|
||||
ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
|
||||
ctxt->incMax * sizeof(ctxt->incTab[0]));
|
||||
if (ctxt->incTab == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
if (ctxt->incNr >= ctxt->incMax) {
|
||||
ctxt->incMax *= 2;
|
||||
ctxt->incTab =
|
||||
(xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
|
||||
ctxt->incMax *
|
||||
sizeof(ctxt->incTab[0]));
|
||||
if (ctxt->incTab == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
ctxt->incTab[ctxt->incNr] = value;
|
||||
ctxt->inc = value;
|
||||
return (ctxt->incNr++);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlRelaxNGIncludePop:
|
||||
* @ctxt: the parser context
|
||||
*
|
||||
* Pops the top include from the include stack
|
||||
*
|
||||
* Returns the include just removed
|
||||
*/
|
||||
static xmlRelaxNGIncludePtr
|
||||
xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
|
||||
{
|
||||
xmlRelaxNGIncludePtr ret;
|
||||
|
||||
if (ctxt->incNr <= 0)
|
||||
return (0);
|
||||
ctxt->incNr--;
|
||||
if (ctxt->incNr > 0)
|
||||
ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
|
||||
else
|
||||
ctxt->inc = NULL;
|
||||
ret = ctxt->incTab[ctxt->incNr];
|
||||
ctxt->incTab[ctxt->incNr] = 0;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlRelaxNGLoadInclude:
|
||||
* @ctxt: the parser context
|
||||
* @URL: the normalized URL
|
||||
* @node: the include node.
|
||||
*
|
||||
* First lookup if the document is already loaded into the parser context,
|
||||
* check against recursion. If not found the resource is loaded and
|
||||
* the content is preprocessed before being returned back to the caller.
|
||||
*
|
||||
* Returns the xmlRelaxNGIncludePtr or NULL in case of error
|
||||
*/
|
||||
static xmlRelaxNGIncludePtr
|
||||
xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
|
||||
xmlNodePtr node) {
|
||||
xmlRelaxNGIncludePtr ret = NULL;
|
||||
xmlDocPtr doc;
|
||||
int i;
|
||||
xmlNodePtr root, tmp, tmp2, cur;
|
||||
|
||||
/*
|
||||
* check against recursion in the stack
|
||||
*/
|
||||
for (i = 0;i < ctxt->incNr;i++) {
|
||||
if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"Detected an externalRef recursion for %s\n",
|
||||
URL);
|
||||
ctxt->nbErrors++;
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup in the hash table
|
||||
*/
|
||||
if (ctxt->includes == NULL) {
|
||||
ctxt->includes = xmlHashCreate(10);
|
||||
if (ctxt->includes == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"Failed to allocate hash table for document\n");
|
||||
ctxt->nbErrors++;
|
||||
return(NULL);
|
||||
}
|
||||
} else {
|
||||
ret = xmlHashLookup(ctxt->includes, URL);
|
||||
if (ret != NULL)
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load the document
|
||||
*/
|
||||
doc = xmlParseFile((const char *) URL);
|
||||
if (doc == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"xmlRelaxNG: could not load %s\n", URL);
|
||||
ctxt->nbErrors++;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the document structures and register it first.
|
||||
*/
|
||||
ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
|
||||
if (ret == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"xmlRelaxNG: allocate memory for doc %s\n", URL);
|
||||
ctxt->nbErrors++;
|
||||
xmlFreeDoc(doc);
|
||||
return (NULL);
|
||||
}
|
||||
memset(ret, 0, sizeof(xmlRelaxNGInclude));
|
||||
ret->doc = doc;
|
||||
ret->href = xmlStrdup(URL);
|
||||
|
||||
/*
|
||||
* push it on the stack and register it in the hash table
|
||||
*/
|
||||
xmlHashAddEntry(ctxt->includes, URL, ret);
|
||||
xmlRelaxNGIncludePush(ctxt, ret);
|
||||
|
||||
/*
|
||||
* Some preprocessing of the document content, this include recursing
|
||||
* in the include stack.
|
||||
*/
|
||||
doc = xmlRelaxNGCleanupDoc(ctxt, doc);
|
||||
if (doc == NULL) {
|
||||
/* xmlFreeDoc(ctxt->include); */
|
||||
ctxt->inc = NULL;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pop up the include from the stack
|
||||
*/
|
||||
xmlRelaxNGIncludePop(ctxt);
|
||||
|
||||
/*
|
||||
* Check that the top element is a grammar
|
||||
*/
|
||||
root = xmlDocGetRootElement(doc);
|
||||
if (root == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"xmlRelaxNG: included document is empty %s\n", URL);
|
||||
ctxt->nbErrors++;
|
||||
xmlFreeDoc(doc);
|
||||
return (NULL);
|
||||
}
|
||||
if (!IS_RELAXNG(root, "grammar")) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"xmlRelaxNG: included document %s root is not a grammar\n",
|
||||
URL);
|
||||
ctxt->nbErrors++;
|
||||
xmlFreeDoc(doc);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Elimination of redefined rules in the include.
|
||||
*/
|
||||
cur = node->children;
|
||||
while (cur != NULL) {
|
||||
if (IS_RELAXNG(cur, "start")) {
|
||||
int found = 0;
|
||||
|
||||
tmp = root->children;
|
||||
while (tmp != NULL) {
|
||||
tmp2 = tmp->next;
|
||||
if (IS_RELAXNG(tmp, "start")) {
|
||||
found = 1;
|
||||
xmlUnlinkNode(tmp);
|
||||
xmlFreeNode(tmp);
|
||||
}
|
||||
tmp = tmp2;
|
||||
}
|
||||
if (!found) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"xmlRelaxNG: include %s has a start but not the included grammar\n",
|
||||
URL);
|
||||
ctxt->nbErrors++;
|
||||
}
|
||||
} else if (IS_RELAXNG(cur, "define")) {
|
||||
xmlChar *name, *name2;
|
||||
|
||||
name = xmlGetProp(cur, BAD_CAST "name");
|
||||
if (name == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"xmlRelaxNG: include %s has define without name\n",
|
||||
URL);
|
||||
ctxt->nbErrors++;
|
||||
} else {
|
||||
int found = 0;
|
||||
|
||||
tmp = root->children;
|
||||
while (tmp != NULL) {
|
||||
tmp2 = tmp->next;
|
||||
if (IS_RELAXNG(tmp, "define")) {
|
||||
name2 = xmlGetProp(tmp, BAD_CAST "name");
|
||||
if (name2 != NULL) {
|
||||
if (xmlStrEqual(name, name2)) {
|
||||
found = 1;
|
||||
xmlUnlinkNode(tmp);
|
||||
xmlFreeNode(tmp);
|
||||
}
|
||||
xmlFree(name2);
|
||||
}
|
||||
}
|
||||
tmp = tmp2;
|
||||
}
|
||||
if (!found) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"xmlRelaxNG: include %s has a define %s but not the included grammar\n",
|
||||
URL, name);
|
||||
ctxt->nbErrors++;
|
||||
}
|
||||
xmlFree(name);
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlRelaxNGDocumentPush:
|
||||
* @ctxt: the parser context
|
||||
@ -739,7 +1046,7 @@ xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlRelaxNGLoadocument:
|
||||
* xmlRelaxNGLoadExternalRef:
|
||||
* @ctxt: the parser context
|
||||
* @URL: the normalized URL
|
||||
* @ns: the inherited ns if any
|
||||
@ -751,7 +1058,7 @@ xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
|
||||
* Returns the xmlRelaxNGDocumentPtr or NULL in case of error
|
||||
*/
|
||||
static xmlRelaxNGDocumentPtr
|
||||
xmlRelaxNGLoaddocument(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
|
||||
xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
|
||||
const xmlChar *ns) {
|
||||
xmlRelaxNGDocumentPtr ret = NULL;
|
||||
xmlDocPtr doc;
|
||||
@ -2855,6 +3162,8 @@ xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
|
||||
xmlRelaxNGFreeDocument);
|
||||
if (ctxt->docTab != NULL)
|
||||
xmlFree(ctxt->docTab);
|
||||
if (ctxt->incTab != NULL)
|
||||
xmlFree(ctxt->incTab);
|
||||
xmlFree(ctxt);
|
||||
}
|
||||
|
||||
@ -2904,7 +3213,23 @@ xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
|
||||
delete = cur;
|
||||
goto skip_children;
|
||||
} else {
|
||||
if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
|
||||
if (xmlStrEqual(cur->name, BAD_CAST "div")) {
|
||||
/*
|
||||
* implements rule 4.11
|
||||
*/
|
||||
xmlNodePtr child, ins, tmp;
|
||||
|
||||
child = cur->children;
|
||||
ins = child;
|
||||
while (child != NULL) {
|
||||
tmp = child->next;
|
||||
xmlUnlinkNode(child);
|
||||
ins = xmlAddNextSibling(ins, child);
|
||||
child = tmp;
|
||||
}
|
||||
delete = cur;
|
||||
goto skip_children;
|
||||
} else if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
|
||||
xmlChar *href, *ns, *base, *URL;
|
||||
xmlRelaxNGDocumentPtr docu;
|
||||
|
||||
@ -2936,7 +3261,7 @@ xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
|
||||
xmlFree(href);
|
||||
if (base != NULL)
|
||||
xmlFree(base);
|
||||
docu = xmlRelaxNGLoaddocument(ctxt, URL, ns);
|
||||
docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
|
||||
if (docu == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
@ -2949,7 +3274,48 @@ xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
|
||||
xmlFree(URL);
|
||||
cur->_private = docu;
|
||||
} else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
|
||||
TODO
|
||||
xmlChar *href, *base, *URL;
|
||||
xmlRelaxNGIncludePtr incl;
|
||||
|
||||
href = xmlGetProp(cur, BAD_CAST "href");
|
||||
if (href == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"xmlRelaxNGParse: externalRef has no href attribute\n");
|
||||
ctxt->nbErrors++;
|
||||
delete = cur;
|
||||
goto skip_children;
|
||||
}
|
||||
base = xmlNodeGetBase(cur->doc, cur);
|
||||
URL = xmlBuildURI(href, base);
|
||||
if (URL == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"Failed to compute URL for externalRef %s\n", href);
|
||||
ctxt->nbErrors++;
|
||||
if (href != NULL)
|
||||
xmlFree(href);
|
||||
if (base != NULL)
|
||||
xmlFree(base);
|
||||
delete = cur;
|
||||
goto skip_children;
|
||||
}
|
||||
if (href != NULL)
|
||||
xmlFree(href);
|
||||
if (base != NULL)
|
||||
xmlFree(base);
|
||||
incl = xmlRelaxNGLoadInclude(ctxt, URL, cur);
|
||||
if (incl == NULL) {
|
||||
if (ctxt->error != NULL)
|
||||
ctxt->error(ctxt->userData,
|
||||
"Failed to load externalRef %s\n", URL);
|
||||
ctxt->nbErrors++;
|
||||
xmlFree(URL);
|
||||
delete = cur;
|
||||
goto skip_children;
|
||||
}
|
||||
xmlFree(URL);
|
||||
cur->_private = incl;
|
||||
} else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
|
||||
(xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
|
||||
xmlChar *name;
|
||||
|
21
test/relaxng/inline2.rng
Normal file
21
test/relaxng/inline2.rng
Normal file
@ -0,0 +1,21 @@
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
||||
|
||||
<define name="inline">
|
||||
<zeroOrMore>
|
||||
<ref name="inline.class"/>
|
||||
</zeroOrMore>
|
||||
</define>
|
||||
|
||||
<define name="inline.class">
|
||||
<choice>
|
||||
<text/>
|
||||
<element name="bold">
|
||||
<ref name="inline"/>
|
||||
</element>
|
||||
<element name="italic">
|
||||
<ref name="inline"/>
|
||||
</element>
|
||||
</choice>
|
||||
</define>
|
||||
|
||||
</grammar>
|
26
test/relaxng/tutor9_7.rng
Normal file
26
test/relaxng/tutor9_7.rng
Normal file
@ -0,0 +1,26 @@
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
||||
|
||||
<include href="inline2.rng"/>
|
||||
|
||||
<start>
|
||||
<element name="doc">
|
||||
<zeroOrMore>
|
||||
<element name="p">
|
||||
<ref name="inline"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</start>
|
||||
|
||||
<define name="inline.class" combine="choice">
|
||||
<choice>
|
||||
<element name="code">
|
||||
<ref name="inline"/>
|
||||
</element>
|
||||
<element name="em">
|
||||
<ref name="inline"/>
|
||||
</element>
|
||||
</choice>
|
||||
</define>
|
||||
|
||||
</grammar>
|
Loading…
Reference in New Issue
Block a user