📄 pattern.c
字号:
break; lst = lst->next; } if (lst != NULL) continue; } goto rollback; } case XML_OP_ATTR: if (node->type != XML_ATTRIBUTE_NODE) goto rollback; 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 voidxmlCompileAttributeTest(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); } 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 voidxmlCompileStepPattern(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++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -