diff options
author | Daniel Veillard <veillard@src.gnome.org> | 2000-10-04 13:33:43 +0000 |
---|---|---|
committer | Daniel Veillard <veillard@src.gnome.org> | 2000-10-04 13:33:43 +0000 |
commit | ac2603066945f8508fc8cb0a78a8f91983c24e59 (patch) | |
tree | 337ee65486a85bff2433e743447735fba295797b | |
parent | 7cfce324d84603dec97d3a6bcafdaec53785e90a (diff) | |
download | libxml2-ac2603066945f8508fc8cb0a78a8f91983c24e59.tar.gz |
More work and fixes on XPath:
- debugXML.c testXPath.c xpath.[ch]: More work on XPath/Xpointer,
incorporated "(TOM)" <ptittom@free.fr> patches rebuilt the XPath
examples with the extra test
Daniel
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | debugXML.c | 38 | ||||
-rw-r--r-- | include/libxml/xpath.h | 16 | ||||
-rw-r--r-- | result/XPath/expr/base | 15 | ||||
-rw-r--r-- | result/XPath/expr/compare | 72 | ||||
-rw-r--r-- | result/XPath/expr/equality | 72 | ||||
-rw-r--r-- | result/XPath/expr/functions | 15 | ||||
-rw-r--r-- | result/XPath/expr/strings | 57 | ||||
-rw-r--r-- | result/XPath/tests/chaptersbase | 37 | ||||
-rw-r--r-- | result/XPath/tests/chaptersprefol | 76 | ||||
-rw-r--r-- | result/XPath/tests/idsimple | 19 | ||||
-rw-r--r-- | result/XPath/tests/simpleabbr | 38 | ||||
-rw-r--r-- | result/XPath/tests/simplebase | 37 | ||||
-rw-r--r-- | result/XPath/tests/usr1check | 7 | ||||
-rw-r--r-- | test/XPath/tests/chaptersprefol | 1 | ||||
-rw-r--r-- | testXPath.c | 29 | ||||
-rw-r--r-- | xpath.c | 796 | ||||
-rw-r--r-- | xpath.h | 16 |
18 files changed, 1226 insertions, 121 deletions
@@ -1,3 +1,9 @@ +Wed Oct 4 15:25:53 CEST 2000 Daniel Veillard <Daniel.Veillard@w3.org> + + * debugXML.c testXPath.c xpath.[ch]: More work on XPath/Xpointer, + incorporated "(TOM)" <ptittom@free.fr> patches rebuilt the XPath + examples with the extra test + Wed Oct 4 14:39:01 CEST 2000 Daniel Veillard <Daniel.Veillard@w3.org> * parser.c xmlIO.c xmlIO.h: fixed bug 26650, and improved @@ -584,6 +584,8 @@ void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) { xmlDebugDumpAttrList(output, node->properties, depth + 1); if (node->type != XML_ENTITY_REF_NODE) { if (node->content != NULL) { + shift[2 * i] = shift[2 * i + 1] = ' ' ; + shift[2 * i + 2] = shift[2 * i + 3] = 0 ; fprintf(output, shift); fprintf(output, "content="); #ifndef XML_USE_BUFFER_CONTENT @@ -1681,6 +1683,18 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, case XPATH_STRING: fprintf(stderr, "%s is a string\n", arg); break; + case XPATH_POINT: + fprintf(stderr, "%s is a point\n", arg); + break; + case XPATH_RANGE: + fprintf(stderr, "%s is a range\n", arg); + break; + case XPATH_LOCATIONSET: + fprintf(stderr, "%s is a range\n", arg); + break; + case XPATH_USERS: + fprintf(stderr, "%s is user-defined\n", arg); + break; } xmlXPathFreeNodeSetList(list); } else { @@ -1719,6 +1733,18 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, case XPATH_STRING: fprintf(stderr, "%s is a string\n", arg); break; + case XPATH_POINT: + fprintf(stderr, "%s is a point\n", arg); + break; + case XPATH_RANGE: + fprintf(stderr, "%s is a range\n", arg); + break; + case XPATH_LOCATIONSET: + fprintf(stderr, "%s is a range\n", arg); + break; + case XPATH_USERS: + fprintf(stderr, "%s is user-defined\n", arg); + break; } xmlXPathFreeNodeSetList(list); } else { @@ -1761,6 +1787,18 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, case XPATH_STRING: fprintf(stderr, "%s is a string\n", arg); break; + case XPATH_POINT: + fprintf(stderr, "%s is a point\n", arg); + break; + case XPATH_RANGE: + fprintf(stderr, "%s is a range\n", arg); + break; + case XPATH_LOCATIONSET: + fprintf(stderr, "%s is a range\n", arg); + break; + case XPATH_USERS: + fprintf(stderr, "%s is user-defined\n", arg); + break; } xmlXPathFreeNodeSetList(list); } else { diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h index 6c5f42eb..631f59f2 100644 --- a/include/libxml/xpath.h +++ b/include/libxml/xpath.h @@ -51,7 +51,10 @@ typedef enum { XPATH_BOOLEAN = 2, XPATH_NUMBER = 3, XPATH_STRING = 4, - XPATH_USERS = 5 + XPATH_POINT = 5, + XPATH_RANGE = 6, + XPATH_LOCATIONSET = 7, + XPATH_USERS = 8 } xmlXPathObjectType; typedef struct _xmlXPathObject xmlXPathObject; @@ -63,6 +66,9 @@ struct _xmlXPathObject { double floatval; xmlChar *stringval; void *user; + int index; + void *user2; + int index2; }; /* @@ -168,6 +174,11 @@ struct _xmlXPathContext { /* extra variables */ int contextSize; /* the context size */ int proximityPosition; /* the proximity position */ + + /* extra stuff for XPointer */ + int xptr; /* it this an XPointer context */ + xmlNodePtr here; /* for here() */ + xmlNodePtr origin; /* for origin() */ }; /* @@ -220,10 +231,13 @@ typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs); /** * Evaluation functions. */ +void xmlXPathInit (void); xmlXPathContextPtr xmlXPathNewContext (xmlDocPtr doc); void xmlXPathFreeContext (xmlXPathContextPtr ctxt); xmlXPathObjectPtr xmlXPathEval (const xmlChar *str, xmlXPathContextPtr ctxt); +xmlXPathObjectPtr xmlXPathEvalXPtrExpr (const xmlChar *str, + xmlXPathContextPtr ctxt); void xmlXPathFreeObject (xmlXPathObjectPtr obj); xmlXPathObjectPtr xmlXPathEvalExpression (const xmlChar *str, xmlXPathContextPtr ctxt); diff --git a/result/XPath/expr/base b/result/XPath/expr/base index 2f1ebda3..35528669 100644 --- a/result/XPath/expr/base +++ b/result/XPath/expr/base @@ -1,5 +1,20 @@ + +======================== +Expression: 1 Object is a number : 1 + +======================== +Expression: 1+2 Object is a number : 3 + +======================== +Expression: 2*3 Object is a number : 6 + +======================== +Expression: 1+2*3+4 Object is a number : 11 + +======================== +Expression: (1+2)*(3+4) Object is a number : 21 diff --git a/result/XPath/expr/compare b/result/XPath/expr/compare index daae1a2e..a0dcdc42 100644 --- a/result/XPath/expr/compare +++ b/result/XPath/expr/compare @@ -1,24 +1,96 @@ + +======================== +Expression: 0<1 Object is a Boolean : true + +======================== +Expression: 0<=1 Object is a Boolean : true + +======================== +Expression: 0>1 Object is a Boolean : false + +======================== +Expression: 0>=1 Object is a Boolean : false + +======================== +Expression: 1<0 Object is a Boolean : false + +======================== +Expression: 1<=0 Object is a Boolean : false + +======================== +Expression: 1>0 Object is a Boolean : true + +======================== +Expression: 1>=0 Object is a Boolean : true + +======================== +Expression: 1<1 Object is a Boolean : false + +======================== +Expression: 1<=1 Object is a Boolean : true + +======================== +Expression: 1>1 Object is a Boolean : false + +======================== +Expression: 1>=1 Object is a Boolean : true + +======================== +Expression: '0'<1 Object is a Boolean : true + +======================== +Expression: '0'<=1 Object is a Boolean : true + +======================== +Expression: '0'>1 Object is a Boolean : false + +======================== +Expression: '0'>=1 Object is a Boolean : false + +======================== +Expression: 0<'1.2' Object is a Boolean : true + +======================== +Expression: 0<='1.2' Object is a Boolean : true + +======================== +Expression: 0>'1.2' Object is a Boolean : false + +======================== +Expression: 0>='1.2' Object is a Boolean : false + +======================== +Expression: false()<1 Object is a Boolean : true + +======================== +Expression: false()<=1 Object is a Boolean : true + +======================== +Expression: 0>true() Object is a Boolean : false + +======================== +Expression: 0>=true() Object is a Boolean : false diff --git a/result/XPath/expr/equality b/result/XPath/expr/equality index 92d6d1c7..594b101e 100644 --- a/result/XPath/expr/equality +++ b/result/XPath/expr/equality @@ -1,24 +1,96 @@ + +======================== +Expression: 1=1 Object is a Boolean : true + +======================== +Expression: 1!=1 Object is a Boolean : false + +======================== +Expression: 1=0 Object is a Boolean : false + +======================== +Expression: 1!=0 Object is a Boolean : true + +======================== +Expression: true()=true() Object is a Boolean : true + +======================== +Expression: true()!=true() Object is a Boolean : false + +======================== +Expression: true()=false() Object is a Boolean : false + +======================== +Expression: false()!=true() Object is a Boolean : true + +======================== +Expression: 'test'='test' Object is a Boolean : true + +======================== +Expression: 'test'!='test' Object is a Boolean : false + +======================== +Expression: 'test2'='test' Object is a Boolean : false + +======================== +Expression: 'test2'!='test' Object is a Boolean : true + +======================== +Expression: false()=0 Object is a Boolean : true + +======================== +Expression: false()!=0 Object is a Boolean : false + +======================== +Expression: false()=1 Object is a Boolean : false + +======================== +Expression: false()!=1 Object is a Boolean : true + +======================== +Expression: 0=true() Object is a Boolean : false + +======================== +Expression: 0!=true() Object is a Boolean : true + +======================== +Expression: 1=true() Object is a Boolean : true + +======================== +Expression: 1!=true() Object is a Boolean : false + +======================== +Expression: true()='test' Object is a Boolean : true + +======================== +Expression: false()='test' Object is a Boolean : false + +======================== +Expression: 'test'!=true() Object is a Boolean : false + +======================== +Expression: 'test'!=false() Object is a Boolean : true diff --git a/result/XPath/expr/functions b/result/XPath/expr/functions index 3e40603a..29f44f7d 100644 --- a/result/XPath/expr/functions +++ b/result/XPath/expr/functions @@ -1,5 +1,20 @@ + +======================== +Expression: true() Object is a Boolean : true + +======================== +Expression: false() Object is a Boolean : false + +======================== +Expression: number("1.5") Object is a number : 1.5 + +======================== +Expression: concat("titi",'toto') Object is a string : tititoto + +======================== +Expression: concat("titi",'toto',"tata","last") Object is a string : tititototatalast diff --git a/result/XPath/expr/strings b/result/XPath/expr/strings index e405715c..85a35c90 100644 --- a/result/XPath/expr/strings +++ b/result/XPath/expr/strings @@ -1,19 +1,76 @@ + +======================== +Expression: string(5) Object is a string : 5 + +======================== +Expression: string(0.5) Object is a string : 0.5 + +======================== +Expression: string(-0.5) Object is a string : -0.5 + +======================== +Expression: string(true()) Object is a string : true + +======================== +Expression: string(false()) Object is a string : false + +======================== +Expression: concat("titi","toto") Object is a string : tititoto + +======================== +Expression: concat("titi","toto","tata") Object is a string : tititototata + +======================== +Expression: starts-with("tititoto","titi") Object is a Boolean : true + +======================== +Expression: starts-with("tititoto","to") Object is a Boolean : false + +======================== +Expression: contains("tititototata","titi") Object is a Boolean : true + +======================== +Expression: contains("tititototata","toto") Object is a Boolean : true + +======================== +Expression: contains("tititototata","tata") Object is a Boolean : true + +======================== +Expression: contains("tititototata","tita") Object is a Boolean : false + +======================== +Expression: substring("12345",2,3) Object is a string : 234 + +======================== +Expression: substring("12345",2) Object is a string : 2345 + +======================== +Expression: substring("12345",1.5,2.6) Object is a string : 234 + +======================== +Expression: substring("12345",0,3) Object is a string : 12 + +======================== +Expression: string-length("") Object is a number : 0 + +======================== +Expression: string-length("titi") Object is a number : 4 diff --git a/result/XPath/tests/chaptersbase b/result/XPath/tests/chaptersbase index 18895355..4b5b9cc6 100644 --- a/result/XPath/tests/chaptersbase +++ b/result/XPath/tests/chaptersbase @@ -1,24 +1,36 @@ + +======================== +Expression: /child::EXAMPLE Object is a Node Set : Set contains 1 nodes: 1 ELEMENT EXAMPLE ATTRIBUTE prop1 TEXT - content=gnome is great + content=gnome is great ATTRIBUTE prop2 TEXT - content=& linux too + content=& linux too + +======================== +Expression: /child::* Object is a Node Set : Set contains 1 nodes: 1 ELEMENT EXAMPLE ATTRIBUTE prop1 TEXT - content=gnome is great + content=gnome is great ATTRIBUTE prop2 TEXT - content=& linux too + content=& linux too + +======================== +Expression: /child::EXAMPLE/child::head Object is a Node Set : Set contains 1 nodes: 1 ELEMENT head + +======================== +Expression: /child::EXAMPLE/child::* Object is a Node Set : Set contains 6 nodes: 1 ELEMENT head @@ -27,16 +39,28 @@ Set contains 6 nodes: 4 ELEMENT chapter 5 ELEMENT chapter 6 ELEMENT chapter + +======================== +Expression: /child::EXAMPLE/child::head/child::title Object is a Node Set : Set contains 1 nodes: 1 ELEMENT title + +======================== +Expression: /child::EXAMPLE/child::head/child::title/child::text() Object is a Node Set : Set contains 1 nodes: 1 TEXT - content=Welcome to Gnome + content=Welcome to Gnome + +======================== +Expression: /child::EXAMPLE/child::head/node() Object is a Node Set : Set contains 1 nodes: 1 ELEMENT title + +======================== +Expression: /descendant::title Object is a Node Set : Set contains 6 nodes: 1 ELEMENT title @@ -45,6 +69,9 @@ Set contains 6 nodes: 4 ELEMENT title 5 ELEMENT title 6 ELEMENT title + +======================== +Expression: /descendant::p/ancestor::chapter Object is a Node Set : Set contains 5 nodes: 1 ELEMENT chapter diff --git a/result/XPath/tests/chaptersprefol b/result/XPath/tests/chaptersprefol new file mode 100644 index 00000000..5c33f2dd --- /dev/null +++ b/result/XPath/tests/chaptersprefol @@ -0,0 +1,76 @@ + +======================== +Expression: /following::* +Object is a Node Set : +Set contains 0 nodes: + +======================== +Expression: /preceding::* +Object is a Node Set : +Set contains 0 nodes: + +======================== +Expression: /child::EXAMPLE/preceding::* +Object is a Node Set : +Set contains 0 nodes: + +======================== +Expression: /child::EXAMPLE/following::* +Object is a Node Set : +Set contains 0 nodes: + +======================== +Expression: /child::EXAMPLE/child::chapter[3]/preceding::* +Object is a Node Set : +Set contains 10 nodes: +1 ELEMENT p +2 ELEMENT title +3 ELEMENT chapter +4 ELEMENT p +5 ELEMENT image + ATTRIBUTE href + TEXT + content=linus.gif +6 ELEMENT p +7 ELEMENT title +8 ELEMENT chapter +9 ELEMENT title +10 ELEMENT head + +======================== +Expression: /child::EXAMPLE/child::chapter[3]/following::* +Object is a Node Set : +Set contains 6 nodes: +1 ELEMENT chapter +2 ELEMENT title +3 ELEMENT p +4 ELEMENT chapter +5 ELEMENT title +6 ELEMENT p + +======================== +Expression: /child::EXAMPLE/child::chapter[1]/image/preceding::* +Object is a Node Set : +Set contains 4 nodes: +1 ELEMENT p +2 ELEMENT title +3 ELEMENT title +4 ELEMENT head + +======================== +Expression: /child::EXAMPLE/child::chapter[1]/image/following::* +Object is a Node Set : +Set contains 13 nodes: +1 ELEMENT p +2 ELEMENT chapter +3 ELEMENT title +4 ELEMENT p +5 ELEMENT chapter +6 ELEMENT title +7 ELEMENT p +8 ELEMENT chapter +9 ELEMENT title +10 ELEMENT p +11 ELEMENT chapter +12 ELEMENT title +13 ELEMENT p diff --git a/result/XPath/tests/idsimple b/result/XPath/tests/idsimple index 3d2e9e29..3d158413 100644 --- a/result/XPath/tests/idsimple +++ b/result/XPath/tests/idsimple @@ -1,24 +1,33 @@ + +======================== +Expression: //*[@id="root"] Object is a Node Set : Set contains 1 nodes: 1 ELEMENT EXAMPLE ATTRIBUTE id TEXT - content=root + content=root ATTRIBUTE prop1 TEXT - content=gnome is great + content=gnome is great ATTRIBUTE prop2 TEXT - content=& linux too + content=& linux too + +======================== +Expression: //*[@id="chapter2"] Object is a Node Set : Set contains 1 nodes: 1 ELEMENT chapter ATTRIBUTE id TEXT - content=chapter2 + content=chapter2 + +======================== +Expression: //*[@id="chapter5"] Object is a Node Set : Set contains 1 nodes: 1 ELEMENT chapter ATTRIBUTE id TEXT - content=chapter5 + content=chapter5 diff --git a/result/XPath/tests/simpleabbr b/result/XPath/tests/simpleabbr index 9e3fcd3f..188a719a 100644 --- a/result/XPath/tests/simpleabbr +++ b/result/XPath/tests/simpleabbr @@ -1,39 +1,63 @@ + +======================== +Expression: /EXAMPLE Object is a Node Set : Set contains 1 nodes: 1 ELEMENT EXAMPLE ATTRIBUTE prop1 TEXT - content=gnome is great + content=gnome is great ATTRIBUTE prop2 TEXT - content=& linux too + content=& linux too + +======================== +Expression: /EXAMPLE/head Object is a Node Set : Set contains 1 nodes: 1 ELEMENT head + +======================== +Expression: /EXAMPLE/chapter[1] Object is a Node Set : Set contains 1 nodes: 1 ELEMENT chapter + +======================== +Expression: //p Object is a Node Set : Set contains 2 nodes: 1 ELEMENT p 2 ELEMENT p + +======================== +Expression: //chapter/image Object is a Node Set : Set contains 1 nodes: 1 ELEMENT image ATTRIBUTE href TEXT - content=linus.gif + content=linus.gif + +======================== +Expression: //p/text() Object is a Node Set : Set contains 2 nodes: 1 TEXT - content=bla bla bla ... + content=bla bla bla ... 2 TEXT - content=... + content=... + +======================== +Expression: //p/text()[position()=1] Object is a Node Set : Set contains 1 nodes: 1 TEXT - content=bla bla bla ... + content=bla bla bla ... + +======================== +Expression: //p/text()[position()=last()] Object is a Node Set : Set contains 1 nodes: 1 TEXT - content=... + content=... diff --git a/result/XPath/tests/simplebase b/result/XPath/tests/simplebase index db968d8d..2e9687c8 100644 --- a/result/XPath/tests/simplebase +++ b/result/XPath/tests/simplebase @@ -1,42 +1,69 @@ + +======================== +Expression: /child::* Object is a Node Set : Set contains 1 nodes: 1 ELEMENT EXAMPLE ATTRIBUTE prop1 TEXT - content=gnome is great + content=gnome is great ATTRIBUTE prop2 TEXT - content=& linux too + content=& linux too + +======================== +Expression: /child::EXAMPLE Object is a Node Set : Set contains 1 nodes: 1 ELEMENT EXAMPLE ATTRIBUTE prop1 TEXT - content=gnome is great + content=gnome is great ATTRIBUTE prop2 TEXT - content=& linux too + content=& linux too + +======================== +Expression: /child::EXAMPLE/child::head Object is a Node Set : Set contains 1 nodes: 1 ELEMENT head + +======================== +Expression: /child::EXAMPLE/child::* Object is a Node Set : Set contains 2 nodes: 1 ELEMENT head 2 ELEMENT chapter + +======================== +Expression: /child::EXAMPLE/child::head/child::title Object is a Node Set : Set contains 1 nodes: 1 ELEMENT title + +======================== +Expression: /child::EXAMPLE/child::head/child::title/child::text() Object is a Node Set : Set contains 1 nodes: 1 TEXT - content=Welcome to Gnome + content=Welcome to Gnome + +======================== +Expression: /child::EXAMPLE/child::head/node() Object is a Node Set : Set contains 1 nodes: 1 ELEMENT title + +======================== +Expression: /descendant::title Object is a Node Set : Set contains 2 nodes: 1 ELEMENT title 2 ELEMENT title + +======================== +Expression: /descendant::p/ancestor::chapter Object is a Node Set : Set contains 1 nodes: 1 ELEMENT chapter diff --git a/result/XPath/tests/usr1check b/result/XPath/tests/usr1check index 989b79fe..f1f2faae 100644 --- a/result/XPath/tests/usr1check +++ b/result/XPath/tests/usr1check @@ -1,9 +1,12 @@ + +======================== +Expression: //ITEM[1] Object is a Node Set : Set contains 1 nodes: 1 ELEMENT ITEM ATTRIBUTE monto TEXT - content=50.12 + content=50.12 ATTRIBUTE divisa TEXT - content=DOL + content=DOL diff --git a/test/XPath/tests/chaptersprefol b/test/XPath/tests/chaptersprefol new file mode 100644 index 00000000..e95995b8 --- /dev/null +++ b/test/XPath/tests/chaptersprefol @@ -0,0 +1 @@ +/following::* /preceding::* /child::EXAMPLE/preceding::* /child::EXAMPLE/following::* /child::EXAMPLE/child::chapter[3]/preceding::* /child::EXAMPLE/child::chapter[3]/following::* /child::EXAMPLE/child::chapter[1]/image/preceding::* /child::EXAMPLE/child::chapter[1]/image/following::* diff --git a/testXPath.c b/testXPath.c index 49df1c45..d8c24ca3 100644 --- a/testXPath.c +++ b/testXPath.c @@ -41,7 +41,10 @@ #include <libxml/debugXML.h> #include <libxml/xmlmemory.h> #include <libxml/parserInternals.h> - +#if defined(LIBXML_XPTR_ENABLED) +#include <libxml/xpointer.h> +static int xptr = 0; +#endif static int debug = 0; static int valid = 0; static int expr = 0; @@ -138,11 +141,20 @@ void testXPath(const char *str) { xmlXPathObjectPtr res; xmlXPathContextPtr ctxt; - ctxt = xmlXPathNewContext(document); - if (expr) - res = xmlXPathEvalExpression(BAD_CAST str, ctxt); - else - res = xmlXPathEval(BAD_CAST str, ctxt); +#if defined(LIBXML_XPTR_ENABLED) + if (xptr) { + ctxt = xmlXPtrNewContext(document, NULL, NULL); + res = xmlXPtrEval(BAD_CAST str, ctxt); + } else { +#endif + ctxt = xmlXPathNewContext(document); + if (expr) + res = xmlXPathEvalExpression(BAD_CAST str, ctxt); + else + res = xmlXPathEval(BAD_CAST str, ctxt); +#if defined(LIBXML_XPTR_ENABLED) + } +#endif xmlXPAthDebugDumpObject(stdout, res); xmlXPathFreeObject(res); xmlXPathFreeContext(ctxt); @@ -158,6 +170,7 @@ void testXPathFile(const char *filename) { return; } while (fscanf(input, "%s", expr) != EOF) { + printf("\n========================\nExpression: %s\n", expr) ; testXPath(expr); } @@ -171,6 +184,10 @@ int main(int argc, char **argv) { char *filename = NULL; for (i = 1; i < argc ; i++) { +#if defined(LIBXML_XPTR_ENABLED) + if ((!strcmp(argv[i], "-xptr")) || (!strcmp(argv[i], "--xptr"))) + xptr++; +#endif if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug"))) debug++; if ((!strcmp(argv[i], "-valid")) || (!strcmp(argv[i], "--valid"))) @@ -1,7 +1,7 @@ /* * xpath.c: XML Path Language implementation * XPath is a language for addressing parts of an XML document, - * designed to be used by both XSLT and XPointer. + * designed to be used by both XSLT and XPtr. * * Reference: W3C Working Draft internal 5 July 1999 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html @@ -49,6 +49,9 @@ #include <libxml/valid.h> #include <libxml/xpath.h> #include <libxml/parserInternals.h> +#ifdef LIBXML_XPTR_ENABLED +#include <libxml/xpointer.h> +#endif /* #define DEBUG */ /* #define DEBUG_STEP */ @@ -792,6 +795,507 @@ xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { xmlFree(obj); } +#ifdef LIBXML_XPTR_ENABLED +/** + * xmlXPathNewPoint: + * @node: the xmlNodePtr + * @index: the index within the node + * + * Create a new xmlXPathObjectPtr of type point + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewPoint(xmlNodePtr node, int index) { + xmlXPathObjectPtr ret; + + if (node == NULL) + return(NULL); + if (index < 0) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewPoint: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_POINT; + ret->user = (void *) node; + ret->index = index; + return(ret); +} + +/** + * xmlXPathNewRangePoints: + * @start: the starting point + * @end: the ending point + * + * Create a new xmlXPathObjectPtr of type range using 2 Points + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + if (start->type != XPATH_POINT) + return(NULL); + if (end->type != XPATH_POINT) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewRangePoints: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start->user; + ret->index = start->index; + ret->user2 = end->user; + ret->index2 = end->index; + return(ret); +} + +/** + * xmlXPathNewRangePointNode: + * @start: the starting point + * @end: the ending node + * + * Create a new xmlXPathObjectPtr of type range from a point to a node + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + if (start->type != XPATH_POINT) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewRangePointNode: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start->user; + ret->index = start->index; + ret->user2 = end; + ret->index2 = -1; + return(ret); +} + +/** + * xmlXPathNewRangeNodePoint: + * @start: the starting node + * @end: the ending point + * + * Create a new xmlXPathObjectPtr of type range from a node to a point + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + if (start->type != XPATH_POINT) + return(NULL); + if (end->type != XPATH_POINT) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewRangeNodePoint: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start; + ret->index = -1; + ret->user2 = end->user; + ret->index2 = end->index; + return(ret); +} + +/** + * xmlXPathNewRangeNodes: + * @start: the starting node + * @end: the ending node + * + * Create a new xmlXPathObjectPtr of type range using 2 nodes + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewRangeNodes(xmlNodePtr start, xmlNodePtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewRangeNodes: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start; + ret->index = -1; + ret->user2 = end; + ret->index2 = -1; + return(ret); +} + +/** + * xmlXPathNewRangeNodeObject: + * @start: the starting node + * @end: the ending object + * + * Create a new xmlXPathObjectPtr of type range from a not to an object + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + switch (end->type) { + case XPATH_POINT: + break; + case XPATH_NODESET: + /* + * Empty set ... + */ + if (end->nodesetval->nodeNr <= 0) + return(NULL); + break; + default: + TODO + return(NULL); + } + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewRangeNodeObject: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start; + ret->index = -1; + switch (end->type) { + case XPATH_POINT: + ret->user2 = end->user; + ret->index2 = end->index; + case XPATH_NODESET: { + ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - -1]; + ret->index2 = -1; + break; + } + default: + STRANGE + return(NULL); + } + ret->user2 = end; + ret->index2 = -1; + return(ret); +} + +#define XML_RANGESET_DEFAULT 10 + +/** + * xmlXPathRangeSetCreate: + * @val: an initial xmlXPathObjectPtr, or NULL + * + * Create a new xmlRangeSetPtr of type double and of value @val + * + * Returns the newly created object. + */ +xmlRangeSetPtr +xmlXPathRangeSetCreate(xmlXPathObjectPtr val) { + xmlRangeSetPtr ret; + + ret = (xmlRangeSetPtr) xmlMalloc(sizeof(xmlRangeSet)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewRangeSet: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlRangeSet)); + if (val != NULL) { + ret->rangeTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * + sizeof(xmlXPathObjectPtr)); + if (ret->rangeTab == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewRangeSet: out of memory\n"); + return(NULL); + } + memset(ret->rangeTab, 0 , + XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); + ret->rangeMax = XML_RANGESET_DEFAULT; + ret->rangeTab[ret->rangeNr++] = val; + } + return(ret); +} + +/** + * xmlXPathRangeSetAdd: + * @cur: the initial range set + * @val: a new xmlXPathObjectPtr + * + * add a new xmlXPathObjectPtr ot an existing RangeSet + */ +void +xmlXPathRangeSetAdd(xmlRangeSetPtr cur, xmlXPathObjectPtr val) { + int i; + + if (val == NULL) return; + + /* + * check against doublons + */ + for (i = 0;i < cur->rangeNr;i++) + if (cur->rangeTab[i] == val) return; + + /* + * grow the rangeTab if needed + */ + if (cur->rangeMax == 0) { + cur->rangeTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * + sizeof(xmlXPathObjectPtr)); + if (cur->rangeTab == NULL) { + fprintf(xmlXPathDebug, "xmlXPathRangeSetAdd: out of memory\n"); + return; + } + memset(cur->rangeTab, 0 , + XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); + cur->rangeMax = XML_RANGESET_DEFAULT; + } else if (cur->rangeNr == cur->rangeMax) { + xmlXPathObjectPtr *temp; + + cur->rangeMax *= 2; + temp = (xmlXPathObjectPtr *) xmlRealloc(cur->rangeTab, cur->rangeMax * + sizeof(xmlXPathObjectPtr)); + if (temp == NULL) { + fprintf(xmlXPathDebug, "xmlXPathRangeSetAdd: out of memory\n"); + return; + } + cur->rangeTab = temp; + } + cur->rangeTab[cur->rangeNr++] = val; +} + +/** + * xmlXPathRangeSetMerge: + * @val1: the first RangeSet + * @val2: the second RangeSet + * + * Merges two rangesets, all ranges from @val2 are added to @val1 + * + * Returns val1 once extended or NULL in case of error. + */ +xmlRangeSetPtr +xmlXPathRangeSetMerge(xmlRangeSetPtr val1, xmlRangeSetPtr val2) { + int i; + + if (val1 == NULL) return(NULL); + if (val2 == NULL) return(val1); + + /* + * !!!!! this can be optimized a lot, knowing that both + * val1 and val2 already have unicity of their values. + */ + + for (i = 0;i < val2->rangeNr;i++) + xmlXPathRangeSetAdd(val1, val2->rangeTab[i]); + + return(val1); +} + +/** + * xmlXPathRangeSetDel: + * @cur: the initial range set + * @val: an xmlXPathObjectPtr + * + * Removes an xmlXPathObjectPtr from an existing RangeSet + */ +void +xmlXPathRangeSetDel(xmlRangeSetPtr cur, xmlXPathObjectPtr val) { + int i; + + if (cur == NULL) return; + if (val == NULL) return; + + /* + * check against doublons + */ + for (i = 0;i < cur->rangeNr;i++) + if (cur->rangeTab[i] == val) break; + + if (i >= cur->rangeNr) { +#ifdef DEBUG + fprintf(xmlXPathDebug, + "xmlXPathRangeSetDel: Range %s wasn't found in RangeList\n", + val->name); +#endif + return; + } + cur->rangeNr--; + for (;i < cur->rangeNr;i++) + cur->rangeTab[i] = cur->rangeTab[i + 1]; + cur->rangeTab[cur->rangeNr] = NULL; +} + +/** + * xmlXPathRangeSetRemove: + * @cur: the initial range set + * @val: the index to remove + * + * Removes an entry from an existing RangeSet list. + */ +void +xmlXPathRangeSetRemove(xmlRangeSetPtr cur, int val) { + if (cur == NULL) return; + if (val >= cur->rangeNr) return; + cur->rangeNr--; + for (;val < cur->rangeNr;val++) + cur->rangeTab[val] = cur->rangeTab[val + 1]; + cur->rangeTab[cur->rangeNr] = NULL; +} + +/** + * xmlXPathFreeRangeSet: + * @obj: the xmlRangeSetPtr to free + * + * Free the RangeSet compound (not the actual ranges !). + */ +void +xmlXPathFreeRangeSet(xmlRangeSetPtr obj) { + if (obj == NULL) return; + if (obj->rangeTab != NULL) { +#ifdef DEBUG + memset(obj->rangeTab, 0xB , + (size_t) sizeof(xmlXPathObjectPtr) * obj->rangeMax); +#endif + xmlFree(obj->rangeTab); + } +#ifdef DEBUG + memset(obj, 0xB , (size_t) sizeof(xmlRangeSet)); +#endif + xmlFree(obj); +} + +#if defined(DEBUG) || defined(DEBUG_STEP) +/** + * xmlXPathDebugRangeSet: + * @output: a FILE * for the output + * @obj: the xmlRangeSetPtr to free + * + * Quick display of a RangeSet + */ +void +xmlXPathDebugRangeSet(FILE *output, xmlRangeSetPtr obj) { + int i; + + if (output == NULL) output = xmlXPathDebug; + if (obj == NULL) { + fprintf(output, "RangeSet == NULL !\n"); + return; + } + if (obj->rangeNr == 0) { + fprintf(output, "RangeSet is empty\n"); + return; + } + if (obj->rangeTab == NULL) { + fprintf(output, " rangeTab == NULL !\n"); + return; + } + for (i = 0; i < obj->rangeNr; i++) { + if (obj->rangeTab[i] == NULL) { + fprintf(output, " NULL !\n"); + return; + } + if ((obj->rangeTab[i]->type == XML_DOCUMENT_NODE) || + (obj->rangeTab[i]->type == XML_HTML_DOCUMENT_NODE)) + fprintf(output, " /"); + else if (obj->rangeTab[i]->name == NULL) + fprintf(output, " noname!"); + else fprintf(output, " %s", obj->rangeTab[i]->name); + } + fprintf(output, "\n"); +} +#endif + +/** + * xmlXPathNewRangeSetNodes: + * @start: the NodePtr value + * @end: the NodePtr value + * + * Create a new xmlXPathObjectPtr of type RangeSet and initialize + * it with the single range made of the two nodes @start and @end + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewRangeSetNodes(xmlNodePtr start, xmlNodePtr end) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathNewRangeSet: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_LOCATIONSET; + ret->user = xmlXPathRangeSetCreate(xmlXPathNewRangeNodes(start, end)); + return(ret); +} + +/** + * xmlXPathWrapRangeSet: + * @val: the RangeSet value + * + * Wrap the RangeSet @val in a new xmlXPathObjectPtr + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathWrapRangeSet(xmlRangeSetPtr val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathWrapRangeSet: out of memory\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_LOCATIONSET; + ret->user = (void *) val; + return(ret); +} + +#endif /* LIBXML_XPTR_ENABLED */ + /** * xmlXPathFreeObject: * @obj: the object to free @@ -801,10 +1305,14 @@ xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { void xmlXPathFreeObject(xmlXPathObjectPtr obj) { if (obj == NULL) return; - if (obj->nodesetval != NULL) - xmlXPathFreeNodeSet(obj->nodesetval); - if (obj->stringval != NULL) - xmlFree(obj->stringval); + if (obj->type == XPATH_NODESET) { + if (obj->nodesetval != NULL) + xmlXPathFreeNodeSet(obj->nodesetval); + } else if (obj->type == XPATH_STRING) { + if (obj->stringval != NULL) + xmlFree(obj->stringval); + } + #ifdef DEBUG memset(obj, 0xB , (size_t) sizeof(xmlXPathObject)); #endif @@ -1153,6 +1661,9 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval); break; case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: TODO break; } @@ -1190,6 +1701,9 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { ret = (arg1->boolval == ret); break; case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: TODO break; } @@ -1218,6 +1732,9 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { ret = (arg1->floatval == arg2->floatval); break; case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: TODO break; } @@ -1249,11 +1766,17 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { ret = (arg1->floatval == arg2->floatval); break; case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: TODO break; } break; case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: TODO break; } @@ -1852,25 +2375,29 @@ xmlNodePtr xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { if (cur != NULL && cur->children != NULL) return cur->children ; - if (cur == NULL) - if ((cur = ctxt->context->node) == NULL) return(NULL) ; + if (cur == NULL) cur = ctxt->context->node; + if (cur == NULL) return(NULL) ; /* ERROR */ + if (cur->next != NULL) return(cur->next) ; do { cur = cur->parent; if (cur == NULL) return(NULL); - if (cur == ctxt->context->doc->children) return(NULL); - if (cur->next != NULL) { - cur = cur->next; - return(cur); - } + if (cur == ctxt->context->doc->children) return(NULL); /* !!!!!?!? */ + if (cur->next != NULL) return(cur->next); } while (cur != NULL); return(cur); } /* + * xmlXPathIsAncestor: + * @ancestor: the ancestor node + * @node: the current node + * + * Check that @ancestor is a @node's ancestor + * * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. */ static int -isAncestor(xmlNodePtr ancestor, xmlNodePtr node) { +xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { xmlNodePtr tmp ; if (ancestor == NULL || node == NULL) return 0 ; for (tmp = node ; tmp->parent != NULL ; tmp = tmp->parent) { @@ -1907,80 +2434,9 @@ xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { cur = cur->parent; if (cur == NULL) return(NULL); if (cur == ctxt->context->doc->children) return(NULL); - } while (isAncestor(cur, ctxt->context->node)); - return(cur); -} - -#if 0 -/* OLD VERSION, I was told they were broken ! */ -/** - * xmlXPathNextFollowing: - * @ctxt: the XPath Parser context - * @cur: the current node in the traversal - * - * Traversal function for the "following" direction - * The following axis contains all nodes in the same document as the context - * node that are after the context node in document order, excluding any - * descendants and excluding attribute nodes and namespace nodes; the nodes - * are ordered in document order - * - * Returns the next element following that axis - */ -xmlNodePtr -xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if (cur == (xmlNodePtr) ctxt->context->doc) - return(NULL); - if (cur == NULL) - return(ctxt->context->node->next);; /* !!!!!!!!! */ - if (cur->children != NULL) return(cur->children); - if (cur->next != NULL) return(cur->next); - - do { - cur = cur->parent; - if (cur == NULL) return(NULL); - if (cur == ctxt->context->doc->children) return(NULL); - if (cur->next != NULL) { - cur = cur->next; - return(cur); - } - } while (cur != NULL); - return(cur); -} - -/** - * xmlXPathNextPreceding: - * @ctxt: the XPath Parser context - * @cur: the current node in the traversal - * - * Traversal function for the "preceding" direction - * the preceding axis contains all nodes in the same document as the context - * node that are before the context node in document order, excluding any - * ancestors and excluding attribute nodes and namespace nodes; the nodes are - * ordered in reverse document order - * - * Returns the next element following that axis - */ -xmlNodePtr -xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if (cur == (xmlNodePtr) ctxt->context->doc) - return(NULL); - if (cur == NULL) - return(ctxt->context->node->prev); /* !!!!!!!!! */ - if (cur->last != NULL) return(cur->last); - if (cur->prev != NULL) return(cur->prev); - - do { - cur = cur->parent; - if (cur == NULL) return(NULL); - if (cur == ctxt->context->doc->children) return(NULL); - if (cur->prev != NULL) { - cur = cur->prev; - return(cur); - } - } while (cur != NULL); + } while (xmlXPathIsAncestor(cur, ctxt->context->node)); return(cur); } -#endif /** * xmlXPathNextNamespace: @@ -2653,6 +3109,9 @@ xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { return; } case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: TODO valuePush(ctxt, xmlXPathNewCString("")); break; @@ -3242,6 +3701,9 @@ xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { valuePush(ctxt, cur); return; case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: TODO valuePush(ctxt, xmlXPathNewFloat(0.0)); break; @@ -4675,10 +5137,17 @@ search_nodes: * xmlXPathEvalStep: * @ctxt: the XPath Parser context * - * [4] Step ::= Basis Predicate* + * TODO [4] was changed between the WD and the REC + * + * [4] Step ::= AxisSpecifier NodeTest Predicate* * | AbbreviatedStep - * [12] AbbreviatedStep ::= '.' - * | '..' + * [12] AbbreviatedStep ::= '.' | '..' + * + * Modified for XPtr range support as: + * + * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* + * | AbbreviatedStep + * | 'range-to' '(' Expr ')' Predicate* * * Evaluate one step in a Location Path * A location step of . is short for self::node(). This is @@ -4704,7 +5173,99 @@ xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) { NEXT; SKIP_BLANKS; } else { - xmlXPathEvalBasis(ctxt); +#ifdef LIBXML_XPTR_ENABLED + if ((CUR == 'r') && (NXT(1) == 'a') && (NXT(2) == 'n') && + (NXT(3) == 'g') && (NXT(4) == 'e') && (NXT(5) == '-') && + (NXT(6) == 't') && (NXT(7) == 'o')) { + xmlXPathObjectPtr range; + const xmlChar *cur; + xmlXPathObjectPtr res, obj; + xmlXPathObjectPtr tmp; + xmlRangeSetPtr newset = NULL; + xmlNodeSetPtr oldset; + int i; + + CHECK_TYPE(XPATH_NODESET); + obj = valuePop(ctxt); + oldset = obj->nodesetval; + ctxt->context->node = NULL; + + SKIP(8); + SKIP_BLANKS; + if (CUR != '(') { + XP_ERROR(XPATH_EXPR_ERROR); + } + NEXT; + SKIP_BLANKS; + + /* + * Save the expression pointer since we will have to evaluate + * it multiple times. Initialize the new set. + */ + cur = ctxt->cur; + newset = xmlXPathRangeSetCreate(NULL); + + for (i = 0; i < oldset->nodeNr; i++) { + ctxt->cur = cur; + + /* + * Run the evaluation with a node list made of a single item + * in the nodeset. + */ + ctxt->context->node = oldset->nodeTab[i]; + tmp = xmlXPathNewNodeSet(ctxt->context->node); + valuePush(ctxt, tmp); + + xmlXPathEvalExpr(ctxt); + CHECK_ERROR; + + /* + * The result of the evaluation need to be tested to + * decided whether the filter succeeded or not + */ + res = valuePop(ctxt); + range = xmlXPathNewRangeNodeObject(oldset->nodeTab[0], res); + if (range != NULL) { + xmlXPathRangeSetAdd(newset, range); + } + + /* + * Cleanup + */ + if (res != NULL) + xmlXPathFreeObject(res); + if (ctxt->value == tmp) { + res = valuePop(ctxt); + xmlXPathFreeObject(res); + } + + ctxt->context->node = NULL; + } + + /* + * The result is used as the new evaluation set. + */ + xmlXPathFreeObject(obj); + ctxt->context->node = NULL; + ctxt->context->contextSize = -1; + ctxt->context->proximityPosition = -1; + valuePush(ctxt, xmlXPathWrapRangeSet(newset)); + + SKIP_BLANKS; + if (CUR != ')') { + XP_ERROR(XPATH_EXPR_ERROR); + } + NEXT; + SKIP_BLANKS; + } else +#endif + { + /* + * TODO cleanup productions/procedures + * Basis is no more an XPath production ! + */ + xmlXPathEvalBasis(ctxt); + } SKIP_BLANKS; while (CUR == '[') { xmlXPathEvalPredicate(ctxt); @@ -4854,6 +5415,63 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { } /** + * xmlXPathEvalXPtrExpr: + * @str: the XPointer XPtrExpr expression + * @ctx: the XPointer context + * + * Evaluate the location set corresponding to this expression. + * + * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL. + * the caller has to free the object. + */ +xmlXPathObjectPtr +xmlXPathEvalXPtrExpr(const xmlChar *str, xmlXPathContextPtr ctx) { + xmlXPathParserContextPtr ctxt; + xmlXPathObjectPtr res = NULL, tmp; + int stack = 0; + + xmlXPathInit(); + + CHECK_CONTEXT(ctx) + + if (xmlXPathDebug == NULL) + xmlXPathDebug = stderr; + ctxt = xmlXPathNewParserContext(str, ctx); + valuePush(ctxt, xmlXPathNewNodeSet(ctx->node)); + if (str[0] == '/') + xmlXPathRoot(ctxt); + xmlXPathEvalExpr(ctxt); + + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_NODESET) && + (ctxt->value->type != XPATH_LOCATIONSET))) { + fprintf(xmlXPathDebug, + "xmlXPathEval: evaluation failed to return a node set\n"); + } else { + res = valuePop(ctxt); + } + + do { + tmp = valuePop(ctxt); + if (tmp != NULL) { + xmlXPathFreeObject(tmp); + stack++; + } + } while (tmp != NULL); + if (stack != 0) { + fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n", + stack); + } + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeObject(res); + res = NULL; + } + + xmlXPathFreeParserContext(ctxt); + return(res); +} + +/** * xmlXPathEvalExpression: * @str: the XPath expression * @ctxt: the XPath context @@ -51,7 +51,10 @@ typedef enum { XPATH_BOOLEAN = 2, XPATH_NUMBER = 3, XPATH_STRING = 4, - XPATH_USERS = 5 + XPATH_POINT = 5, + XPATH_RANGE = 6, + XPATH_LOCATIONSET = 7, + XPATH_USERS = 8 } xmlXPathObjectType; typedef struct _xmlXPathObject xmlXPathObject; @@ -63,6 +66,9 @@ struct _xmlXPathObject { double floatval; xmlChar *stringval; void *user; + int index; + void *user2; + int index2; }; /* @@ -168,6 +174,11 @@ struct _xmlXPathContext { /* extra variables */ int contextSize; /* the context size */ int proximityPosition; /* the proximity position */ + + /* extra stuff for XPointer */ + int xptr; /* it this an XPointer context */ + xmlNodePtr here; /* for here() */ + xmlNodePtr origin; /* for origin() */ }; /* @@ -220,10 +231,13 @@ typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs); /** * Evaluation functions. */ +void xmlXPathInit (void); xmlXPathContextPtr xmlXPathNewContext (xmlDocPtr doc); void xmlXPathFreeContext (xmlXPathContextPtr ctxt); xmlXPathObjectPtr xmlXPathEval (const xmlChar *str, xmlXPathContextPtr ctxt); +xmlXPathObjectPtr xmlXPathEvalXPtrExpr (const xmlChar *str, + xmlXPathContextPtr ctxt); void xmlXPathFreeObject (xmlXPathObjectPtr obj); xmlXPathObjectPtr xmlXPathEvalExpression (const xmlChar *str, xmlXPathContextPtr ctxt); |