📄 pattern.c
字号:
if (step->value != NULL) {
if (step->value[0] != node->name[0])
goto rollback;
if (!xmlStrEqual(step->value, node->name))
goto rollback;
}
/* Namespace test */
if (node->ns == NULL) {
if (step->value2 != NULL)
goto rollback;
} else if (step->value2 != NULL) {
if (!xmlStrEqual(step->value2, node->ns->href))
goto rollback;
}
continue;
case XML_OP_PARENT:
if ((node->type == XML_DOCUMENT_NODE) ||
(node->type == XML_HTML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
(node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
(node->type == XML_NAMESPACE_DECL))
goto rollback;
node = node->parent;
if (node == NULL)
goto rollback;
if (step->value == NULL)
continue;
if (step->value[0] != node->name[0])
goto rollback;
if (!xmlStrEqual(step->value, node->name))
goto rollback;
/* Namespace test */
if (node->ns == NULL) {
if (step->value2 != NULL)
goto rollback;
} else if (node->ns->href != NULL) {
if (step->value2 == NULL)
goto rollback;
if (!xmlStrEqual(step->value2, node->ns->href))
goto rollback;
}
continue;
case XML_OP_ANCESTOR:
/* TODO: implement coalescing of ANCESTOR/NODE ops */
if (step->value == NULL) {
i++;
step = &comp->steps[i];
if (step->op == XML_OP_ROOT)
goto found;
if (step->op != XML_OP_ELEM)
goto rollback;
if (step->value == NULL)
return(-1);
}
if (node == NULL)
goto rollback;
if ((node->type == XML_DOCUMENT_NODE) ||
(node->type == XML_HTML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
(node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
(node->type == XML_NAMESPACE_DECL))
goto rollback;
node = node->parent;
while (node != NULL) {
if (node == NULL)
goto rollback;
if ((node->type == XML_ELEMENT_NODE) &&
(step->value[0] == node->name[0]) &&
(xmlStrEqual(step->value, node->name))) {
/* Namespace test */
if (node->ns == NULL) {
if (step->value2 == NULL)
break;
} else if (node->ns->href != NULL) {
if ((step->value2 != NULL) &&
(xmlStrEqual(step->value2, node->ns->href)))
break;
}
}
node = node->parent;
}
if (node == NULL)
goto rollback;
/*
* prepare a potential rollback from here
* for ancestors of that node.
*/
if (step->op == XML_OP_ANCESTOR)
xmlPatPushState(&states, i, node);
else
xmlPatPushState(&states, i - 1, node);
continue;
case XML_OP_NS:
if (node->type != XML_ELEMENT_NODE)
goto rollback;
if (node->ns == NULL) {
if (step->value != NULL)
goto rollback;
} else if (node->ns->href != NULL) {
if (step->value == NULL)
goto rollback;
if (!xmlStrEqual(step->value, node->ns->href))
goto rollback;
}
break;
case XML_OP_ALL:
if (node->type != XML_ELEMENT_NODE)
goto rollback;
break;
}
}
found:
if (states.states != NULL) {
/* Free the rollback states */
xmlFree(states.states);
}
return(1);
rollback:
/* got an error try to rollback */
if (states.states == NULL)
return(0);
if (states.nbstates <= 0) {
xmlFree(states.states);
return(0);
}
states.nbstates--;
i = states.states[states.nbstates].step;
node = states.states[states.nbstates].node;
#if 0
fprintf(stderr, "Pop: %d, %s\n", i, node->name);
#endif
goto restart;
}
/************************************************************************
* *
* Dedicated parser for templates *
* *
************************************************************************/
#define TODO \
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
#define CUR (*ctxt->cur)
#define SKIP(val) ctxt->cur += (val)
#define NXT(val) ctxt->cur[(val)]
#define CUR_PTR ctxt->cur
#define SKIP_BLANKS \
while (IS_BLANK_CH(CUR)) NEXT
#define CURRENT (*ctxt->cur)
#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
#define PUSH(op, val, val2) \
if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error;
#define XSLT_ERROR(X) \
{ xsltError(ctxt, __FILE__, __LINE__, X); \
ctxt->error = (X); return; }
#define XSLT_ERROR0(X) \
{ xsltError(ctxt, __FILE__, __LINE__, X); \
ctxt->error = (X); return(0); }
#if 0
/**
* xmlPatScanLiteral:
* @ctxt: the XPath Parser context
*
* Parse an XPath Litteral:
*
* [29] Literal ::= '"' [^"]* '"'
* | "'" [^']* "'"
*
* Returns the Literal parsed or NULL
*/
static xmlChar *
xmlPatScanLiteral(xmlPatParserContextPtr ctxt) {
const xmlChar *q, *cur;
xmlChar *ret = NULL;
int val, len;
SKIP_BLANKS;
if (CUR == '"') {
NEXT;
cur = q = CUR_PTR;
val = xmlStringCurrentChar(NULL, cur, &len);
while ((IS_CHAR(val)) && (val != '"')) {
cur += len;
val = xmlStringCurrentChar(NULL, cur, &len);
}
if (!IS_CHAR(val)) {
ctxt->error = 1;
return(NULL);
} else {
ret = xmlStrndup(q, cur - q);
}
cur += len;
CUR_PTR = cur;
} else if (CUR == '\'') {
NEXT;
cur = q = CUR_PTR;
val = xmlStringCurrentChar(NULL, cur, &len);
while ((IS_CHAR(val)) && (val != '\'')) {
cur += len;
val = xmlStringCurrentChar(NULL, cur, &len);
}
if (!IS_CHAR(val)) {
ctxt->error = 1;
return(NULL);
} else {
ret = xmlStrndup(q, cur - q);
}
cur += len;
CUR_PTR = cur;
} else {
/* XP_ERROR(XPATH_START_LITERAL_ERROR); */
ctxt->error = 1;
return(NULL);
}
return(ret);
}
#endif
/**
* xmlPatScanName:
* @ctxt: the XPath Parser context
*
* [4] NameChar ::= Letter | Digit | '.' | '-' | '_' |
* CombiningChar | Extender
*
* [5] Name ::= (Letter | '_' | ':') (NameChar)*
*
* [6] Names ::= Name (S Name)*
*
* Returns the Name parsed or NULL
*/
static xmlChar *
xmlPatScanName(xmlPatParserContextPtr ctxt) {
const xmlChar *q, *cur;
xmlChar *ret = NULL;
int val, len;
SKIP_BLANKS;
cur = q = CUR_PTR;
val = xmlStringCurrentChar(NULL, cur, &len);
if (!IS_LETTER(val) && (val != '_') && (val != ':'))
return(NULL);
while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
(val == '.') || (val == '-') ||
(val == '_') ||
(IS_COMBINING(val)) ||
(IS_EXTENDER(val))) {
cur += len;
val = xmlStringCurrentChar(NULL, cur, &len);
}
ret = xmlStrndup(q, cur - q);
CUR_PTR = cur;
return(ret);
}
/**
* xmlPatScanNCName:
* @ctxt: the XPath Parser context
*
* Parses a non qualified name
*
* Returns the Name parsed or NULL
*/
static xmlChar *
xmlPatScanNCName(xmlPatParserContextPtr ctxt) {
const xmlChar *q, *cur;
xmlChar *ret = NULL;
int val, len;
SKIP_BLANKS;
cur = q = CUR_PTR;
val = xmlStringCurrentChar(NULL, cur, &len);
if (!IS_LETTER(val) && (val != '_'))
return(NULL);
while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
(val == '.') || (val == '-') ||
(val == '_') ||
(IS_COMBINING(val)) ||
(IS_EXTENDER(val))) {
cur += len;
val = xmlStringCurrentChar(NULL, cur, &len);
}
ret = xmlStrndup(q, cur - q);
CUR_PTR = cur;
return(ret);
}
#if 0
/**
* xmlPatScanQName:
* @ctxt: the XPath Parser context
* @prefix: the place to store the prefix
*
* Parse a qualified name
*
* Returns the Name parsed or NULL
*/
static xmlChar *
xmlPatScanQName(xmlPatParserContextPtr ctxt, xmlChar **prefix) {
xmlChar *ret = NULL;
*prefix = NULL;
ret = xmlPatScanNCName(ctxt);
if (CUR == ':') {
*prefix = ret;
NEXT;
ret = xmlPatScanNCName(ctxt);
}
return(ret);
}
#endif
/**
* xmlCompileAttributeTest:
* @ctxt: the compilation context
*
* Compile an attribute test.
*/
static void
xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) {
xmlChar *token = NULL;
xmlChar *name = NULL;
xmlChar *URL = NULL;
name = xmlPatScanNCName(ctxt);
if (name == NULL) {
if (CUR == '*') {
PUSH(XML_OP_ATTR, NULL, NULL);
NEXT;
} else {
ERROR(NULL, NULL, NULL,
"xmlCompileAttributeTest : Name expected\n");
ctxt->error = 1;
}
return;
}
if (CUR == ':') {
int i;
xmlChar *prefix = name;
NEXT;
/*
* This is a namespace match
*/
token = xmlPatScanName(ctxt);
for (i = 0;i < ctxt->nb_namespaces;i++) {
if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
URL = xmlStrdup(ctxt->namespaces[2 * i]);
break;
}
}
if (i >= ctxt->nb_namespaces) {
ERROR5(NULL, NULL, NULL,
"xmlCompileAttributeTest : no namespace bound to prefix %s\n",
prefix);
ctxt->error = 1;
goto error;
}
xmlFree(prefix);
if (token == NULL) {
if (CUR == '*') {
NEXT;
PUSH(XML_OP_ATTR, NULL, URL);
} else {
ERROR(NULL, NULL, NULL,
"xmlCompileAttributeTest : Name expected\n");
ctxt->error = 1;
goto error;
}
} else {
PUSH(XML_OP_ATTR, token, URL);
}
} else {
PUSH(XML_OP_ATTR, name, NULL);
}
return;
error:
if (URL != NULL)
xmlFree(URL);
if (token != NULL)
xmlFree(token);
}
/**
* xmlCompileStepPattern:
* @ctxt: the compilation context
*
* Compile the Step Pattern and generates a precompiled
* form suitable for fast matching.
*
* [3] Step ::= '.' | NameTest
* [4] NameTest ::= QName | '*' | NCName ':' '*'
*/
static void
xmlCompileStepPattern(xmlPatParserContextPtr ctxt) {
xmlChar *token = NULL;
xmlChar *name = NULL;
xmlChar *URL = NULL;
SKIP_BLANKS;
if (CUR == '.') {
NEXT;
PUSH(XML_OP_ELEM, NULL, NULL);
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");
ctxt->error = 1;
return;
}
}
SKIP_BLANKS;
if (CUR == ':') {
NEXT;
if (CUR != ':') {
xmlChar *prefix = name;
int i;
/*
* This is a namespace match
*/
token = xmlPatScanName(ctxt);
for (i = 0;i < ctxt->nb_namespaces;i++) {
if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
URL = xmlStrdup(ctxt->namespaces[2 * i]);
break;
}
}
if (i >= ctxt->nb_namespaces) {
ERROR5(NULL, NULL, NULL,
"xmlCompileStepPattern : no namespace bound to prefix %s\n",
prefix);
ctxt->error = 1;
goto error;
}
xmlFree(prefix);
if (token == NULL) {
if (CUR == '*') {
NEXT;
PUSH(XML_OP_NS, URL, NULL);
} else {
ERROR(NULL, NULL, NULL,
"xmlCompileStepPattern : Name expected\n");
ctxt->error = 1;
goto error;
}
} else {
PUSH(XML_OP_ELEM, token, URL);
}
} else {
NEXT;
if (xmlStrEqual(name, (const xmlChar *) "child")) {
xmlFree(name);
name = xmlPatScanName(ctxt);
if (name == NULL) {
if (CUR == '*') {
NEXT;
PUSH(XML_OP_ALL, NULL, NULL);
return;
} else {
ERROR(NULL, NULL, NULL,
"xmlCompileStepPattern : QName expected\n");
ctxt->error = 1;
goto error;
}
}
if (CUR == ':') {
xmlChar *prefix = name;
int i;
NEXT;
/*
* This is a namespace match
*/
token = xmlPatScanName(ctxt);
for (i = 0;i < ctxt->nb_namespaces;i++) {
if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
URL = xmlStrdup(ctxt->namespaces[2 * i]);
break;
}
}
if (i >= ctxt->nb_namespaces) {
ERROR5(NULL, NULL, NULL,
"xmlCompileStepPattern : no namespace bound "
"to prefix %s\n", prefix);
ctxt->error = 1;
goto error;
}
xmlFree(prefix);
if (token == NULL) {
if (CUR == '*') {
NEXT;
PUSH(XML_OP_NS, URL, NULL);
} else {
ERROR(NULL, NULL, NULL,
"xmlCompileStepPattern : Name expected\n");
ctxt->error = 1;
goto error;
}
} else {
PUSH(XML_OP_CHILD, token, URL);
}
} else
PUSH(XML_OP_CHILD, name, NULL);
return;
} else if (xmlStrEqual(name, (const xmlChar *) "attribute")) {
xmlFree(name);
name = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -