📄 pattern.c
字号:
if (stream->blockLevel != -1) {
/*
* Skip blocked expressions.
*/
stream->level++;
goto stream_next;
}
/*
* Check evolution of existing states
*/
i = 0;
m = stream->nbState;
while (i < m) {
if ((comp->flags & XML_STREAM_DESC) == 0) {
/*
* If there is no "//", then only the last
* added state is of interest.
*/
step = stream->states[2 * (stream->nbState -1)];
/*
* TODO: Security check, should not happen, remove it.
*/
if (stream->states[(2 * (stream->nbState -1)) + 1] <
stream->level) {
return (-1);
}
desc = 0;
/* loop-stopper */
i = m;
} else {
/*
* If there are "//", then we need to process every "//"
* occuring in the states, plus any other state for this
* level.
*/
step = stream->states[2 * i];
/* TODO: should not happen anymore: dead states */
if (step < 0)
goto next_state;
tmp = stream->states[(2 * i) + 1];
/* skip new states just added */
if (tmp > stream->level)
goto next_state;
/* skip states at ancestor levels, except if "//" */
desc = comp->steps[step].flags & XML_STREAM_STEP_DESC;
if ((tmp < stream->level) && (!desc))
goto next_state;
}
/*
* Check for correct node-type.
*/
if ((nodeType == XML_ATTRIBUTE_NODE) &&
((comp->steps[step].flags & XML_STREAM_STEP_ATTR) == 0))
goto next_state;
/*
* Compare local/namespace-name.
*/
match = 0;
if (comp->dict) {
if (comp->steps[step].name == NULL) {
if (comp->steps[step].ns == NULL)
match = 1;
else
match = (comp->steps[step].ns == ns);
} else {
match = ((comp->steps[step].name == name) &&
(comp->steps[step].ns == ns));
}
} else {
if (comp->steps[step].name == NULL) {
if (comp->steps[step].ns == NULL)
match = 1;
else
match = xmlStrEqual(comp->steps[step].ns, ns);
} else {
match = ((xmlStrEqual(comp->steps[step].name, name)) &&
(xmlStrEqual(comp->steps[step].ns, ns)));
}
}
if (match) {
final = comp->steps[step].flags & XML_STREAM_STEP_FINAL;
if (desc) {
if (final) {
ret = 1;
} else {
/* descending match create a new state */
xmlStreamCtxtAddState(stream, step + 1,
stream->level + 1);
}
} else {
if (final) {
ret = 1;
} else {
xmlStreamCtxtAddState(stream, step + 1,
stream->level + 1);
}
}
}
if (((comp->flags & XML_STREAM_DESC) == 0) &&
((! match) || final)) {
/*
* Mark this expression as blocked for any evaluation at
* deeper levels. Note that this includes "/foo"
* expressions if the *pattern* behaviour is used.
*/
stream->blockLevel = stream->level +1;
}
next_state:
i++;
}
stream->level++;
/*
* Re/enter the expression.
*/
if (comp->steps[0].flags & XML_STREAM_STEP_ROOT)
goto stream_next;
desc = comp->steps[0].flags & XML_STREAM_STEP_DESC;
if (stream->flags & XML_PATTERN_NOTPATTERN) {
/*
* Re/enter the expression if it is a "descendant" one,
* or if we are at the 1st level of evaluation.
*/
if (stream->level == 1) {
if (XML_STREAM_XS_IDC(stream)) {
/*
* XS-IDC: The missing "self::node()" will always
* match the first given node.
*/
goto stream_next;
} else
goto compare;
}
/*
* A "//" is always reentrant.
*/
if (desc)
goto compare;
/*
* XS-IDC: Process the 2nd level, since the missing
* "self::node()" is responsible for the 2nd level being
* the real start level.
*/
if ((stream->level == 2) && XML_STREAM_XS_IDC(stream))
goto compare;
goto stream_next;
}
compare:
/*
* Check expected node-type.
*/
if ((nodeType == XML_ATTRIBUTE_NODE) &&
((comp->steps[0].flags & XML_STREAM_STEP_ATTR) == 0))
goto stream_next;
/*
* Compare local/namespace-name.
*/
match = 0;
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
match = xmlStrEqual(comp->steps[0].ns, ns);
}
} else {
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)));
}
if (match) {
final = comp->steps[0].flags & XML_STREAM_STEP_FINAL;
if (final)
ret = 1;
else
xmlStreamCtxtAddState(stream, 1, stream->level);
}
if (((comp->flags & XML_STREAM_DESC) == 0) &&
((! match) || final)) {
/*
* Mark this expression as blocked for any evaluation at
* deeper levels.
*/
stream->blockLevel = stream->level;
}
stream_next:
stream = stream->next;
} /* while stream != NULL */
if (err > 0)
ret = -1;
#ifdef DEBUG_STREAMING
xmlDebugStreamCtxt(orig, ret);
#endif
return(ret);
}
/**
* xmlStreamPush:
* @stream: the stream context
* @name: the current name
* @ns: the namespace name
*
* 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.
*
* Returns: -1 in case of error, 1 if the current state in the stream is a
* match and 0 otherwise.
*/
int
xmlStreamPush(xmlStreamCtxtPtr stream,
const xmlChar *name, const xmlChar *ns) {
return (xmlStreamPushInternal(stream, name, ns, XML_ELEMENT_NODE));
}
/**
* xmlStreamPushAttr:
* @stream: the stream context
* @name: the current name
* @ns: the namespace name
*
* Push new attribute 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.
*
* Returns: -1 in case of error, 1 if the current state in the stream is a
* match and 0 otherwise.
*/
int
xmlStreamPushAttr(xmlStreamCtxtPtr stream,
const xmlChar *name, const xmlChar *ns) {
return (xmlStreamPushInternal(stream, name, ns, XML_ATTRIBUTE_NODE));
}
/**
* xmlStreamPop:
* @stream: the stream context
*
* push one level from the stream.
*
* Returns: -1 in case of error, 0 otherwise.
*/
int
xmlStreamPop(xmlStreamCtxtPtr stream) {
int i, lev;
int ret;
if (stream == NULL)
return(-1);
ret = 0;
while (stream != NULL) {
/*
* Reset block-level.
*/
if (stream->blockLevel == stream->level)
stream->blockLevel = -1;
stream->level--;
if (stream->level < 0)
ret = -1;
/*
* Check evolution of existing states
*/
for (i = stream->nbState -1; i >= 0; i--) {
/* discard obsoleted states */
lev = stream->states[(2 * i) + 1];
if (lev > stream->level)
stream->nbState--;
if (lev <= stream->level)
break;
}
stream = stream->next;
}
return(0);
}
/************************************************************************
* *
* The public interfaces *
* *
************************************************************************/
/**
* xmlPatterncompile:
* @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
*
* Compile a pattern.
*
* Returns the compiled form of the pattern or NULL in case of error
*/
xmlPatternPtr
xmlPatterncompile(const xmlChar *pattern, xmlDict *dict,
xmlPatternFlags flags,
const xmlChar **namespaces) {
xmlPatternPtr ret = NULL, cur;
xmlPatParserContextPtr ctxt = NULL;
const xmlChar *or, *start;
xmlChar *tmp = NULL;
int type = 0;
int streamable = 1;
if (pattern == NULL)
return(NULL);
start = pattern;
or = start;
while (*or != 0) {
tmp = NULL;
while ((*or != 0) && (*or != '|')) or++;
if (*or == 0)
ctxt = xmlNewPatParserContext(start, dict, namespaces);
else {
tmp = xmlStrndup(start, or - start);
if (tmp != NULL) {
ctxt = xmlNewPatParserContext(tmp, dict, namespaces);
}
or++;
}
if (ctxt == NULL) goto error;
cur = xmlNewPattern();
if (cur == NULL) goto error;
if (ret == NULL)
ret = cur;
else {
cur->next = ret->next;
ret->next = cur;
}
cur->flags = flags;
ctxt->comp = cur;
xmlCompilePathPattern(ctxt);
if (ctxt->error != 0)
goto error;
xmlFreePatParserContext(ctxt);
ctxt = NULL;
if (streamable) {
if (type == 0) {
type = cur->flags & (PAT_FROM_ROOT | PAT_FROM_CUR);
} else if (type == PAT_FROM_ROOT) {
if (cur->flags & PAT_FROM_CUR)
streamable = 0;
} else if (type == PAT_FROM_CUR) {
if (cur->flags & PAT_FROM_ROOT)
streamable = 0;
}
}
if (streamable)
xmlStreamCompile(cur);
if (xmlReversePattern(cur) < 0)
goto error;
if (tmp != NULL) {
xmlFree(tmp);
tmp = NULL;
}
start = or;
}
if (streamable == 0) {
cur = ret;
while (cur != NULL) {
if (cur->stream != NULL) {
xmlFreeStreamComp(cur->stream);
cur->stream = NULL;
}
cur = cur->next;
}
}
return(ret);
error:
if (ctxt != NULL) xmlFreePatParserContext(ctxt);
if (ret != NULL) xmlFreePattern(ret);
if (tmp != NULL) xmlFree(tmp);
return(NULL);
}
/**
* xmlPatternMatch:
* @comp: the precompiled pattern
* @node: a node
*
* Test whether the node matches the pattern
*
* Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
*/
int
xmlPatternMatch(xmlPatternPtr comp, xmlNodePtr node)
{
int ret = 0;
if ((comp == NULL) || (node == NULL))
return(-1);
while (comp != NULL) {
ret = xmlPatMatch(comp, node);
if (ret != 0)
return(ret);
comp = comp->next;
}
return(ret);
}
/**
* xmlPatternGetStreamCtxt:
* @comp: the precompiled pattern
*
* Get a streaming context for that pattern
* Use xmlFreeStreamCtxt to free the context.
*
* Returns a pointer to the context or NULL in case of failure
*/
xmlStreamCtxtPtr
xmlPatternGetStreamCtxt(xmlPatternPtr comp)
{
xmlStreamCtxtPtr ret = NULL, cur;
if ((comp == NULL) || (comp->stream == NULL))
return(NULL);
while (comp != NULL) {
if (comp->stream == NULL)
goto failed;
cur = xmlNewStreamCtxt(comp->stream);
if (cur == NULL)
goto failed;
if (ret == NULL)
ret = cur;
else {
cur->next = ret->next;
ret->next = cur;
}
cur->flags = comp->flags;
comp = comp->next;
}
return(ret);
failed:
xmlFreeStreamCtxt(ret);
return(NULL);
}
/**
* xmlPatternStreamable:
* @comp: the precompiled pattern
*
* Check if the pattern is streamable i.e. xmlPatternGetStreamCtxt()
* should work.
*
* Returns 1 if streamable, 0 if not and -1 in case of error.
*/
int
xmlPatternStreamable(xmlPatternPtr comp) {
if (comp == NULL)
return(-1);
while (comp != NULL) {
if (comp->stream == NULL)
return(0);
comp = comp->next;
}
return(1);
}
/**
* xmlPatternMaxDepth:
* @comp: the precompiled pattern
*
* Check the maximum depth reachable by a pattern
*
* Returns -2 if no limit (using //), otherwise the depth,
* and -1 in case of error
*/
int
xmlPatternMaxDepth(xmlPatternPtr comp) {
int ret = 0, i;
if (comp == NULL)
return(-1);
while (comp != NULL) {
if (comp->stream == NULL)
return(-1);
for (i = 0;i < comp->stream->nbStep;i++)
if (comp->stream->steps[i].flags & XML_STREAM_STEP_DESC)
return(-2);
if (comp->stream->nbStep > ret)
ret = comp->stream->nbStep;
comp = comp->next;
}
return(ret);
}
/**
* xmlPatternFromRoot:
* @comp: the precompiled pattern
*
* Check if the pattern must be looked at from the root.
*
* Returns 1 if true, 0 if false and -1 in case of error
*/
int
xmlPatternFromRoot(xmlPatternPtr comp) {
if (comp == NULL)
return(-1);
while (comp != NULL) {
if (comp->stream == NULL)
return(-1);
if (comp->flags & PAT_FROM_ROOT)
return(1);
comp = comp->next;
}
return(0);
}
#define bottom_pattern
#include "elfgcchack.h"
#endif /* LIBXML_PATTERN_ENABLED */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -