summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Veillard <veillard@src.gnome.org>2000-10-04 13:33:43 +0000
committerDaniel Veillard <veillard@src.gnome.org>2000-10-04 13:33:43 +0000
commitac2603066945f8508fc8cb0a78a8f91983c24e59 (patch)
tree337ee65486a85bff2433e743447735fba295797b
parent7cfce324d84603dec97d3a6bcafdaec53785e90a (diff)
downloadlibxml2-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--ChangeLog6
-rw-r--r--debugXML.c38
-rw-r--r--include/libxml/xpath.h16
-rw-r--r--result/XPath/expr/base15
-rw-r--r--result/XPath/expr/compare72
-rw-r--r--result/XPath/expr/equality72
-rw-r--r--result/XPath/expr/functions15
-rw-r--r--result/XPath/expr/strings57
-rw-r--r--result/XPath/tests/chaptersbase37
-rw-r--r--result/XPath/tests/chaptersprefol76
-rw-r--r--result/XPath/tests/idsimple19
-rw-r--r--result/XPath/tests/simpleabbr38
-rw-r--r--result/XPath/tests/simplebase37
-rw-r--r--result/XPath/tests/usr1check7
-rw-r--r--test/XPath/tests/chaptersprefol1
-rw-r--r--testXPath.c29
-rw-r--r--xpath.c796
-rw-r--r--xpath.h16
18 files changed, 1226 insertions, 121 deletions
diff --git a/ChangeLog b/ChangeLog
index 70c747d1..17675450 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/debugXML.c b/debugXML.c
index 0363352f..f2178dec 100644
--- a/debugXML.c
+++ b/debugXML.c
@@ -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")))
diff --git a/xpath.c b/xpath.c
index 12ab43a6..1ea8aea6 100644
--- a/xpath.c
+++ b/xpath.c
@@ -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
diff --git a/xpath.h b/xpath.h
index 6c5f42eb..631f59f2 100644
--- a/xpath.h
+++ b/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);