diff --git a/ChangeLog b/ChangeLog index 38774899..efee4d0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Wed Jun 9 11:07:42 PDT 2005 William Brack + + * pattern.c, xpath.c, include/libxml/pattern.h: Further + enhancement for XPath streaming, consolidated with + schemas usage of pattern.c. Added a new enum + xmlPatternFlags. + * doc/*, testapi.c, elfgcchack.h: updated to reflect new + enum. + * test/XPath/tests/mixedpat, test/XPath/docs/mixed, + result/XPath/mixedpat: added regression test for problems + reported in bug306348 + Thu Jun 9 16:51:31 CEST 2005 Kasimier Buchcik * xmlschemastypes.c: Changed non-prefixed QNames to be bound to a diff --git a/doc/APIfiles.html b/doc/APIfiles.html index 5bd67748..bae02194 100644 --- a/doc/APIfiles.html +++ b/doc/APIfiles.html @@ -856,10 +856,15 @@ A:link, A:visited, A:active { text-decoration: underline } xmlSwitchEncoding
xmlSwitchInputEncoding
xmlSwitchToEncoding
-

Module pattern:

xmlFreePattern
+

Module pattern:

XML_PATTERN_DEFAULT
+XML_PATTERN_XPATH
+XML_PATTERN_XSFIELD
+XML_PATTERN_XSSEL
+xmlFreePattern
xmlFreePatternList
xmlFreeStreamCtxt
xmlPattern
+xmlPatternFlags
xmlPatternFromRoot
xmlPatternGetStreamCtxt
xmlPatternMatch
diff --git a/doc/APIfunctions.html b/doc/APIfunctions.html index 366d0bce..171f3ea7 100644 --- a/doc/APIfunctions.html +++ b/doc/APIfunctions.html @@ -1705,6 +1705,7 @@ A:link, A:visited, A:active { text-decoration: underline }

Type xmlParserNodeInfoSeqPtr:

xmlClearNodeInfoSeq
xmlInitNodeInfoSeq

Type xmlParserSeverities:

xmlTextReaderErrorFunc
+

Type xmlPatternFlags:

xmlPatterncompile

Type xmlPatternPtr:

xmlFreePattern
xmlFreePatternList
xmlPatternFromRoot
diff --git a/doc/APIsymbols.html b/doc/APIsymbols.html index 96492655..73bafc10 100644 --- a/doc/APIsymbols.html +++ b/doc/APIsymbols.html @@ -558,6 +558,10 @@ A:link, A:visited, A:active { text-decoration: underline } XML_PARSE_SAX1
XML_PARSE_UNKNOWN
XML_PARSE_XINCLUDE
+XML_PATTERN_DEFAULT
+XML_PATTERN_XPATH
+XML_PATTERN_XSFIELD
+XML_PATTERN_XSSEL
XML_PI_NODE
XML_READER_TYPE_ATTRIBUTE
XML_READER_TYPE_CDATA
@@ -2336,6 +2340,7 @@ A:link, A:visited, A:active { text-decoration: underline } xmlParserVersion
xmlParserWarning
xmlPattern
+xmlPatternFlags
xmlPatternFromRoot
xmlPatternGetStreamCtxt
xmlPatternMatch
diff --git a/doc/html/libxml-pattern.html b/doc/html/libxml-pattern.html index e9b5a69e..0659588b 100644 --- a/doc/html/libxml-pattern.html +++ b/doc/html/libxml-pattern.html @@ -12,6 +12,7 @@ A:link, A:visited, A:active { text-decoration: underline } pre.programlisting {border-style: double;background: #EECFA1} Module pattern from libxml2
Action against software patentsGnome2 LogoW3C LogoRed Hat Logo
Made with Libxml2 Logo

Module pattern from libxml2

API Menu
API Indexes
Related links

allows to compile and test pattern expressions for nodes either in a tree or based on a parser state.

Table of Contents

Structure xmlPattern
struct _xmlPattern The content of this structure is not made public by the API. +
Enum xmlPatternFlags
 
Typedef xmlPattern * xmlPatternPtr
 
Structure xmlStreamCtxt
struct _xmlStreamCtxt The content of this structure is not made public by the API. @@ -24,14 +25,20 @@ The content of this structure is not made public by the API.
int	xmlPatternMatch			(xmlPatternPtr comp, 
xmlNodePtr node)
int	xmlPatternMaxDepth		(xmlPatternPtr comp)
int	xmlPatternStreamable		(xmlPatternPtr comp)
-
xmlPatternPtr	xmlPatterncompile	(const xmlChar * pattern, 
xmlDict * dict,
int flags,
const xmlChar ** namespaces)
+
xmlPatternPtr	xmlPatterncompile	(const xmlChar * pattern, 
xmlDict * dict,
xmlPatternFlags flags,
const xmlChar ** namespaces)
int	xmlStreamPop			(xmlStreamCtxtPtr stream)
int	xmlStreamPush			(xmlStreamCtxtPtr stream, 
const xmlChar * name,
const xmlChar * ns)
int	xmlStreamPushAttr		(xmlStreamCtxtPtr stream, 
const xmlChar * name,
const xmlChar * ns)

Description

Structure xmlPattern

Structure xmlPattern
struct _xmlPattern { The content of this structure is not made public by the API. -}

Structure xmlStreamCtxt

Structure xmlStreamCtxt
struct _xmlStreamCtxt { +}

Enum xmlPatternFlags

Enum xmlPatternFlags {
+    XML_PATTERN_DEFAULT = 0 : simple pattern match
+    XML_PATTERN_XPATH = 1 : standard XPath pattern
+    XML_PATTERN_XSSEL = 2 : XPath subset for schema selector
+    XML_PATTERN_XSFIELD = 4 : XPath subset for schema field
+}
+

Structure xmlStreamCtxt

Structure xmlStreamCtxt
struct _xmlStreamCtxt { The content of this structure is not made public by the API. }

Function: xmlFreePattern

void	xmlFreePattern			(xmlPatternPtr comp)

Free up the memory allocated by @comp

@@ -49,7 +56,7 @@ The content of this structure is not made public by the API.

Check the maximum depth reachable by a pattern

comp:the precompiled pattern
Returns:-2 if no limit (using //), otherwise the depth, and -1 in case of error

Function: xmlPatternStreamable

int	xmlPatternStreamable		(xmlPatternPtr comp)

Check if the pattern is streamable i.e. xmlPatternGetStreamCtxt() should work.

-
comp:the precompiled pattern
Returns:1 if streamable, 0 if not and -1 in case of error.

Function: xmlPatterncompile

xmlPatternPtr	xmlPatterncompile	(const xmlChar * pattern, 
xmlDict * dict,
int flags,
const xmlChar ** namespaces)
+
comp:the precompiled pattern
Returns:1 if streamable, 0 if not and -1 in case of error.

Function: xmlPatterncompile

xmlPatternPtr	xmlPatterncompile	(const xmlChar * pattern, 
xmlDict * dict,
xmlPatternFlags flags,
const xmlChar ** namespaces)

Compile a pattern.

pattern:the pattern to compile
dict:an optional dictionary for interned strings
flags:compilation flags, undefined yet
namespaces:the prefix definitions, array of [URI, prefix] or NULL
Returns:the compiled form of the pattern or NULL in case of error

Function: xmlStreamPop

int	xmlStreamPop			(xmlStreamCtxtPtr stream)

push one level from the stream.

diff --git a/doc/libxml2-api.xml b/doc/libxml2-api.xml index 16f7437b..770153be 100644 --- a/doc/libxml2-api.xml +++ b/doc/libxml2-api.xml @@ -951,8 +951,13 @@ pattern expression handling allows to compile and test pattern expressions for nodes either in a tree or based on a parser state. Daniel Veillard - + + + + + + @@ -4739,6 +4744,10 @@ + + + + @@ -5942,6 +5951,7 @@ actually an xmlCharEncoding'/> + @@ -11641,7 +11651,7 @@ actually an xmlCharEncoding'/> - + diff --git a/doc/libxml2-refs.xml b/doc/libxml2-refs.xml index 93b13288..0e857b9c 100644 --- a/doc/libxml2-refs.xml +++ b/doc/libxml2-refs.xml @@ -552,6 +552,10 @@ + + + + @@ -2330,6 +2334,7 @@ + @@ -3875,6 +3880,10 @@ + + + + @@ -5689,6 +5698,7 @@ + @@ -9345,6 +9355,9 @@ + + + @@ -10826,10 +10839,15 @@ + + + + + diff --git a/include/libxml/pattern.h b/include/libxml/pattern.h index f801a374..e3ee76dd 100644 --- a/include/libxml/pattern.h +++ b/include/libxml/pattern.h @@ -29,6 +29,20 @@ extern "C" { typedef struct _xmlPattern xmlPattern; typedef xmlPattern *xmlPatternPtr; +/** + * xmlPatternFlags: + * + * This is the set of options affecting the behaviour of pattern + * matching with this module + * + */ +typedef enum { + XML_PATTERN_DEFAULT = 0, /* simple pattern match */ + XML_PATTERN_XPATH = 1<<0, /* standard XPath pattern */ + XML_PATTERN_XSSEL = 1<<1, /* XPath subset for schema selector */ + XML_PATTERN_XSFIELD = 1<<2 /* XPath subset for schema field */ +} xmlPatternFlags; + XMLPUBFUN void XMLCALL xmlFreePattern (xmlPatternPtr comp); @@ -38,7 +52,7 @@ XMLPUBFUN void XMLCALL XMLPUBFUN xmlPatternPtr XMLCALL xmlPatterncompile (const xmlChar *pattern, xmlDict *dict, - int flags, + xmlPatternFlags flags, const xmlChar **namespaces); XMLPUBFUN int XMLCALL xmlPatternMatch (xmlPatternPtr comp, diff --git a/pattern.c b/pattern.c index fdd9f162..7bd8bb01 100644 --- a/pattern.c +++ b/pattern.c @@ -48,7 +48,10 @@ #define XML_STREAM_STEP_ROOT 4 #define XML_STREAM_STEP_ATTR 8 -#define XML_PATTERN_NOTPATTERN 1 +#define XML_PATTERN_NOTPATTERN (XML_PATTERN_XPATH | \ + XML_PATTERN_XSSEL | \ + XML_PATTERN_XSFIELD) +#define XML_PATTERN_XSD (XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD) typedef struct _xmlStreamStep xmlStreamStep; typedef xmlStreamStep *xmlStreamStepPtr; @@ -119,16 +122,15 @@ struct _xmlStepOp { const xmlChar *value2; }; -#define PAT_FROM_ROOT 1 -#define PAT_FROM_CUR 2 +#define PAT_FROM_ROOT (1<<8) +#define PAT_FROM_CUR (1<<9) struct _xmlPattern { void *data; /* the associated template */ xmlDictPtr dict; /* the optional dictionary */ struct _xmlPattern *next; /* next pattern if | is used */ const xmlChar *pattern; /* the pattern */ - - int flags; /* flags */ + xmlPatternFlags flags; /* flags */ int nbStep; int maxStep; xmlStepOpPtr steps; /* ops for computation */ @@ -692,11 +694,11 @@ rollback: if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error; #define XSLT_ERROR(X) \ - { xsltError(ctxt, __FILE__, __LINE__, X); \ + { xsltError(ctxt, __FILE__, __LINE__, X); \ ctxt->error = (X); return; } #define XSLT_ERROR0(X) \ - { xsltError(ctxt, __FILE__, __LINE__, X); \ + { xsltError(ctxt, __FILE__, __LINE__, X); \ ctxt->error = (X); return(0); } #if 0 @@ -1047,8 +1049,8 @@ xmlCompileStepPattern(xmlPatParserContextPtr ctxt) { } if (i >= ctxt->nb_namespaces) { ERROR5(NULL, NULL, NULL, - "xmlCompileStepPattern : no namespace bound to prefix %s\n", - prefix); + "xmlCompileStepPattern : no namespace bound " + "to prefix %s\n", prefix); ctxt->error = 1; goto error; } @@ -1122,9 +1124,10 @@ xmlCompilePathPattern(xmlPatParserContextPtr ctxt) { SKIP_BLANKS; if (CUR == '/') { ctxt->comp->flags |= PAT_FROM_ROOT; - } else if (CUR == '.') { + } else if ((CUR == '.') || (ctxt->comp->flags & XML_PATTERN_NOTPATTERN)) { ctxt->comp->flags |= PAT_FROM_CUR; } + if ((CUR == '/') && (NXT(1) == '/')) { PUSH(XML_OP_ANCESTOR, NULL, NULL); NEXT; @@ -1581,9 +1584,9 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, */ if (comp->nbStep == 0) { /* - * For non-pattern like evaluation like XML Schema IDCs, - * this will match if we are at the first level only, - * otherwise on every level. + * For non-pattern like evaluation like XML Schema IDCs + * or traditional XPath expressions, this will match if + * we are at the first level only, otherwise on every level. */ if ((nodeType == XML_ELEMENT_NODE) && (((stream->flags & XML_PATTERN_NOTPATTERN) == 0) || @@ -1593,18 +1596,20 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, stream->level++; goto stream_next; } - tmp = stream->level; - for (i = 0; i < comp->nbStep; i++) { - if (comp->steps[i].flags & XML_STREAM_STEP_DESC) { - tmp = -2; - break; + if ((stream->flags & XML_PATTERN_NOTPATTERN) != 0) { + tmp = stream->level; + for (i = 0; i < comp->nbStep; i++) { + if (comp->steps[i].flags & XML_STREAM_STEP_DESC) { + tmp = -2; + break; + } + } + if (comp->nbStep <= tmp) { + stream->level++; + goto stream_next; } - } - if (comp->nbStep < tmp) { - stream->level++; - goto stream_next; - } + } /* * Check evolution of existing states */ @@ -1685,7 +1690,7 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, */ desc = comp->steps[0].flags & XML_STREAM_STEP_DESC; if ( ((comp->steps[0].flags & XML_STREAM_STEP_ROOT) == 0) && - ( ((stream->flags & XML_PATTERN_NOTPATTERN) == 0) || + ( ((stream->flags & XML_PATTERN_XSD) == 0) || ( (desc || (stream->level == 1)) ) ) ) { @@ -1709,48 +1714,26 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, if (!(comp->steps[0].flags & XML_STREAM_STEP_ROOT)) { #endif */ - match = 0; - if (comp->dict) { - if (comp->steps[0].name == NULL) { - if (comp->steps[0].ns == NULL) - match = 1; - else + if (comp->steps[0].name == NULL) { + if (comp->steps[0].ns == NULL) + match = 1; + else { + if (comp->dict) match = (comp->steps[0].ns == ns); - } else { - if (stream->flags & XML_PATTERN_NOTPATTERN) { - /* - * Workaround for missing "self::node() on "foo". - */ - if (!desc) { - xmlStreamCtxtAddState(stream, 0, stream->level); - goto stream_next; - } else { - match = ((comp->steps[0].name == name) && - (comp->steps[0].ns == ns)); - } - } else { - match = ((comp->steps[0].name == name) && - (comp->steps[0].ns == ns)); - } - } - } else { - if (comp->steps[0].name == NULL) { - if (comp->steps[0].ns == NULL) - match = 1; else match = xmlStrEqual(comp->steps[0].ns, ns); + } + } else { + if ((stream->flags & XML_PATTERN_XSD) && (!desc)) { + /* + * Workaround for missing "self::node() on "foo". + */ + xmlStreamCtxtAddState(stream, 0, stream->level); + goto stream_next; } else { - if (stream->flags & XML_PATTERN_NOTPATTERN) { - /* - * Workaround for missing "self::node() on "foo". - */ - if (!desc) { - xmlStreamCtxtAddState(stream, 0, stream->level); - goto stream_next; - } else { - match = ((xmlStrEqual(comp->steps[0].name, name)) && - (xmlStrEqual(comp->steps[0].ns, ns))); - } + if (comp->dict) { + match = ((comp->steps[0].name == name) && + (comp->steps[0].ns == ns)); } else { match = ((xmlStrEqual(comp->steps[0].name, name)) && (xmlStrEqual(comp->steps[0].ns, ns))); @@ -1873,7 +1856,7 @@ xmlStreamPop(xmlStreamCtxtPtr stream) { */ xmlPatternPtr xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, - int flags ATTRIBUTE_UNUSED, + xmlPatternFlags flags, const xmlChar **namespaces) { xmlPatternPtr ret = NULL, cur; xmlPatParserContextPtr ctxt = NULL; @@ -1933,8 +1916,10 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, xmlStreamCompile(cur); if (xmlReversePattern(cur) < 0) goto error; - if (tmp != NULL) + if (tmp != NULL) { xmlFree(tmp); + tmp = NULL; + } start = or; } if (streamable == 0) { diff --git a/result/XPath/tests/mixedpat b/result/XPath/tests/mixedpat new file mode 100644 index 00000000..3be0c497 --- /dev/null +++ b/result/XPath/tests/mixedpat @@ -0,0 +1,101 @@ + +======================== +Expression: s +Object is a Node Set : +Set contains 1 nodes: +1 ELEMENT s + ATTRIBUTE p + TEXT + content=root + +======================== +Expression: s|p1/s +Object is a Node Set : +Set contains 2 nodes: +1 ELEMENT s + ATTRIBUTE p + TEXT + content=root +2 ELEMENT s + ATTRIBUTE p + TEXT + content=p1 + +======================== +Expression: s|/root/p1/s +Object is a Node Set : +Set contains 2 nodes: +1 ELEMENT s + ATTRIBUTE p + TEXT + content=root +2 ELEMENT s + ATTRIBUTE p + TEXT + content=p1 + +======================== +Expression: /root/p1/s|s +Object is a Node Set : +Set contains 2 nodes: +1 ELEMENT s + ATTRIBUTE p + TEXT + content=root +2 ELEMENT s + ATTRIBUTE p + TEXT + content=p1 + +======================== +Expression: //s +Object is a Node Set : +Set contains 3 nodes: +1 ELEMENT s + ATTRIBUTE p + TEXT + content=root +2 ELEMENT s + ATTRIBUTE p + TEXT + content=p1 +3 ELEMENT s + ATTRIBUTE p + TEXT + content=p2 + +======================== +Expression: //s|p1 +Object is a Node Set : +Set contains 4 nodes: +1 ELEMENT s + ATTRIBUTE p + TEXT + content=root +2 ELEMENT p1 +3 ELEMENT s + ATTRIBUTE p + TEXT + content=p1 +4 ELEMENT s + ATTRIBUTE p + TEXT + content=p2 + +======================== +Expression: p1|//s +Object is a Node Set : +Set contains 4 nodes: +1 ELEMENT s + ATTRIBUTE p + TEXT + content=root +2 ELEMENT p1 +3 ELEMENT s + ATTRIBUTE p + TEXT + content=p1 +4 ELEMENT s + ATTRIBUTE p + TEXT + content=p2 diff --git a/test/XPath/docs/mixed b/test/XPath/docs/mixed new file mode 100644 index 00000000..3b457bc8 --- /dev/null +++ b/test/XPath/docs/mixed @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/XPath/tests/mixedpat b/test/XPath/tests/mixedpat new file mode 100644 index 00000000..c212f6cd --- /dev/null +++ b/test/XPath/tests/mixedpat @@ -0,0 +1,7 @@ +s +s|p1/s +s|/root/p1/s +/root/p1/s|s +//s +//s|p1 +p1|//s diff --git a/testapi.c b/testapi.c index f29996f2..eb621ef2 100644 --- a/testapi.c +++ b/testapi.c @@ -1053,6 +1053,21 @@ static void des_xmlElementTypeVal(int no ATTRIBUTE_UNUSED, xmlElementTypeVal val static void desret_xmlParserErrors(xmlParserErrors val ATTRIBUTE_UNUSED) { } +#ifdef LIBXML_PATTERN_ENABLED +#define gen_nb_xmlPatternFlags 4 +static xmlPatternFlags gen_xmlPatternFlags(int no, int nr ATTRIBUTE_UNUSED) { + if (no == 1) return(XML_PATTERN_DEFAULT); + if (no == 2) return(XML_PATTERN_XPATH); + if (no == 3) return(XML_PATTERN_XSFIELD); + if (no == 4) return(XML_PATTERN_XSSEL); + return(0); +} + +static void des_xmlPatternFlags(int no ATTRIBUTE_UNUSED, xmlPatternFlags val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { +} + +#endif + #ifdef LIBXML_SCHEMAS_ENABLED #define gen_nb_xmlSchemaValType 4 static xmlSchemaValType gen_xmlSchemaValType(int no, int nr ATTRIBUTE_UNUSED) { diff --git a/xpath.c b/xpath.c index 8ee08052..6dba2936 100644 --- a/xpath.c +++ b/xpath.c @@ -11322,7 +11322,8 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { } } - stream = xmlPatterncompile(str, dict, 0, &namespaces[0]); + stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, + &namespaces[0]); if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { comp = xmlXPathNewCompExpr(); if (comp == NULL) {