From c08a2c6fd41773f55853c5d93a67a932c61511e9 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Wed, 8 Sep 1999 21:35:25 +0000 Subject: [PATCH] Bug fixes, improvement on ID/IDREF support, 1.6.2, no memleaks, Daniel --- ChangeLog | 12 ++ HACKING | 2 +- HTMLparser.c | 2 + SAX.c | 7 +- configure.in | 2 +- doc/xml.html | 4 +- include/libxml/parserInternals.h | 3 + include/libxml/tree.h | 18 ++ include/libxml/valid.h | 27 +++ include/libxml/xpath.h | 107 ++++++++++- parser.c | 4 +- parserInternals.h | 3 + testXPath.c | 2 +- tree.c | 2 + tree.h | 18 ++ valid.c | 305 ++++++++++++++++++++++++++++++- valid.h | 27 +++ xpath.c | 22 ++- xpath.h | 107 ++++++++++- 19 files changed, 647 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index a60e0a73..e939c0c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Wed Sep 8 22:46:14 CEST 1999 Daniel Veillard + + * HTMLparser.c : cleanup + * SAX.c valid.c valid.h: added ID/IDREF checking + * tree.c tree.h: extended doc structure for refs + * configure.in: 1.6.2 + * parser.c: patched bug in SAX user arg call + * parserInternals.h: patched missing close in C++ wrapping + * testXPath.c xpath.c xpath.h: prepared for extensibility, + especially upcoming XPointer implementation. + * doc/xml.html: augmented, typo + Sat Sep 4 22:48:05 CEST 1999 Timur Bakeyev * doc/Makefile.am: replaced "install -d " with "mkinstalldirs" - diff --git a/HACKING b/HACKING index 6b702fa5..8f791bc0 100644 --- a/HACKING +++ b/HACKING @@ -15,7 +15,7 @@ mean that I'm on holliday or on the road. The reasons I'm asking for an ask before commit policy is that I'm using a separate CVS base for unstable developments and if you commit a patch I didn't get, I may loose your change by mistake (it happened -already once) and seriously complicatye my job of merging both bases. +already once) and seriously complicates my job of merging both bases. (The second base is at http://dev.w3.org/ under the XML module). thanks in advance for following the rule, diff --git a/HTMLparser.c b/HTMLparser.c index adfa2d99..a559d9b7 100644 --- a/HTMLparser.c +++ b/HTMLparser.c @@ -1133,6 +1133,8 @@ htmlNewDoc(const CHAR *URI, const CHAR *ExternalID) { cur->encoding = NULL; cur->standalone = 1; cur->compression = 0; + cur->ids = NULL; + cur->refs = NULL; #ifndef XML_WITHOUT_CORBA cur->_private = NULL; cur->vepv = NULL; diff --git a/SAX.c b/SAX.c index 57443edf..d0c08fed 100644 --- a/SAX.c +++ b/SAX.c @@ -492,10 +492,13 @@ startDocument(void *ctx) void endDocument(void *ctx) { - /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; #ifdef DEBUG_SAX fprintf(stderr, "SAX.endDocument()\n"); #endif + if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) + ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc); } /** @@ -572,6 +575,8 @@ attribute(void *ctx, const CHAR *fullname, const CHAR *value) */ if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret); + else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) + xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret); } if (name != NULL) diff --git a/configure.in b/configure.in index 7d33d2b8..49d57083 100644 --- a/configure.in +++ b/configure.in @@ -5,7 +5,7 @@ AM_CONFIG_HEADER(config.h) LIBXML_MAJOR_VERSION=1 LIBXML_MINOR_VERSION=6 -LIBXML_MICRO_VERSION=1 +LIBXML_MICRO_VERSION=2 LIBXML_VERSION=$LIBXML_MAJOR_VERSION.$LIBXML_MINOR_VERSION.$LIBXML_MICRO_VERSION LIBXML_VERSION_INFO=`expr $LIBXML_MAJOR_VERSION + $LIBXML_MINOR_VERSION`:$LIBXML_MICRO_VERSION:$LIBXML_MINOR_VERSION diff --git a/doc/xml.html b/doc/xml.html index 49e08997..a5afae11 100644 --- a/doc/xml.html +++ b/doc/xml.html @@ -529,7 +529,7 @@ core.

Model this is an API for accessing XML or HTML structured documents. Native support for DOM in Gnome is on the way (module gnome-dom), and it will be based on gnome-xml. This will be a far cleaner interface to manipulate XML -files within Gnome since it won't expose the internal structure. DOM defiles a +files within Gnome since it won't expose the internal structure. DOM defines a set of IDL (or Java) interfaces allowing to traverse and manipulate a document. The DOM library will allow accessing and modifying "live" documents presents on other programs like this:

@@ -747,6 +747,6 @@ base under gnome-xml/example

Daniel Veillard

-

$Id$

+

$Id: xml.html,v 1.7 1999/09/04 18:27:23 veillard Exp $

diff --git a/include/libxml/parserInternals.h b/include/libxml/parserInternals.h index 13ea1362..cb289435 100644 --- a/include/libxml/parserInternals.h +++ b/include/libxml/parserInternals.h @@ -637,4 +637,7 @@ int inputPush (xmlParserCtxtPtr ctxt, xmlParserInputPtr value); xmlParserInputPtr inputPop (xmlParserCtxtPtr ctxt); +#ifdef __cplusplus +} +#endif #endif /* __XML_PARSER_INTERNALS_H__ */ diff --git a/include/libxml/tree.h b/include/libxml/tree.h index 6d22ac12..bf8a77ed 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -210,6 +210,17 @@ typedef struct xmlID { } xmlID; typedef xmlID *xmlIDPtr; +/* + * An XML IDREF instance. + */ + +typedef struct xmlRef { + struct xmlRef *next; /* next Ref */ + const CHAR *value; /* The Ref name */ + xmlAttrPtr attr; /* The attribut holding it */ +} xmlRef; +typedef xmlRef *xmlRefPtr; + /* * A node in an XML tree. */ @@ -253,6 +264,7 @@ typedef struct xmlDoc { struct xmlNs *oldNs; /* Global namespace, the old way */ struct xmlNode *root; /* the document tree */ void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ } _xmlDoc; typedef _xmlDoc xmlDoc; typedef xmlDoc *xmlDocPtr; @@ -440,6 +452,12 @@ const CHAR * xmlNodeGetLang (xmlNodePtr cur); void xmlNodeSetLang (xmlNodePtr cur, const CHAR *lang); +/* + * Removing content. + */ +int xmlRemoveProp (xmlAttrPtr attr); /* TODO */ +int xmlRemoveNode (xmlNodePtr node); /* TODO */ + /* * Internal, don't use */ diff --git a/include/libxml/valid.h b/include/libxml/valid.h index 37b4f999..22a2c27c 100644 --- a/include/libxml/valid.h +++ b/include/libxml/valid.h @@ -88,6 +88,20 @@ typedef struct xmlIDTable { } xmlIDTable; typedef xmlIDTable *xmlIDTablePtr; +/* + * ALl Refs attributes are stored in a table + * there is one table per document + */ + +#define XML_MIN_REF_TABLE 32 + +typedef struct xmlRefTable { + int nb_refs; /* number of refs stored */ + int max_refs; /* maximum number of refs */ + xmlRefPtr *table; /* the table of refs */ +} xmlRefTable; +typedef xmlRefTable *xmlRefTablePtr; + /* Notation */ xmlNotationPtr xmlAddNotationDecl (xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, @@ -148,6 +162,17 @@ int xmlIsID (xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr); +/* IDREFs */ +xmlRefPtr xmlAddRef (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const CHAR *value, + xmlAttrPtr attr); +xmlRefTablePtr xmlCopyRefTable (xmlRefTablePtr table); +void xmlFreeRefTable (xmlRefTablePtr table); +int xmlIsRef (xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr); + /** * The public function calls related to validity checking */ @@ -181,6 +206,8 @@ int xmlValidateOneAttribute (xmlValidCtxtPtr ctxt, xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value); +int xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, + xmlDocPtr doc); int xmlValidateNotationUse (xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *notationName); diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h index 64085032..d46c0633 100644 --- a/include/libxml/xpath.h +++ b/include/libxml/xpath.h @@ -14,6 +14,8 @@ #include "tree.h" +typedef struct xmlXPathParserContext *xmlXPathParserContextPtr; + /* * A node-set (an unordered collection of nodes without duplicates) */ @@ -37,6 +39,7 @@ typedef struct xmlNodeSet { #define XPATH_BOOLEAN 2 #define XPATH_NUMBER 3 #define XPATH_STRING 4 +#define XPATH_USERS 5 typedef struct xmlXPathObject { int type; @@ -44,8 +47,66 @@ typedef struct xmlXPathObject { int boolval; double floatval; CHAR *stringval; + void *user; } xmlXPathObject, *xmlXPathObjectPtr; +/* + * A conversion function is associated to a type and used to cast + * the new type to primitive values. + */ +typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type); + +/* + * Extra type: a name and a conversion function. + */ + +typedef struct xmlXPathType { + const CHAR *name; /* the type name */ + xmlXPathConvertFunc func; /* the conversion function */ +} xmlXPathType, *xmlXPathTypePtr; + +/* + * Extra variable: a name and a value. + */ + +typedef struct xmlXPathVariable { + const CHAR *name; /* the variable name */ + xmlXPathObjectPtr value; /* the value */ +} xmlXPathVariable, *xmlXPathVariablePtr; + +/* + * an evaluation function, the parameters are on the context stack + */ + +typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, int nargs); + +/* + * Extra function: a name and a evaluation function. + */ + +typedef struct xmlXPathFunct { + const CHAR *name; /* the function name */ + xmlXPathEvalFunc func; /* the evaluation function */ +} xmlXPathFunc, *xmlXPathFuncPtr; + +/* + * An axis traversal function. To traverse an axis, the engine calls + * the first time with cur == NULL and repeat until the function returns + * NULL indicating the end of the axis traversal. + */ + +typedef xmlXPathObjectPtr (*xmlXPathAxisFunc) (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr cur); + +/* + * Extra axis: a name and an axis function. + */ + +typedef struct xmlXPathAxis { + const CHAR *name; /* the axis name */ + xmlXPathAxisFunc func; /* the search function */ +} xmlXPathAxis, *xmlXPathAxisPtr; + /* * Expression evaluation occurs with respect to a context. * he context consists of: @@ -60,10 +121,27 @@ typedef struct xmlXPathContext { xmlDocPtr doc; /* The current document */ xmlNodePtr node; /* The current node */ xmlNodeSetPtr nodelist; /* The current node list */ - void *variables; /* TODO !!!! */ - void *functions; /* TODO !!!! */ + + int nb_variables; /* number of defined variables */ + int max_variables; /* max number of variables */ + xmlXPathVariablePtr *variables; /* Array of defined variables */ + + int nb_types; /* number of defined types */ + int max_types; /* max number of types */ + xmlXPathTypePtr *types; /* Array of defined types */ + + int nb_funcs; /* number of defined funcs */ + int max_funcs; /* max number of funcs */ + xmlXPathFuncPtr *funcs; /* Array of defined funcs */ + + int nb_axis; /* number of defined axis */ + int max_axis; /* max number of axis */ + xmlXPathAxisPtr *axis; /* Array of defined axis */ + + /* Namespace traversal should be implemented with user */ xmlNsPtr *namespaces; /* The namespaces lookup */ int nsNr; /* the current Namespace index */ + void *user; /* user defined extra info */ } xmlXPathContext, *xmlXPathContextPtr; /* @@ -81,7 +159,7 @@ typedef struct xmlXPathParserContext { int valueNr; /* number of values stacked */ int valueMax; /* max number of values stacked */ xmlXPathObjectPtr *valueTab; /* stack of values */ -} xmlXPathParserContext, *xmlXPathParserContextPtr; +} xmlXPathParserContext; /* * An XPath function @@ -97,9 +175,26 @@ typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs); * * ************************************************************************/ -xmlXPathContextPtr xmlXPathNewContext (xmlDocPtr doc, - void *variables, - void *functions); +/** + * Registering extensions to the expression language + */ +/* TODO */ int xmlXPathRegisterType (xmlXPathContextPtr ctxt, + const CHAR *name, + xmlXPathConvertFunc f); +/* TODO */ int xmlXPathRegisterAxis (xmlXPathContextPtr ctxt, + const CHAR *name, + xmlXPathAxisFunc f); +/* TODO */ int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, + const CHAR *name, + xmlXPathFunction f); +/* TODO */ int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, + const CHAR *name, + xmlXPathObject value); + +/** + * Evaluation functions. + */ +xmlXPathContextPtr xmlXPathNewContext (xmlDocPtr doc); void xmlXPathFreeContext (xmlXPathContextPtr ctxt); xmlXPathObjectPtr xmlXPathEval (const CHAR *str, xmlXPathContextPtr ctxt); diff --git a/parser.c b/parser.c index 0f3e7cfa..1b353fb0 100644 --- a/parser.c +++ b/parser.c @@ -3122,11 +3122,11 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { if (isParameter) { if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) - cur = ctxt->sax->getParameterEntity(ctxt, name); + cur = ctxt->sax->getParameterEntity(ctxt->userData, name); } else { if ((ctxt->sax != NULL) && (ctxt->sax->getEntity != NULL)) - cur = ctxt->sax->getEntity(ctxt, name); + cur = ctxt->sax->getEntity(ctxt->userData, name); } if (cur != NULL) { if (cur->orig != NULL) diff --git a/parserInternals.h b/parserInternals.h index 13ea1362..cb289435 100644 --- a/parserInternals.h +++ b/parserInternals.h @@ -637,4 +637,7 @@ int inputPush (xmlParserCtxtPtr ctxt, xmlParserInputPtr value); xmlParserInputPtr inputPop (xmlParserCtxtPtr ctxt); +#ifdef __cplusplus +} +#endif #endif /* __XML_PARSER_INTERNALS_H__ */ diff --git a/testXPath.c b/testXPath.c index 178f23e2..50453969 100644 --- a/testXPath.c +++ b/testXPath.c @@ -125,7 +125,7 @@ void testXPath(const char *str) { xmlXPathObjectPtr res; xmlXPathContextPtr ctxt; - ctxt = xmlXPathNewContext(document, NULL, NULL); + ctxt = xmlXPathNewContext(document); if (expr) res = xmlXPathEvalExpression(BAD_CAST str, ctxt); else diff --git a/tree.c b/tree.c index 9e622ffe..006defee 100644 --- a/tree.c +++ b/tree.c @@ -395,6 +395,7 @@ xmlNewDoc(const CHAR *version) { cur->standalone = -1; cur->compression = xmlCompressMode; cur->ids = NULL; + cur->refs = NULL; #ifndef XML_WITHOUT_CORBA cur->_private = NULL; cur->vepv = NULL; @@ -425,6 +426,7 @@ xmlFreeDoc(xmlDocPtr cur) { if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset); if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs); if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids); + if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs); memset(cur, -1, sizeof(xmlDoc)); xmlFree(cur); } diff --git a/tree.h b/tree.h index 6d22ac12..bf8a77ed 100644 --- a/tree.h +++ b/tree.h @@ -210,6 +210,17 @@ typedef struct xmlID { } xmlID; typedef xmlID *xmlIDPtr; +/* + * An XML IDREF instance. + */ + +typedef struct xmlRef { + struct xmlRef *next; /* next Ref */ + const CHAR *value; /* The Ref name */ + xmlAttrPtr attr; /* The attribut holding it */ +} xmlRef; +typedef xmlRef *xmlRefPtr; + /* * A node in an XML tree. */ @@ -253,6 +264,7 @@ typedef struct xmlDoc { struct xmlNs *oldNs; /* Global namespace, the old way */ struct xmlNode *root; /* the document tree */ void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ } _xmlDoc; typedef _xmlDoc xmlDoc; typedef xmlDoc *xmlDocPtr; @@ -440,6 +452,12 @@ const CHAR * xmlNodeGetLang (xmlNodePtr cur); void xmlNodeSetLang (xmlNodePtr cur, const CHAR *lang); +/* + * Removing content. + */ +int xmlRemoveProp (xmlAttrPtr attr); /* TODO */ +int xmlRemoveNode (xmlNodePtr node); /* TODO */ + /* * Internal, don't use */ diff --git a/valid.c b/valid.c index 3a107dbe..a6466ff6 100644 --- a/valid.c +++ b/valid.c @@ -1316,7 +1316,7 @@ xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { /************************************************************************ * * - * NOTATIONs * + * IDs * * * ************************************************************************/ /** @@ -1549,6 +1549,228 @@ xmlGetID(xmlDocPtr doc, const CHAR *ID) { return(NULL); } +/************************************************************************ + * * + * Refs * + * * + ************************************************************************/ +/** + * xmlCreateRefTable: + * + * create and initialize an empty ref hash table. + * + * Returns the xmlRefTablePtr just created or NULL in case + * of error. + */ +xmlRefTablePtr +xmlCreateRefTable(void) { + xmlRefTablePtr ret; + + ret = (xmlRefTablePtr) + xmlMalloc(sizeof(xmlRefTable)); + if (ret == NULL) { + fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n", + (long)sizeof(xmlRefTable)); + return(NULL); + } + ret->max_refs = XML_MIN_NOTATION_TABLE; + ret->nb_refs = 0; + ret->table = (xmlRefPtr *) + xmlMalloc(ret->max_refs * sizeof(xmlRefPtr)); + if (ret == NULL) { + fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n", + ret->max_refs * (long)sizeof(xmlRef)); + xmlFree(ret); + return(NULL); + } + return(ret); +} + + +/** + * xmlAddRef: + * @ctxt: the validation context + * @doc: pointer to the document + * @value: the value name + * @attr: the attribute holding the Ref + * + * Register a new ref declaration + * + * Returns NULL if not, othervise the new xmlRefPtr + */ +xmlRefPtr +xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value, + xmlAttrPtr attr) { + xmlRefPtr ret; + xmlRefTablePtr table; + + if (doc == NULL) { + fprintf(stderr, "xmlAddRefDecl: doc == NULL\n"); + return(NULL); + } + if (value == NULL) { + fprintf(stderr, "xmlAddRefDecl: value == NULL\n"); + return(NULL); + } + if (attr == NULL) { + fprintf(stderr, "xmlAddRefDecl: attr == NULL\n"); + return(NULL); + } + + /* + * Create the Ref table if needed. + */ + table = doc->refs; + if (table == NULL) + table = doc->refs = xmlCreateRefTable(); + if (table == NULL) { + fprintf(stderr, "xmlAddRef: Table creation failed!\n"); + return(NULL); + } + + /* + * Grow the table, if needed. + */ + if (table->nb_refs >= table->max_refs) { + /* + * need more refs. + */ + table->max_refs *= 2; + table->table = (xmlRefPtr *) + xmlRealloc(table->table, table->max_refs * + sizeof(xmlRefPtr)); + if (table->table == NULL) { + fprintf(stderr, "xmlAddRef: out of memory\n"); + return(NULL); + } + } + ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef)); + if (ret == NULL) { + fprintf(stderr, "xmlAddRef: out of memory\n"); + return(NULL); + } + table->table[table->nb_refs] = ret; + + /* + * fill the structure. + */ + ret->value = xmlStrdup(value); + ret->attr = attr; + table->nb_refs++; + + return(ret); +} + +/** + * xmlFreeRef: + * @not: A ref + * + * Deallocate the memory used by an ref definition + */ +void +xmlFreeRef(xmlRefPtr ref) { + if (ref == NULL) return; + if (ref->value != NULL) + xmlFree((CHAR *) ref->value); + memset(ref, -1, sizeof(xmlRef)); + xmlFree(ref); +} + +/** + * xmlFreeRefTable: + * @table: An ref table + * + * Deallocate the memory used by an Ref hash table. + */ +void +xmlFreeRefTable(xmlRefTablePtr table) { + int i; + + if (table == NULL) return; + + for (i = 0;i < table->nb_refs;i++) { + xmlFreeRef(table->table[i]); + } + xmlFree(table->table); + xmlFree(table); +} + +/** + * xmlIsRef + * @doc: the document + * @elem: the element carrying the attribute + * @attr: the attribute + * + * Determine whether an attribute is of type Ref. In case we have Dtd(s) + * then this is simple, otherwise we use an heuristic: name Ref (upper + * or lowercase). + * + * Returns 0 or 1 depending on the lookup result + */ +int +xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { + if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { + return(0); + /******************* + if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) && + ((attr->name[1] == 'D') || (attr->name[1] == 'd')) && + (attr->name[2] == 0)) return(1); + *******************/ + } else { + xmlAttributePtr attrDecl; + + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, + attr->name); + + if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF)) + return(1); + } + return(0); +} + +/** + * xmlGetRef: + * @doc: pointer to the document + * @Ref: the Ref value + * + * Search the attribute declaring the given Ref + * + * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref + */ +xmlAttrPtr +xmlGetRef(xmlDocPtr doc, const CHAR *Ref) { + xmlRefPtr cur; + xmlRefTablePtr table; + int i; + + if (doc == NULL) { + fprintf(stderr, "xmlGetRef: doc == NULL\n"); + return(NULL); + } + + if (Ref == NULL) { + fprintf(stderr, "xmlGetRef: Ref == NULL\n"); + return(NULL); + } + + table = doc->refs; + if (table == NULL) + return(NULL); + + /* + * Search the Ref list. + */ + for (i = 0;i < table->nb_refs;i++) { + cur = table->table[i]; + if (!xmlStrcmp(cur->value, Ref)) { + return(cur->attr); + } + } + return(NULL); +} + /************************************************************************ * * * Routines for validity checking * @@ -2165,6 +2387,10 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlAddID(ctxt, doc, value, attr); } + if (attrDecl->type == XML_ATTRIBUTE_IDREF) { + xmlAddRef(ctxt, doc, value, attr); + } + /* Validity Constraint: Notation Attributes */ if (attrDecl->type == XML_ATTRIBUTE_NOTATION) { xmlEnumerationPtr tree = attrDecl->tree; @@ -2610,9 +2836,75 @@ xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { int xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) { + xmlNodePtr child; + xmlAttrPtr attr; + CHAR *value; + int ret = 1; + + /* TODO xmlValidateElement */ + + if (elem == NULL) return(0); CHECK_DTD; - return(1); + ret &= xmlValidateOneElement(ctxt, doc, elem); + attr = elem->properties; + while(attr != NULL) { + value = xmlNodeListGetString(doc, attr->val, 0); + ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value); + if (value != NULL) + free(value); + attr= attr->next; + } + child = elem->childs; + while (child != NULL) { + ret &= xmlValidateElement(ctxt, doc, child); + child = child->next; + } + + return(ret); +} + +/** + * xmlValidateDocumentFinal: + * @ctxt: the validation context + * @doc: a document instance + * + * Does the final step for the document validation once all the + * incremental validation steps have been completed + * + * basically it does the following checks described by the XML Rec + * + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { + int ret = 1, i; + xmlRefTablePtr table; + xmlAttrPtr id; + + if (doc == NULL) { + fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n"); + return(0); + } + + /* + * Get the refs table + */ + table = doc->refs; + if (table != NULL) { + for (i = 0; i < table->nb_refs; i++) { + id = xmlGetID(doc, table->table[i]->value); + if (id == NULL) { + VERROR(ctxt->userData, + "IDREF attribute %s reference an unknown ID '%s'\n", + table->table[i]->attr->name, table->table[i]->value); + ret = 0; + } + } + } + return(ret); } /** @@ -2630,6 +2922,7 @@ xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) { int xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { + /* TODO xmlValidateDtd */ return(1); } @@ -2640,7 +2933,7 @@ xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { * * Try to validate the document instance * - * basically it does the all the checks described by the + * basically it does the all the checks described by the XML Rec * i.e. validates the internal and external subset (if present) * and validate the document tree. * @@ -2649,8 +2942,12 @@ xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { int xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { + int ret; + if (!xmlValidateRoot(ctxt, doc)) return(0); - return(1); + ret = xmlValidateElement(ctxt, doc, doc->root); + ret &= xmlValidateDocumentFinal(ctxt, doc); + return(ret); } diff --git a/valid.h b/valid.h index 37b4f999..22a2c27c 100644 --- a/valid.h +++ b/valid.h @@ -88,6 +88,20 @@ typedef struct xmlIDTable { } xmlIDTable; typedef xmlIDTable *xmlIDTablePtr; +/* + * ALl Refs attributes are stored in a table + * there is one table per document + */ + +#define XML_MIN_REF_TABLE 32 + +typedef struct xmlRefTable { + int nb_refs; /* number of refs stored */ + int max_refs; /* maximum number of refs */ + xmlRefPtr *table; /* the table of refs */ +} xmlRefTable; +typedef xmlRefTable *xmlRefTablePtr; + /* Notation */ xmlNotationPtr xmlAddNotationDecl (xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, @@ -148,6 +162,17 @@ int xmlIsID (xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr); +/* IDREFs */ +xmlRefPtr xmlAddRef (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const CHAR *value, + xmlAttrPtr attr); +xmlRefTablePtr xmlCopyRefTable (xmlRefTablePtr table); +void xmlFreeRefTable (xmlRefTablePtr table); +int xmlIsRef (xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr); + /** * The public function calls related to validity checking */ @@ -181,6 +206,8 @@ int xmlValidateOneAttribute (xmlValidCtxtPtr ctxt, xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value); +int xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, + xmlDocPtr doc); int xmlValidateNotationUse (xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *notationName); diff --git a/xpath.c b/xpath.c index 4ff7da52..a0f6a2a6 100644 --- a/xpath.c +++ b/xpath.c @@ -769,7 +769,7 @@ xmlXPathFreeObject(xmlXPathObjectPtr obj) { * Returns the xmlXPathContext just allocated. */ xmlXPathContextPtr -xmlXPathNewContext(xmlDocPtr doc, void *variables, void *functions) { +xmlXPathNewContext(xmlDocPtr doc) { xmlXPathContextPtr ret; ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); @@ -779,9 +779,25 @@ xmlXPathNewContext(xmlDocPtr doc, void *variables, void *functions) { } memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); ret->doc = doc; - ret->variables = variables; - ret->functions = functions; + + ret->nb_variables = 0; + ret->max_variables = 0; + ret->variables = NULL; + + ret->nb_types = 0; + ret->max_types = 0; + ret->types = NULL; + + ret->nb_funcs = 0; + ret->max_funcs = 0; + ret->funcs = NULL; + + ret->nb_axis = 0; + ret->max_axis = 0; + ret->axis = NULL; + ret->namespaces = NULL; + ret->user = NULL; ret->nsNr = 0; return(ret); } diff --git a/xpath.h b/xpath.h index 64085032..d46c0633 100644 --- a/xpath.h +++ b/xpath.h @@ -14,6 +14,8 @@ #include "tree.h" +typedef struct xmlXPathParserContext *xmlXPathParserContextPtr; + /* * A node-set (an unordered collection of nodes without duplicates) */ @@ -37,6 +39,7 @@ typedef struct xmlNodeSet { #define XPATH_BOOLEAN 2 #define XPATH_NUMBER 3 #define XPATH_STRING 4 +#define XPATH_USERS 5 typedef struct xmlXPathObject { int type; @@ -44,8 +47,66 @@ typedef struct xmlXPathObject { int boolval; double floatval; CHAR *stringval; + void *user; } xmlXPathObject, *xmlXPathObjectPtr; +/* + * A conversion function is associated to a type and used to cast + * the new type to primitive values. + */ +typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type); + +/* + * Extra type: a name and a conversion function. + */ + +typedef struct xmlXPathType { + const CHAR *name; /* the type name */ + xmlXPathConvertFunc func; /* the conversion function */ +} xmlXPathType, *xmlXPathTypePtr; + +/* + * Extra variable: a name and a value. + */ + +typedef struct xmlXPathVariable { + const CHAR *name; /* the variable name */ + xmlXPathObjectPtr value; /* the value */ +} xmlXPathVariable, *xmlXPathVariablePtr; + +/* + * an evaluation function, the parameters are on the context stack + */ + +typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, int nargs); + +/* + * Extra function: a name and a evaluation function. + */ + +typedef struct xmlXPathFunct { + const CHAR *name; /* the function name */ + xmlXPathEvalFunc func; /* the evaluation function */ +} xmlXPathFunc, *xmlXPathFuncPtr; + +/* + * An axis traversal function. To traverse an axis, the engine calls + * the first time with cur == NULL and repeat until the function returns + * NULL indicating the end of the axis traversal. + */ + +typedef xmlXPathObjectPtr (*xmlXPathAxisFunc) (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr cur); + +/* + * Extra axis: a name and an axis function. + */ + +typedef struct xmlXPathAxis { + const CHAR *name; /* the axis name */ + xmlXPathAxisFunc func; /* the search function */ +} xmlXPathAxis, *xmlXPathAxisPtr; + /* * Expression evaluation occurs with respect to a context. * he context consists of: @@ -60,10 +121,27 @@ typedef struct xmlXPathContext { xmlDocPtr doc; /* The current document */ xmlNodePtr node; /* The current node */ xmlNodeSetPtr nodelist; /* The current node list */ - void *variables; /* TODO !!!! */ - void *functions; /* TODO !!!! */ + + int nb_variables; /* number of defined variables */ + int max_variables; /* max number of variables */ + xmlXPathVariablePtr *variables; /* Array of defined variables */ + + int nb_types; /* number of defined types */ + int max_types; /* max number of types */ + xmlXPathTypePtr *types; /* Array of defined types */ + + int nb_funcs; /* number of defined funcs */ + int max_funcs; /* max number of funcs */ + xmlXPathFuncPtr *funcs; /* Array of defined funcs */ + + int nb_axis; /* number of defined axis */ + int max_axis; /* max number of axis */ + xmlXPathAxisPtr *axis; /* Array of defined axis */ + + /* Namespace traversal should be implemented with user */ xmlNsPtr *namespaces; /* The namespaces lookup */ int nsNr; /* the current Namespace index */ + void *user; /* user defined extra info */ } xmlXPathContext, *xmlXPathContextPtr; /* @@ -81,7 +159,7 @@ typedef struct xmlXPathParserContext { int valueNr; /* number of values stacked */ int valueMax; /* max number of values stacked */ xmlXPathObjectPtr *valueTab; /* stack of values */ -} xmlXPathParserContext, *xmlXPathParserContextPtr; +} xmlXPathParserContext; /* * An XPath function @@ -97,9 +175,26 @@ typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs); * * ************************************************************************/ -xmlXPathContextPtr xmlXPathNewContext (xmlDocPtr doc, - void *variables, - void *functions); +/** + * Registering extensions to the expression language + */ +/* TODO */ int xmlXPathRegisterType (xmlXPathContextPtr ctxt, + const CHAR *name, + xmlXPathConvertFunc f); +/* TODO */ int xmlXPathRegisterAxis (xmlXPathContextPtr ctxt, + const CHAR *name, + xmlXPathAxisFunc f); +/* TODO */ int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, + const CHAR *name, + xmlXPathFunction f); +/* TODO */ int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, + const CHAR *name, + xmlXPathObject value); + +/** + * Evaluation functions. + */ +xmlXPathContextPtr xmlXPathNewContext (xmlDocPtr doc); void xmlXPathFreeContext (xmlXPathContextPtr ctxt); xmlXPathObjectPtr xmlXPathEval (const CHAR *str, xmlXPathContextPtr ctxt);