From f62ceffb7e538bf78894d2e2192848fdb40fe278 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 24 Nov 2000 23:36:01 +0000 Subject: [PATCH] General fixes, XPointer improvements: - HTMLparser.c: some fixes on auto-open of html/head/body - encoding.c: fixed a compilation error on some gcc env - xpath.c xpointer.[ch] xpathInternals.h: improved the XPointer implementation - test/XPath/xptr/strpoint test/XPath/xptr/strrange3: added related XPointer tests and associated results Daniel --- ChangeLog | 9 ++ HTMLparser.c | 74 +++++++++++--- aclocal.m4 | 40 ++++---- encoding.c | 4 +- include/libxml/xpathInternals.h | 2 + include/libxml/xpointer.h | 1 + result/HTML/doc2.htm | 4 +- result/HTML/doc2.htm.sax | 2 - result/XPath/xptr/strpoint | 75 ++++++++++++++ result/XPath/xptr/strrange3 | 48 +++++++++ test/XPath/xptr/strpoint | 9 ++ test/XPath/xptr/strrange3 | 4 + xpath.c | 14 ++- xpathInternals.h | 2 + xpointer.c | 170 +++++++++++++++++++++++++++++--- xpointer.h | 1 + 16 files changed, 400 insertions(+), 59 deletions(-) create mode 100644 result/XPath/xptr/strpoint create mode 100644 result/XPath/xptr/strrange3 create mode 100644 test/XPath/xptr/strpoint create mode 100644 test/XPath/xptr/strrange3 diff --git a/ChangeLog b/ChangeLog index 7a3a23ab..e4ae3377 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Sat Nov 25 00:24:49 CET 2000 Daniel Veillard + + * HTMLparser.c: some fixes on auto-open of html/head/body + * encoding.c: fixed a compilation error on some gcc env + * xpath.c xpointer.[ch] xpathInternals.h: improved the + XPointer implementation + * test/XPath/xptr/strpoint test/XPath/xptr/strrange3: added + related XPointer tests and associated results + Fri Nov 24 14:01:44 CET 2000 Daniel Veillard * doc/xmldtd.html doc/xml.html: following a short step by step diff --git a/HTMLparser.c b/HTMLparser.c index 7e3f239c..f2831f6b 100644 --- a/HTMLparser.c +++ b/HTMLparser.c @@ -855,13 +855,13 @@ htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag) { } if ((xmlStrEqual(newtag, BAD_CAST"body")) || (xmlStrEqual(newtag, BAD_CAST"head"))) return; - if (ctxt->nameNr <= 1) { - if ((xmlStrEqual(newtag, BAD_CAST"script")) || - (xmlStrEqual(newtag, BAD_CAST"style")) || - (xmlStrEqual(newtag, BAD_CAST"meta")) || - (xmlStrEqual(newtag, BAD_CAST"link")) || - (xmlStrEqual(newtag, BAD_CAST"title")) || - (xmlStrEqual(newtag, BAD_CAST"base"))) { + if ((ctxt->nameNr <= 1) && + ((xmlStrEqual(newtag, BAD_CAST"script")) || + (xmlStrEqual(newtag, BAD_CAST"style")) || + (xmlStrEqual(newtag, BAD_CAST"meta")) || + (xmlStrEqual(newtag, BAD_CAST"link")) || + (xmlStrEqual(newtag, BAD_CAST"title")) || + (xmlStrEqual(newtag, BAD_CAST"base")))) { /* * dropped OBJECT ... i you put it first BODY will be * assumed ! @@ -872,14 +872,25 @@ htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag) { htmlnamePush(ctxt, xmlStrdup(BAD_CAST"head")); if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL)) ctxt->sax->startElement(ctxt->userData, BAD_CAST"head", NULL); - } else { -#ifdef DEBUG - xmlGenericError(xmlGenericErrorContext,"Implied element body: pushed body\n"); -#endif - htmlnamePush(ctxt, xmlStrdup(BAD_CAST"body")); - if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL)) - ctxt->sax->startElement(ctxt->userData, BAD_CAST"body", NULL); + } else if ((!xmlStrEqual(newtag, BAD_CAST"noframes")) && + (!xmlStrEqual(newtag, BAD_CAST"frame")) && + (!xmlStrEqual(newtag, BAD_CAST"frameset"))) { + int i; + for (i = 0;i < ctxt->nameNr;i++) { + if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"body")) { + return; + } + if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"head")) { + return; + } } + +#ifdef DEBUG + xmlGenericError(xmlGenericErrorContext,"Implied element body: pushed body\n"); +#endif + htmlnamePush(ctxt, xmlStrdup(BAD_CAST"body")); + if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL)) + ctxt->sax->startElement(ctxt->userData, BAD_CAST"body", NULL); } } @@ -2932,6 +2943,41 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { */ htmlCheckImplied(ctxt, name); + /* + * Avoid html at any level > 0, head at any level != 1 + * or any attempt to recurse body + */ + if ((ctxt->nameNr > 0) && (xmlStrEqual(name, BAD_CAST"html"))) { + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "htmlParseStartTag: misplaced tag\n"); + ctxt->wellFormed = 0; + xmlFree(name); + return; + } + if ((ctxt->nameNr != 1) && + (xmlStrEqual(name, BAD_CAST"head"))) { + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "htmlParseStartTag: misplaced tag\n"); + ctxt->wellFormed = 0; + xmlFree(name); + return; + } + if (xmlStrEqual(name, BAD_CAST"body")) { + int i; + for (i = 0;i < ctxt->nameNr;i++) { + if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"body")) { + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "htmlParseStartTag: misplaced tag\n"); + ctxt->wellFormed = 0; + xmlFree(name); + return; + } + } + } + /* * Now parse the attributes, it ends up with the ending * diff --git a/aclocal.m4 b/aclocal.m4 index e3726759..869e5fcc 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -620,35 +620,31 @@ esac ]) # AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for -# the libltdl convenience library and INCLTDL to the include flags for -# the libltdl header and adds --enable-ltdl-convenience to the -# configure arguments. Note that LIBLTDL and INCLTDL are not -# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not -# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed -# with '${top_builddir}/' and INCLTDL will be prefixed with -# '${top_srcdir}/' (note the single quotes!). If your package is not -# flat and you're not using automake, define top_builddir and -# top_srcdir appropriately in the Makefiles. +# the libltdl convenience library, adds --enable-ltdl-convenience to +# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor +# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed +# to be `${top_builddir}/libltdl'. Make sure you start DIR with +# '${top_builddir}/' (note the single quotes!) if your package is not +# flat, and, if you're not using automake, define top_builddir as +# appropriate in the Makefiles. AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl case "$enable_ltdl_convenience" in no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; "") enable_ltdl_convenience=yes ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac - LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la - INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdlc.la + INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl']) ]) # AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for -# the libltdl installable library and INCLTDL to the include flags for -# the libltdl header and adds --enable-ltdl-install to the configure -# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is -# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed -# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will -# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed -# with '${top_srcdir}/' (note the single quotes!). If your package is -# not flat and you're not using automake, define top_builddir and -# top_srcdir appropriately in the Makefiles. +# the libltdl installable library, and adds --enable-ltdl-install to +# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor +# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed +# to be `${top_builddir}/libltdl'. Make sure you start DIR with +# '${top_builddir}/' (note the single quotes!) if your package is not +# flat, and, if you're not using automake, define top_builddir as +# appropriate in the Makefiles. # In the future, this macro may have to be called after AC_PROG_LIBTOOL. AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_CHECK_LIB(ltdl, main, @@ -661,8 +657,8 @@ AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl ]) if test x"$enable_ltdl_install" = x"yes"; then ac_configure_args="$ac_configure_args --enable-ltdl-install" - LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la - INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdl.la + INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl']) else ac_configure_args="$ac_configure_args --enable-ltdl-install=no" LIBLTDL="-lltdl" diff --git a/encoding.c b/encoding.c index d60b8459..643d7f88 100644 --- a/encoding.c +++ b/encoding.c @@ -1686,9 +1686,9 @@ xmlIconvWrapper(iconv_t cd, #ifdef EINVAL if (errno == EINVAL) { return -3; - } + } else #endif - else { + { return -3; } } diff --git a/include/libxml/xpathInternals.h b/include/libxml/xpathInternals.h index b73d49e4..a18e453a 100644 --- a/include/libxml/xpathInternals.h +++ b/include/libxml/xpathInternals.h @@ -133,6 +133,8 @@ void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth); * Existing functions */ +int xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr res); void xmlXPathInit(void); void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs); void xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt); diff --git a/include/libxml/xpointer.h b/include/libxml/xpointer.h index f90d9c6e..786fb5a0 100644 --- a/include/libxml/xpointer.h +++ b/include/libxml/xpointer.h @@ -49,6 +49,7 @@ xmlXPathObjectPtr xmlXPtrEval (const xmlChar *str, void xmlXPtrRangeToFunction (xmlXPathParserContextPtr ctxt, int nargs); xmlNodePtr xmlXPtrBuildNodeList (xmlXPathObjectPtr obj); +void xmlXPtrEvalRangePredicate (xmlXPathParserContextPtr ctxt); #ifdef __cplusplus } diff --git a/result/HTML/doc2.htm b/result/HTML/doc2.htm index 759780d5..674044b3 100644 --- a/result/HTML/doc2.htm +++ b/result/HTML/doc2.htm @@ -13,12 +13,12 @@ - + <body bgcolor="#FFFFFF" text="#000000" link="#000080" vlink="#000080" alink="#000080" topmargin="0" leftmargin="0" marginheight="0" marginwidth="0"><p>This page uses frames, but your browser doesn't support them.</p></body> - + diff --git a/result/HTML/doc2.htm.sax b/result/HTML/doc2.htm.sax index 94f2819e..27d458a1 100644 --- a/result/HTML/doc2.htm.sax +++ b/result/HTML/doc2.htm.sax @@ -37,7 +37,6 @@ SAX.ignorableWhitespace( SAX.startElement(meta, content='MSHTML 5.00.3103.1000', name='GENERATOR') SAX.endElement(meta) SAX.endElement(head) -SAX.startElement(body) SAX.startElement(frameset, border='false', cols='172,*', frameborder='0', framespacing='0') SAX.startElement(frame, marginheight='0', marginwidth='0', name='left', noresize, scrolling='no', src='doc2_files/side.htm', target='rtop') SAX.endElement(frame) @@ -64,7 +63,6 @@ SAX.characters( , 3) SAX.endElement(noframes) SAX.endElement(frameset) -SAX.endElement(body) SAX.endElement(html) SAX.ignorableWhitespace( , 1) diff --git a/result/XPath/xptr/strpoint b/result/XPath/xptr/strpoint new file mode 100644 index 00000000..d6ecab39 --- /dev/null +++ b/result/XPath/xptr/strpoint @@ -0,0 +1,75 @@ + +======================== +Expression: xpointer(start-point(string-range(//p,'multiple'))) +Object is a Location Set: +1 : Object is a point : index 1 in node TEXT + content=multiple tests + + +======================== +Expression: xpointer(end-point(string-range(//p,'multiple'))) +Object is a Location Set: +1 : Object is a point : index 8 in node TEXT + content=multiple tests + + +======================== +Expression: xpointer(start-point(string-range(//p,'test'))) +Object is a Location Set: +1 : Object is a point : index 10 in node TEXT + content=a simple test + +2 : Object is a point : index 10 in node TEXT + content=multiple tests + +3 : Object is a point : index 7 in node TEXT + content=anced test + + +======================== +Expression: xpointer(end-point(string-range(//p,'test'))) +Object is a Location Set: +1 : Object is a point : index 13 in node TEXT + content=a simple test + +2 : Object is a point : index 13 in node TEXT + content=multiple tests + +3 : Object is a point : index 10 in node TEXT + content=anced test + + +======================== +Expression: xpointer(start-point(string-range(//*,'multiple',1,0))) +Object is a Location Set: +1 : Object is a point : index 1 in node TEXT + content=multiple tests + + +======================== +Expression: xpointer(end-point(string-range(//*,'multiple',1,0))) +Object is a Location Set: +1 : Object is a point : index 1 in node TEXT + content=multiple tests + + +======================== +Expression: xpointer(start-point(string-range(//*,'multiple',1,1))) +Object is a Location Set: +1 : Object is a point : index 1 in node TEXT + content=multiple tests + + +======================== +Expression: xpointer(end-point(string-range(//*,'multiple',1,1))) +Object is a Location Set: +1 : Object is a point : index 2 in node TEXT + content=multiple tests + + +======================== +Expression: xpointer(start-point(string-range(//p,'test'))[1]) +Object is a Location Set: +1 : Object is a point : index 10 in node TEXT + content=a simple test + diff --git a/result/XPath/xptr/strrange3 b/result/XPath/xptr/strrange3 new file mode 100644 index 00000000..6d3114a8 --- /dev/null +++ b/result/XPath/xptr/strrange3 @@ -0,0 +1,48 @@ + +======================== +Expression: xpointer(string-range(//p, 'test', 1, 0)) +Object is a Location Set: +1 : Object is a collapsed range : + index 10 in node + TEXT + content=a simple test +2 : Object is a collapsed range : + index 10 in node + TEXT + content=multiple tests +3 : Object is a collapsed range : + index 7 in node + TEXT + content=anced test + +======================== +Expression: xpointer(string-range(//*, 'test', 1, 0)) +Object is a Location Set: +1 : Object is a collapsed range : + index 10 in node + TEXT + content=a simple test +2 : Object is a collapsed range : + index 10 in node + TEXT + content=multiple tests +3 : Object is a collapsed range : + index 7 in node + TEXT + content=anced test + +======================== +Expression: xpointer(string-range(//p, 'test', 1, 0)[2]) +Object is a Location Set: +1 : Object is a collapsed range : + index 10 in node + TEXT + content=multiple tests + +======================== +Expression: xpointer(string-range(//*, 'test', 1, 0)[2]) +Object is a Location Set: +1 : Object is a collapsed range : + index 10 in node + TEXT + content=multiple tests diff --git a/test/XPath/xptr/strpoint b/test/XPath/xptr/strpoint new file mode 100644 index 00000000..0916ef10 --- /dev/null +++ b/test/XPath/xptr/strpoint @@ -0,0 +1,9 @@ +xpointer(start-point(string-range(//p,'multiple'))) +xpointer(end-point(string-range(//p,'multiple'))) +xpointer(start-point(string-range(//p,'test'))) +xpointer(end-point(string-range(//p,'test'))) +xpointer(start-point(string-range(//*,'multiple',1,0))) +xpointer(end-point(string-range(//*,'multiple',1,0))) +xpointer(start-point(string-range(//*,'multiple',1,1))) +xpointer(end-point(string-range(//*,'multiple',1,1))) +xpointer(start-point(string-range(//p,'test'))[1]) diff --git a/test/XPath/xptr/strrange3 b/test/XPath/xptr/strrange3 new file mode 100644 index 00000000..aea56652 --- /dev/null +++ b/test/XPath/xptr/strrange3 @@ -0,0 +1,4 @@ +xpointer(string-range(//p, 'test', 1, 0)) +xpointer(string-range(//*, 'test', 1, 0)) +xpointer(string-range(//p, 'test', 1, 0)[2]) +xpointer(string-range(//*, 'test', 1, 0)[2]) diff --git a/xpath.c b/xpath.c index 29917117..2a1ad069 100644 --- a/xpath.c +++ b/xpath.c @@ -4421,12 +4421,16 @@ xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) { CHECK_ERROR; SKIP_BLANKS; - if (CUR != '[') return; - - CHECK_TYPE(XPATH_NODESET); - while (CUR == '[') { - xmlXPathEvalPredicate(ctxt); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_NODESET) && + (ctxt->value->type != XPATH_LOCATIONSET))) + XP_ERROR(XPATH_INVALID_TYPE) + + if (ctxt->value->type == XPATH_NODESET) + xmlXPathEvalPredicate(ctxt); + else + xmlXPtrEvalRangePredicate(ctxt); SKIP_BLANKS; } diff --git a/xpathInternals.h b/xpathInternals.h index b73d49e4..a18e453a 100644 --- a/xpathInternals.h +++ b/xpathInternals.h @@ -133,6 +133,8 @@ void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth); * Existing functions */ +int xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr res); void xmlXPathInit(void); void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs); void xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt); diff --git a/xpointer.c b/xpointer.c index 7ead4b73..376421ff 100644 --- a/xpointer.c +++ b/xpointer.c @@ -275,6 +275,36 @@ xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) { } } +/** + * xmlXPtrRangesEqual: + * @range1: the first range + * @range2: the second range + * + * Compare two ranges + * + * Return 1 if equal, 0 otherwise + */ +int +xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) { + if (range1 == range2) + return(1); + if ((range1 == NULL) || (range2 == NULL)) + return(0); + if (range1->type != range2->type) + return(0); + if (range1->type != XPATH_RANGE) + return(0); + if (range1->user != range2->user) + return(0); + if (range1->index != range2->index) + return(0); + if (range1->user2 != range2->user2) + return(0); + if (range1->index2 != range2->index2) + return(0); + return(1); +} + /** * xmlXPtrNewRange: * @start: the starting node @@ -594,6 +624,7 @@ xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) { * @val: a new xmlXPathObjectPtr * * add a new xmlXPathObjectPtr ot an existing LocationSet + * If the location already exist in the set @val is freed. */ void xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { @@ -604,8 +635,12 @@ xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { /* * check against doublons */ - for (i = 0;i < cur->locNr;i++) - if (cur->locTab[i] == val) return; + for (i = 0;i < cur->locNr;i++) { + if (xmlXPtrRangesEqual(cur->locTab[i], val)) { + xmlXPathFreeObject(val); + return; + } + } /* * grow the locTab if needed @@ -1656,6 +1691,10 @@ xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { } newset = xmlXPtrLocationSetCreate(NULL); + if (newset == NULL) { + xmlXPathFreeObject(obj); + XP_ERROR(XPATH_MEMORY_ERROR); + } oldset = (xmlLocationSetPtr) obj->user; if (oldset != NULL) { int i; @@ -1680,10 +1719,6 @@ xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { } point = xmlXPtrNewPoint(node, tmp->index); } - if (tmp->user2 == NULL) { - point = xmlXPtrNewPoint(node, 0); - } else - point = xmlXPtrNewPoint(node, tmp->index); break; } default: @@ -1699,6 +1734,7 @@ xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { } } xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); } /** @@ -1762,7 +1798,7 @@ xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { point = xmlXPtrNewPoint(tmp->user, tmp->index); break; case XPATH_RANGE: { - xmlNodePtr node = tmp->user; + xmlNodePtr node = tmp->user2; if (node != NULL) { if (node->type == XML_ATTRIBUTE_NODE) { /* TODO: Namespace Nodes ??? */ @@ -1770,13 +1806,11 @@ xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPtrFreeLocationSet(newset); XP_ERROR(XPTR_SYNTAX_ERROR); } - point = xmlXPtrNewPoint(node, tmp->index); - } - if (tmp->user2 == NULL) { + point = xmlXPtrNewPoint(node, tmp->index2); + } else if (tmp->user == NULL) { point = xmlXPtrNewPoint(node, xmlXPtrNbLocChildren(node)); - } else - point = xmlXPtrNewPoint(node, tmp->index); + } break; } default: @@ -1792,6 +1826,7 @@ xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { } } xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); } @@ -2515,6 +2550,8 @@ xmlXPtrGetLastChar(xmlNodePtr *node, int *index) { len = xmlBufferLength(cur->content); #endif break; + } else { + return(-1); } } if (cur == NULL) @@ -2756,6 +2793,115 @@ xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (number) xmlXPathFreeObject(number); } +/** + * xmlXPtrEvalRangePredicate: + * @ctxt: the XPointer Parser context + * + * [8] Predicate ::= '[' PredicateExpr ']' + * [9] PredicateExpr ::= Expr + * + * Evaluate a predicate as in xmlXPathEvalPredicate() but for + * a Location Set instead of a node set + */ +void +xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) { + const xmlChar *cur; + xmlXPathObjectPtr res; + xmlXPathObjectPtr obj, tmp; + xmlLocationSetPtr newset = NULL; + xmlLocationSetPtr oldset; + int i; + + SKIP_BLANKS; + if (CUR != '[') { + XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); + } + NEXT; + SKIP_BLANKS; + + /* + * Extract the old set, and then evaluate the result of the + * expression for all the element in the set. use it to grow + * up a new set. + */ + CHECK_TYPE(XPATH_LOCATIONSET); + obj = valuePop(ctxt); + oldset = obj->user; + ctxt->context->node = NULL; + + if ((oldset == NULL) || (oldset->locNr == 0)) { + ctxt->context->contextSize = 0; + ctxt->context->proximityPosition = 0; + xmlXPathEvalExpr(ctxt); + res = valuePop(ctxt); + if (res != NULL) + xmlXPathFreeObject(res); + valuePush(ctxt, obj); + CHECK_ERROR; + } else { + /* + * Save the expression pointer since we will have to evaluate + * it multiple times. Initialize the new set. + */ + cur = ctxt->cur; + newset = xmlXPtrLocationSetCreate(NULL); + + for (i = 0; i < oldset->locNr; i++) { + ctxt->cur = cur; + + /* + * Run the evaluation with a node list made of a single item + * in the nodeset. + */ + ctxt->context->node = oldset->locTab[i]->user; + tmp = xmlXPathNewNodeSet(ctxt->context->node); + valuePush(ctxt, tmp); + ctxt->context->contextSize = oldset->locNr; + ctxt->context->proximityPosition = i + 1; + + xmlXPathEvalExpr(ctxt); + CHECK_ERROR; + + /* + * The result of the evaluation need to be tested to + * decided whether the filter succeeded or not + */ + res = valuePop(ctxt); + if (xmlXPathEvaluatePredicateResult(ctxt, res)) { + xmlXPtrLocationSetAdd(newset, + xmlXPathObjectCopy(oldset->locTab[i])); + } + + /* + * 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, xmlXPtrWrapLocationSet(newset)); + } + if (CUR != ']') { + XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); + } + + NEXT; + SKIP_BLANKS; +} + #else #endif diff --git a/xpointer.h b/xpointer.h index f90d9c6e..786fb5a0 100644 --- a/xpointer.h +++ b/xpointer.h @@ -49,6 +49,7 @@ xmlXPathObjectPtr xmlXPtrEval (const xmlChar *str, void xmlXPtrRangeToFunction (xmlXPathParserContextPtr ctxt, int nargs); xmlNodePtr xmlXPtrBuildNodeList (xmlXPathObjectPtr obj); +void xmlXPtrEvalRangePredicate (xmlXPathParserContextPtr ctxt); #ifdef __cplusplus }