diff options
author | Mike Hommey <glandium@debian.org> | 2006-01-06 18:28:17 +0100 |
---|---|---|
committer | Mike Hommey <glandium@debian.org> | 2006-01-06 18:28:17 +0100 |
commit | 0fd83af441e251fc23fc1af7959fd6ecfa105fe1 (patch) | |
tree | a2b35749a66abce02e6f07983ef50618d93bef58 /pattern.c | |
parent | 17049f05f9ef09b3dc2a9c5d1de3f21de7c03193 (diff) | |
download | libxml2-0fd83af441e251fc23fc1af7959fd6ecfa105fe1.tar.gz |
Load /tmp/tmp.U9vXwU/libxml2-2.6.23 intoupstream/2.6.23
local/libxml2/branches/upstream/current.
Diffstat (limited to 'pattern.c')
-rw-r--r-- | pattern.c | 517 |
1 files changed, 435 insertions, 82 deletions
@@ -46,26 +46,43 @@ #define XML_STREAM_STEP_FINAL 2 #define XML_STREAM_STEP_ROOT 4 #define XML_STREAM_STEP_ATTR 8 +#define XML_STREAM_STEP_NODE 16 +#define XML_STREAM_STEP_IN_SET 32 /* -* TODO: This is used on _xmlStreamCtxt, so don't use any values -* from xmlPatternFlags. +* NOTE: Those private flags (XML_STREAM_xxx) are used +* in _xmlStreamCtxt->flag. They extend the public +* xmlPatternFlags, so be carefull not to interfere with the +* reserved values for xmlPatternFlags. */ +#define XML_STREAM_FINAL_IS_ANY_NODE 1<<14 +#define XML_STREAM_FROM_ROOT 1<<15 #define XML_STREAM_DESC 1<<16 +/* +* XML_STREAM_ANY_NODE is used for comparison against +* xmlElementType enums, to indicate a node of any type. +*/ +#define XML_STREAM_ANY_NODE 100 + #define XML_PATTERN_NOTPATTERN (XML_PATTERN_XPATH | \ XML_PATTERN_XSSEL | \ XML_PATTERN_XSFIELD) -#define XML_STREAM_XS_IDC(item) (item->flags & \ +#define XML_STREAM_XS_IDC(c) ((c)->flags & \ (XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD)) +#define XML_STREAM_XS_IDC_SEL(c) ((c)->flags & XML_PATTERN_XSSEL) + +#define XML_STREAM_XS_IDC_FIELD(c) ((c)->flags & XML_PATTERN_XSFIELD) + typedef struct _xmlStreamStep xmlStreamStep; typedef xmlStreamStep *xmlStreamStepPtr; struct _xmlStreamStep { int flags; /* properties of that step */ const xmlChar *name; /* first string value if NULL accept all */ const xmlChar *ns; /* second string value */ + int nodeType; /* type of node */ }; typedef struct _xmlStreamComp xmlStreamComp; @@ -690,6 +707,7 @@ rollback: #define CUR (*ctxt->cur) #define SKIP(val) ctxt->cur += (val) #define NXT(val) ctxt->cur[(val)] +#define PEEKPREV(val) ctxt->cur[-(val)] #define CUR_PTR ctxt->cur #define SKIP_BLANKS \ @@ -884,6 +902,7 @@ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) { xmlChar *name = NULL; xmlChar *URL = NULL; + SKIP_BLANKS; name = xmlPatScanNCName(ctxt); if (name == NULL) { if (CUR == '*') { @@ -901,6 +920,13 @@ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) { xmlChar *prefix = name; NEXT; + + if (IS_BLANK_CH(CUR)) { + ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL); + xmlFree(prefix); + ctxt->error = 1; + goto error; + } /* * This is a namespace match */ @@ -967,25 +993,39 @@ xmlCompileStepPattern(xmlPatParserContextPtr ctxt) { xmlChar *token = NULL; xmlChar *name = NULL; xmlChar *URL = NULL; + int hasBlanks = 0; SKIP_BLANKS; if (CUR == '.') { + /* + * Context node. + */ NEXT; PUSH(XML_OP_ELEM, NULL, NULL); return; } + if (CUR == '@') { + /* + * Attribute test. + */ + if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) { + ERROR5(NULL, NULL, NULL, + "Unexpected attribute axis in '%s'.\n", ctxt->base); + ctxt->error = 1; + return; + } + NEXT; + xmlCompileAttributeTest(ctxt); + if (ctxt->error != 0) + goto error; + return; + } name = xmlPatScanNCName(ctxt); if (name == NULL) { if (CUR == '*') { NEXT; PUSH(XML_OP_ALL, NULL, NULL); return; - } else if (CUR == '@') { - NEXT; - xmlCompileAttributeTest(ctxt); - if (ctxt->error != 0) - goto error; - return; } else { ERROR(NULL, NULL, NULL, "xmlCompileStepPattern : Name expected\n"); @@ -993,13 +1033,21 @@ xmlCompileStepPattern(xmlPatParserContextPtr ctxt) { return; } } - SKIP_BLANKS; + if (IS_BLANK_CH(CUR)) { + hasBlanks = 1; + SKIP_BLANKS; + } if (CUR == ':') { NEXT; if (CUR != ':') { xmlChar *prefix = name; - int i; + int i; + if (hasBlanks || IS_BLANK_CH(CUR)) { + ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL); + ctxt->error = 1; + goto error; + } /* * This is a namespace match */ @@ -1060,6 +1108,11 @@ xmlCompileStepPattern(xmlPatParserContextPtr ctxt) { int i; NEXT; + if (IS_BLANK_CH(CUR)) { + ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL); + ctxt->error = 1; + goto error; + } /* * This is a namespace match */ @@ -1104,13 +1157,19 @@ xmlCompileStepPattern(xmlPatParserContextPtr ctxt) { } else if (xmlStrEqual(name, (const xmlChar *) "attribute")) { xmlFree(name); name = NULL; + if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) { + ERROR5(NULL, NULL, NULL, + "Unexpected attribute axis in '%s'.\n", ctxt->base); + ctxt->error = 1; + goto error; + } xmlCompileAttributeTest(ctxt); if (ctxt->error != 0) goto error; return; } else { - ERROR(NULL, NULL, NULL, - "xmlCompileStepPattern : 'child' or 'attribute' expected\n"); + ERROR5(NULL, NULL, NULL, + "The 'element' or 'attribute' axis is expected.\n", NULL); ctxt->error = 1; goto error; } @@ -1167,20 +1226,41 @@ xmlCompilePathPattern(xmlPatParserContextPtr ctxt) { NEXT; NEXT; NEXT; + /* Check for incompleteness. */ + SKIP_BLANKS; + if (CUR == 0) { + ERROR5(NULL, NULL, NULL, + "Incomplete expression '%s'.\n", ctxt->base); + ctxt->error = 1; + goto error; + } } if (CUR == '@') { NEXT; xmlCompileAttributeTest(ctxt); SKIP_BLANKS; + /* TODO: check for incompleteness */ if (CUR != 0) { xmlCompileStepPattern(ctxt); + if (ctxt->error != 0) + goto error; } } else { if (CUR == '/') { PUSH(XML_OP_ROOT, NULL, NULL); NEXT; + /* Check for incompleteness. */ + SKIP_BLANKS; + if (CUR == 0) { + ERROR5(NULL, NULL, NULL, + "Incomplete expression '%s'.\n", ctxt->base); + ctxt->error = 1; + goto error; + } } xmlCompileStepPattern(ctxt); + if (ctxt->error != 0) + goto error; SKIP_BLANKS; while (CUR == '/') { if (NXT(1) == '/') { @@ -1189,13 +1269,21 @@ xmlCompilePathPattern(xmlPatParserContextPtr ctxt) { NEXT; SKIP_BLANKS; xmlCompileStepPattern(ctxt); + if (ctxt->error != 0) + goto error; } else { PUSH(XML_OP_PARENT, NULL, NULL); NEXT; SKIP_BLANKS; - if (CUR != 0) { - xmlCompileStepPattern(ctxt); + if (CUR == 0) { + ERROR5(NULL, NULL, NULL, + "Incomplete expression '%s'.\n", ctxt->base); + ctxt->error = 1; + goto error; } + xmlCompileStepPattern(ctxt); + if (ctxt->error != 0) + goto error; } } } @@ -1208,6 +1296,107 @@ error: return; } +/** + * xmlCompileIDCXPathPath: + * @ctxt: the compilation context + * + * Compile the Path Pattern and generates a precompiled + * form suitable for fast matching. + * + * [5] Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest ) + */ +static void +xmlCompileIDCXPathPath(xmlPatParserContextPtr ctxt) { + SKIP_BLANKS; + if (CUR == '/') { + ERROR5(NULL, NULL, NULL, + "Unexpected selection of the document root in '%s'.\n", + ctxt->base); + goto error; + } + ctxt->comp->flags |= PAT_FROM_CUR; + + if (CUR == '.') { + /* "." - "self::node()" */ + NEXT; + SKIP_BLANKS; + if (CUR == 0) { + /* + * Selection of the context node. + */ + PUSH(XML_OP_ELEM, NULL, NULL); + return; + } + if (CUR != '/') { + /* TODO: A more meaningful error message. */ + ERROR5(NULL, NULL, NULL, + "Unexpected token after '.' in '%s'.\n", ctxt->base); + goto error; + } + /* "./" - "self::node()/" */ + NEXT; + SKIP_BLANKS; + if (CUR == '/') { + if (IS_BLANK_CH(PEEKPREV(1))) { + /* + * Disallow "./ /" + */ + ERROR5(NULL, NULL, NULL, + "Unexpected '/' token in '%s'.\n", ctxt->base); + goto error; + } + /* ".//" - "self:node()/descendant-or-self::node()/" */ + PUSH(XML_OP_ANCESTOR, NULL, NULL); + NEXT; + SKIP_BLANKS; + } + if (CUR == 0) + goto error_unfinished; + } + /* + * Process steps. + */ + do { + xmlCompileStepPattern(ctxt); + if (ctxt->error != 0) + goto error; + SKIP_BLANKS; + if (CUR != '/') + break; + PUSH(XML_OP_PARENT, NULL, NULL); + NEXT; + SKIP_BLANKS; + if (CUR == '/') { + /* + * Disallow subsequent '//'. + */ + ERROR5(NULL, NULL, NULL, + "Unexpected subsequent '//' in '%s'.\n", + ctxt->base); + goto error; + } + if (CUR == 0) + goto error_unfinished; + + } while (CUR != 0); + + if (CUR != 0) { + ERROR5(NULL, NULL, NULL, + "Failed to compile expression '%s'.\n", ctxt->base); + ctxt->error = 1; + } + return; +error: + ctxt->error = 1; + return; + +error_unfinished: + ctxt->error = 1; + ERROR5(NULL, NULL, NULL, + "Unfinished expression '%s'.\n", ctxt->base); + return; +} + /************************************************************************ * * * The streaming code * @@ -1334,7 +1523,7 @@ xmlFreeStreamComp(xmlStreamCompPtr comp) { */ static int xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name, - const xmlChar *ns, int flags) { + const xmlChar *ns, int nodeType, int flags) { xmlStreamStepPtr cur; if (comp->nbStep >= comp->maxStep) { @@ -1352,6 +1541,7 @@ xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name, cur->flags = flags; cur->name = name; cur->ns = ns; + cur->nodeType = nodeType; return(comp->nbStep - 1); } @@ -1366,7 +1556,8 @@ xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name, static int xmlStreamCompile(xmlPatternPtr comp) { xmlStreamCompPtr stream; - int i, s = 0, root = 0, flags = 0; + int i, s = 0, root = 0, flags = 0, prevs = -1; + xmlStepOp step; if ((comp == NULL) || (comp->steps == NULL)) return(-1); @@ -1380,6 +1571,8 @@ xmlStreamCompile(xmlPatternPtr comp) { stream = xmlNewStreamComp(0); if (stream == NULL) return(-1); + /* Note that the stream will have no steps in this case. */ + stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE; comp->stream = stream; return(0); } @@ -1392,19 +1585,13 @@ xmlStreamCompile(xmlPatternPtr comp) { xmlDictReference(stream->dict); } - /* - * Skip leading ./ on relative paths - */ - i = 0; - while ((comp->flags & PAT_FROM_CUR) && (comp->nbStep > i + 2) && - (comp->steps[i].op == XML_OP_ELEM) && - (comp->steps[i].value == NULL) && - (comp->steps[i].value2 == NULL) && - (comp->steps[i + 1].op == XML_OP_PARENT)) { - i += 2; - } + i = 0; + if (comp->flags & PAT_FROM_ROOT) + stream->flags |= XML_STREAM_FROM_ROOT; + for (;i < comp->nbStep;i++) { - switch (comp->steps[i].op) { + step = comp->steps[i]; + switch (step.op) { case XML_OP_END: break; case XML_OP_ROOT: @@ -1413,51 +1600,95 @@ xmlStreamCompile(xmlPatternPtr comp) { root = 1; break; case XML_OP_NS: - s = xmlStreamCompAddStep(stream, NULL, - comp->steps[i].value, flags); - flags = 0; + s = xmlStreamCompAddStep(stream, NULL, step.value, + XML_ELEMENT_NODE, flags); if (s < 0) goto error; + prevs = s; + flags = 0; break; case XML_OP_ATTR: flags |= XML_STREAM_STEP_ATTR; - s = xmlStreamCompAddStep(stream, comp->steps[i].value, - comp->steps[i].value2, flags); + prevs = -1; + s = xmlStreamCompAddStep(stream, + step.value, step.value2, XML_ATTRIBUTE_NODE, flags); flags = 0; if (s < 0) goto error; break; - case XML_OP_ELEM: - if ((comp->steps[i].value == NULL) && - (comp->steps[i].value2 == NULL) && - (comp->nbStep > i + 2) && - (comp->steps[i + 1].op == XML_OP_PARENT)) { - i++; - continue; - } + case XML_OP_ELEM: + if ((step.value == NULL) && (step.value2 == NULL)) { + /* + * We have a "." or "self::node()" here. + * Eliminate redundant self::node() tests like in "/./." + * or "//./" + * The only case we won't eliminate is "//.", i.e. if + * self::node() is the last node test and we had + * continuation somewhere beforehand. + */ + if ((comp->nbStep == i + 1) && + (flags & XML_STREAM_STEP_DESC)) { + /* + * Mark the special case where the expression resolves + * to any type of node. + */ + if (comp->nbStep == i + 1) { + stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE; + } + flags |= XML_STREAM_STEP_NODE; + s = xmlStreamCompAddStep(stream, NULL, NULL, + XML_STREAM_ANY_NODE, flags); + if (s < 0) + goto error; + flags = 0; + /* + * If there was a previous step, mark it to be added to + * the result node-set; this is needed since only + * the last step will be marked as "final" and only + * "final" nodes are added to the resulting set. + */ + if (prevs != -1) { + stream->steps[prevs].flags |= XML_STREAM_STEP_IN_SET; + prevs = -1; + } + break; + + } else { + /* Just skip this one. */ + continue; + } + } + /* An element node. */ + s = xmlStreamCompAddStep(stream, step.value, step.value2, + XML_ELEMENT_NODE, flags); + if (s < 0) + goto error; + prevs = s; + flags = 0; + break; case XML_OP_CHILD: - s = xmlStreamCompAddStep(stream, comp->steps[i].value, - comp->steps[i].value2, flags); - flags = 0; + /* An element node child. */ + s = xmlStreamCompAddStep(stream, step.value, step.value2, + XML_ELEMENT_NODE, flags); if (s < 0) goto error; + prevs = s; + flags = 0; break; case XML_OP_ALL: - s = xmlStreamCompAddStep(stream, NULL, NULL, flags); - flags = 0; + s = xmlStreamCompAddStep(stream, NULL, NULL, + XML_ELEMENT_NODE, flags); if (s < 0) goto error; + prevs = s; + flags = 0; break; - case XML_OP_PARENT: - if ((comp->nbStep > i + 1) && - (comp->steps[i + 1].op == XML_OP_ELEM) && - (comp->steps[i + 1].value == NULL) && - (comp->steps[i + 1].value2 == NULL)) { - i++; - continue; - } + case XML_OP_PARENT: break; case XML_OP_ANCESTOR: + /* Skip redundant continuations. */ + if (flags & XML_STREAM_STEP_DESC) + break; flags |= XML_STREAM_STEP_DESC; /* * Mark the expression as having "//". @@ -1481,6 +1712,8 @@ xmlStreamCompile(xmlPatternPtr comp) { stream->steps[0].flags |= XML_STREAM_STEP_DESC; } } + if (stream->nbStep <= s) + goto error; stream->steps[s].flags |= XML_STREAM_STEP_FINAL; if (root) stream->steps[0].flags |= XML_STREAM_STEP_ROOT; @@ -1603,7 +1836,7 @@ xmlStreamCtxtAddState(xmlStreamCtxtPtr comp, int idx, int level) { static int xmlStreamPushInternal(xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns, - xmlElementType nodeType) { + int nodeType) { int ret = 0, err = 0, final = 0, tmp, i, m, match, step, desc; xmlStreamCompPtr comp; #ifdef DEBUG_STREAMING @@ -1615,16 +1848,34 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, while (stream != NULL) { comp = stream->comp; - if ((name == NULL) && (ns == NULL)) { + + if ((nodeType == XML_ELEMENT_NODE) && + (name == NULL) && (ns == NULL)) { + /* We have a document node here (or a reset). */ stream->nbState = 0; stream->level = 0; stream->blockLevel = -1; - if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) { - tmp = xmlStreamCtxtAddState(stream, 0, 0); - if (tmp < 0) - err++; - if (comp->nbStep == 0) + if (comp->flags & XML_STREAM_FROM_ROOT) { + if (comp->nbStep == 0) { + /* TODO: We have a "/." here? */ ret = 1; + } else { + if ((comp->nbStep == 1) && + (comp->steps[0].nodeType == XML_STREAM_ANY_NODE) && + (comp->steps[0].flags & XML_STREAM_STEP_DESC)) + { + /* + * In the case of "//." the document node will match + * as well. + */ + ret = 1; + } else if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) { + /* TODO: Do we need this ? */ + tmp = xmlStreamCtxtAddState(stream, 0, 0); + if (tmp < 0) + err++; + } + } } stream = stream->next; continue; /* while */ @@ -1647,7 +1898,7 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, * or traditional XPath expressions, this will match if * we are at the first level only, otherwise on every level. */ - if ((nodeType == XML_ELEMENT_NODE) && + if ((nodeType != XML_ATTRIBUTE_NODE) && (((stream->flags & XML_PATTERN_NOTPATTERN) == 0) || (stream->level == 0))) { ret = 1; @@ -1662,6 +1913,19 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, stream->level++; goto stream_next; } + + if ((nodeType != XML_ELEMENT_NODE) && + (nodeType != XML_ATTRIBUTE_NODE) && + ((comp->flags & XML_STREAM_FINAL_IS_ANY_NODE) == 0)) { + /* + * No need to process nodes of other types if we don't + * resolve to those types. + * TODO: Do we need to block the context here? + */ + stream->level++; + goto stream_next; + } + /* * Check evolution of existing states */ @@ -1710,14 +1974,24 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, /* * Check for correct node-type. */ - if ((nodeType == XML_ATTRIBUTE_NODE) && - ((comp->steps[step].flags & XML_STREAM_STEP_ATTR) == 0)) - goto next_state; + if (comp->steps[step].nodeType != nodeType) { + if (comp->steps[step].nodeType == XML_ATTRIBUTE_NODE) { + /* + * Block this expression for deeper evaluation. + */ + if ((comp->flags & XML_STREAM_DESC) == 0) + stream->blockLevel = stream->level +1; + goto next_state; + } else if (comp->steps[step].nodeType != XML_STREAM_ANY_NODE) + goto next_state; + } /* * Compare local/namespace-name. */ match = 0; - if (comp->dict) { + if (comp->steps[step].nodeType == XML_STREAM_ANY_NODE) { + match = 1; + } else if (comp->dict) { if (comp->steps[step].name == NULL) { if (comp->steps[step].ns == NULL) match = 1; @@ -1756,7 +2030,15 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, stream->level + 1); } } - } + if ((ret != 1) && + (comp->steps[step].flags & XML_STREAM_STEP_IN_SET)) { + /* + * Check if we have a special case like "foo/bar//.", where + * "foo" is selected as well. + */ + ret = 1; + } + } if (((comp->flags & XML_STREAM_DESC) == 0) && ((! match) || final)) { /* @@ -1774,6 +2056,8 @@ next_state: /* * Re/enter the expression. + * Don't reenter if it's an absolute expression like "/foo", + * except "//foo". */ if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) goto stream_next; @@ -1816,14 +2100,19 @@ compare: /* * Check expected node-type. */ - if ((nodeType == XML_ATTRIBUTE_NODE) && - ((comp->steps[0].flags & XML_STREAM_STEP_ATTR) == 0)) - goto stream_next; + if (comp->steps[0].nodeType != nodeType) { + if (nodeType == XML_ATTRIBUTE_NODE) + goto stream_next; + else if (comp->steps[0].nodeType != XML_STREAM_ANY_NODE) + goto stream_next; + } /* * Compare local/namespace-name. */ match = 0; - if (comp->steps[0].name == NULL) { + if (comp->steps[0].nodeType == XML_STREAM_ANY_NODE) { + match = 1; + } else if (comp->steps[0].name == NULL) { if (comp->steps[0].ns == NULL) match = 1; else { @@ -1840,12 +2129,20 @@ compare: match = ((xmlStrEqual(comp->steps[0].name, name)) && (xmlStrEqual(comp->steps[0].ns, ns))); } - if (match) { - final = comp->steps[0].flags & XML_STREAM_STEP_FINAL; + final = comp->steps[0].flags & XML_STREAM_STEP_FINAL; + if (match) { if (final) ret = 1; else xmlStreamCtxtAddState(stream, 1, stream->level); + if ((ret != 1) && + (comp->steps[0].flags & XML_STREAM_STEP_IN_SET)) { + /* + * Check if we have a special case like "foo//.", where + * "foo" is selected as well. + */ + ret = 1; + } } if (((comp->flags & XML_STREAM_DESC) == 0) && ((! match) || final)) { @@ -1855,7 +2152,7 @@ compare: */ stream->blockLevel = stream->level; } - + stream_next: stream = stream->next; } /* while stream != NULL */ @@ -1879,6 +2176,7 @@ stream_next: * to come from the dictionary. * Both @name and @ns being NULL means the / i.e. the root of the document. * This can also act as a reset. + * Otherwise the function will act as if it has been given an element-node. * * Returns: -1 in case of error, 1 if the current state in the stream is a * match and 0 otherwise. @@ -1886,7 +2184,35 @@ stream_next: int xmlStreamPush(xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns) { - return (xmlStreamPushInternal(stream, name, ns, XML_ELEMENT_NODE)); + return (xmlStreamPushInternal(stream, name, ns, (int) XML_ELEMENT_NODE)); +} + +/** + * xmlStreamPushNode: + * @stream: the stream context + * @name: the current name + * @ns: the namespace name + * @nodeType: the type of the node being pushed + * + * Push new data onto the stream. NOTE: if the call xmlPatterncompile() + * indicated a dictionary, then strings for name and ns will be expected + * to come from the dictionary. + * Both @name and @ns being NULL means the / i.e. the root of the document. + * This can also act as a reset. + * Different from xmlStreamPush() this function can be fed with nodes of type: + * element-, attribute-, text-, cdata-section-, comment- and + * processing-instruction-node. + * + * Returns: -1 in case of error, 1 if the current state in the stream is a + * match and 0 otherwise. + */ +int +xmlStreamPushNode(xmlStreamCtxtPtr stream, + const xmlChar *name, const xmlChar *ns, + int nodeType) +{ + return (xmlStreamPushInternal(stream, name, ns, + nodeType)); } /** @@ -1900,6 +2226,7 @@ xmlStreamPush(xmlStreamCtxtPtr stream, * to come from the dictionary. * Both @name and @ns being NULL means the / i.e. the root of the document. * This can also act as a reset. +* Otherwise the function will act as if it has been given an attribute-node. * * Returns: -1 in case of error, 1 if the current state in the stream is a * match and 0 otherwise. @@ -1907,7 +2234,7 @@ xmlStreamPush(xmlStreamCtxtPtr stream, int xmlStreamPushAttr(xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns) { - return (xmlStreamPushInternal(stream, name, ns, XML_ATTRIBUTE_NODE)); + return (xmlStreamPushInternal(stream, name, ns, (int) XML_ATTRIBUTE_NODE)); } /** @@ -1921,11 +2248,9 @@ xmlStreamPushAttr(xmlStreamCtxtPtr stream, int xmlStreamPop(xmlStreamCtxtPtr stream) { int i, lev; - int ret; - + if (stream == NULL) return(-1); - ret = 0; while (stream != NULL) { /* * Reset block-level. @@ -1935,7 +2260,7 @@ xmlStreamPop(xmlStreamCtxtPtr stream) { stream->level--; if (stream->level < 0) - ret = -1; + return(-1); /* * Check evolution of existing states */ @@ -1952,6 +2277,31 @@ xmlStreamPop(xmlStreamCtxtPtr stream) { return(0); } +/** + * xmlStreamWantsAnyNode: + * @streamCtxt: the stream context + * + * Query if the streaming pattern additionally needs to be fed with + * text-, cdata-section-, comment- and processing-instruction-nodes. + * If the result is 0 then only element-nodes and attribute-nodes + * need to be pushed. + * + * Returns: 1 in case of need of nodes of the above described types, + * 0 otherwise. -1 on API errors. + */ +int +xmlStreamWantsAnyNode(xmlStreamCtxtPtr streamCtxt) +{ + if (streamCtxt == NULL) + return(-1); + while (streamCtxt != NULL) { + if (streamCtxt->comp->flags & XML_STREAM_FINAL_IS_ANY_NODE) + return(1); + streamCtxt = streamCtxt->next; + } + return(0); +} + /************************************************************************ * * * The public interfaces * @@ -2008,7 +2358,10 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, cur->flags = flags; ctxt->comp = cur; - xmlCompilePathPattern(ctxt); + if (XML_STREAM_XS_IDC(cur)) + xmlCompileIDCXPathPath(ctxt); + else + xmlCompilePathPattern(ctxt); if (ctxt->error != 0) goto error; xmlFreePatParserContext(ctxt); |