allows to compile and test pattern expressions for nodes either in a tree or based on a parser state. Table of ContentsStructure 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 struct _xmlPattern {
The content of this structure is not made public by the API.
-} Structure xmlStreamCtxt struct _xmlStreamCtxt {
+} 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 struct _xmlStreamCtxt {
The content of this structure is not made public by the API.
} Function: xmlFreePatternvoid 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: xmlPatternStreamableint 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: xmlPatterncompilexmlPatternPtr 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: xmlPatterncompilexmlPatternPtr 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: xmlStreamPopint 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) {
|