diff --git a/ChangeLog b/ChangeLog index b6b38863dca56f285313a794a699305c15c97c87_Q2hhbmdlTG9n..edf652d35df17788cb48390bab49e1c62044b2dd_Q2hhbmdlTG9n 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Tue Jan 16 17:17:17 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> + + * TODO: started filling it :-( + * libxslt/pattern.c: should now at least compile the full + set of patterns authorized. Default priorities added. + * libxslt/transform.c: a bit more work and cleanup. + Mon Jan 15 15:34:17 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> * TODO: started adding in there :-( diff --git a/TODO b/TODO index b6b38863dca56f285313a794a699305c15c97c87_VE9ETw==..edf652d35df17788cb48390bab49e1c62044b2dd_VE9ETw== 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,25 @@ +Design: + - should transforms for a given stylesheet be thread clean, + or can a stylesheet be enriched with document specific + informations and cleaned up later ? + +Import: + -> parse them + -> provide functions to circulate in the import tree of stylesheets + +Pattern tester: + -> try to optimize for ID scan and tests. + +Pattern scanner: + -> add error checks on all returns + -> handle unions + -> compute priority + +Separate util module: + -> macros, config, verbosity ? + Support for disable-output-escaping="yes": -> looks problematic, libxml has no support for anything like this, and unless adding a new node type :-( or tweaking text node and output routines this is gonna be messy ... must be handled at libxml level. @@ -1,5 +21,10 @@ Support for disable-output-escaping="yes": -> looks problematic, libxml has no support for anything like this, and unless adding a new node type :-( or tweaking text node and output routines this is gonna be messy ... must be handled at libxml level. + +Error handling: + -> check the version stuff, design a separate module for error interfacing + and default handling, parsing vs. runtime, fatal / compat / warning, + and lack of optionnal features. diff --git a/libxslt/pattern.c b/libxslt/pattern.c index b6b38863dca56f285313a794a699305c15c97c87_bGlieHNsdC9wYXR0ZXJuLmM=..edf652d35df17788cb48390bab49e1c62044b2dd_bGlieHNsdC9wYXR0ZXJuLmM= 100644 --- a/libxslt/pattern.c +++ b/libxslt/pattern.c @@ -56,6 +56,10 @@ XSLT_OP_KEY, XSLT_OP_NS, XSLT_OP_ALL, + XSLT_OP_PI, + XSLT_OP_COMMENT, + XSLT_OP_TEXT, + XSLT_OP_NODE, XSLT_OP_PREDICATE } xsltOp; @@ -72,6 +76,6 @@ typedef xsltCompMatch *xsltCompMatchPtr; struct _xsltCompMatch { struct _xsltCompMatch *next; /* siblings in the name hash */ - int priority; /* the priority */ + float priority; /* the priority */ xsltTemplatePtr template; /* the associated template */ @@ -76,6 +80,6 @@ xsltTemplatePtr template; /* the associated template */ - /* TODO fix the statically allocated size */ + /* TODO fix the statically allocated size steps[] */ int nbStep; int maxStep; xsltStepOp steps[20]; /* ops for computation */ @@ -294,7 +298,7 @@ /* TODO: Handle namespace ... */ continue; case XSLT_OP_CHILD: - TODO /* Hummm !!! */ + TODO /* Handle OP_CHILD */ return(0); case XSLT_OP_ATTR: if (node->type != XML_ATTRIBUTE_NODE) @@ -351,6 +355,6 @@ TODO /* Handle Namespace */ break; case XSLT_OP_ALL: - TODO /* Handle Namespace */ + TODO /* Handle * */ break; case XSLT_OP_PREDICATE: @@ -355,6 +359,18 @@ break; case XSLT_OP_PREDICATE: - TODO /* Handle Namespace */ + TODO /* Handle Predicate */ + break; + case XSLT_OP_PI: + TODO /* Handle PI() */ + break; + case XSLT_OP_COMMENT: + TODO /* Handle Comments() */ + break; + case XSLT_OP_TEXT: + TODO /* Handle Text() */ + break; + case XSLT_OP_NODE: + TODO /* Handle Node() */ break; } } @@ -382,6 +398,66 @@ #define PUSH(op, val, val2) \ if (xsltCompMatchAdd(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); } + +/** + * xsltScanLiteral: + * @ctxt: the XPath Parser context + * + * Parse an XPath Litteral: + * + * [29] Literal ::= '"' [^"]* '"' + * | "'" [^']* "'" + * + * Returns the Literal parsed or NULL + */ + +xmlChar * +xsltScanLiteral(xsltParserContextPtr ctxt) { + const xmlChar *q; + xmlChar *ret = NULL; + + SKIP_BLANKS; + if (CUR == '"') { + NEXT; + q = CUR_PTR; + while ((IS_CHAR(CUR)) && (CUR != '"')) + NEXT; + if (!IS_CHAR(CUR)) { + /* XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); */ + ctxt->error = 1; + return(NULL); + } else { + ret = xmlStrndup(q, CUR_PTR - q); + NEXT; + } + } else if (CUR == '\'') { + NEXT; + q = CUR_PTR; + while ((IS_CHAR(CUR)) && (CUR != '\'')) + NEXT; + if (!IS_CHAR(CUR)) { + /* XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); */ + ctxt->error = 1; + return(NULL); + } else { + ret = xmlStrndup(q, CUR_PTR - q); + NEXT; + } + } else { + /* XP_ERROR(XPATH_START_LITERAL_ERROR); */ + ctxt->error = 1; + return(NULL); + } + return(ret); +} + /** * xsltScanName: * @ctxt: the XPath Parser context @@ -433,6 +509,11 @@ return(xmlStrndup(buf, len)); } /* - * Compile the XSLT LocationPathPattern + * xsltCompileIdKeyPattern: + * @comp: the compilation context + * @name: a preparsed name + * @aid: whether id/key are allowed there + * + * Compile the XSLT LocationIdKeyPattern * [3] IdKeyPattern ::= 'id' '(' Literal ')' * | 'key' '(' Literal ',' Literal ')' @@ -437,3 +518,9 @@ * [3] IdKeyPattern ::= 'id' '(' Literal ')' * | 'key' '(' Literal ',' Literal ')' + * + * also handle NodeType and PI from: + * + * [7] NodeTest ::= NameTest + * | NodeType '(' ')' + * | 'processing-instruction' '(' Literal ')' */ @@ -439,4 +526,124 @@ */ +void +xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name, int aid) { + xmlChar *lit = NULL; + xmlChar *lit2 = NULL; + + if (CUR != '(') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : ( expected\n"); + ctxt->error = 1; + return; + } + if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) { + NEXT; + SKIP_BLANKS; + lit = xsltScanLiteral(ctxt); + if (ctxt->error) + return; + SKIP_BLANKS; + if (CUR != ')') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + NEXT; + PUSH(XSLT_OP_ID, lit, NULL); + } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) { + NEXT; + SKIP_BLANKS; + lit = xsltScanLiteral(ctxt); + if (ctxt->error) + return; + SKIP_BLANKS; + if (CUR != ',') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : , expected\n"); + ctxt->error = 1; + return; + } + NEXT; + SKIP_BLANKS; + lit2 = xsltScanLiteral(ctxt); + if (ctxt->error) + return; + SKIP_BLANKS; + if (CUR != ')') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + NEXT; + PUSH(XSLT_OP_KEY, lit, NULL); + } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) { + NEXT; + SKIP_BLANKS; + if (CUR != ')') { + lit = xsltScanLiteral(ctxt); + if (ctxt->error) + return; + SKIP_BLANKS; + if (CUR != ')') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + } + NEXT; + PUSH(XSLT_OP_PI, lit, NULL); + } else if (xmlStrEqual(name, (const xmlChar *)"text")) { + NEXT; + SKIP_BLANKS; + if (CUR != ')') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + NEXT; + PUSH(XSLT_OP_TEXT, NULL, NULL); + } else if (xmlStrEqual(name, (const xmlChar *)"comment")) { + NEXT; + SKIP_BLANKS; + if (CUR != ')') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + NEXT; + PUSH(XSLT_OP_COMMENT, NULL, NULL); + } else if (xmlStrEqual(name, (const xmlChar *)"comment")) { + NEXT; + SKIP_BLANKS; + if (CUR != ')') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + NEXT; + PUSH(XSLT_OP_NODE, NULL, NULL); + } else if (aid) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n"); + ctxt->error = 1; + return; + } else { + xsltGenericError(xsltGenericErrorContext, + "xsltCompileIdKeyPattern : node type\n"); + ctxt->error = 1; + return; + } +error: + if (lit != NULL) + xmlFree(lit); + if (lit2 != NULL) + xmlFree(lit2); +} /** * xsltCompileStepPattern: @@ -461,6 +668,8 @@ void xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) { + xmlChar *name = NULL; + SKIP_BLANKS; if ((token == NULL) && (CUR == '@')) { token = xsltScanName(ctxt); @@ -468,5 +677,5 @@ xsltGenericError(xsltGenericErrorContext, "xsltCompilePattern : Name expected\n"); ctxt->error = 1; - return; + goto error; } @@ -472,4 +681,6 @@ } + PUSH(XSLT_OP_ATTR, token, NULL); + return; } if (token == NULL) token = xsltScanName(ctxt); @@ -477,7 +688,7 @@ xsltGenericError(xsltGenericErrorContext, "xsltCompilePattern : Name expected\n"); ctxt->error = 1; - return; + goto error; } SKIP_BLANKS; if (CUR == '(') { @@ -481,6 +692,7 @@ } SKIP_BLANKS; if (CUR == '(') { - TODO; - /* if (xmlStrEqual(token, "processing-instruction")) */ + xsltCompileIdKeyPattern(ctxt, token, 0); + if (ctxt->error) + goto error; } else if (CUR == ':') { @@ -486,3 +698,37 @@ } else if (CUR == ':') { - TODO; + NEXT; + if (NXT(1) != ':') { + xsltGenericError(xsltGenericErrorContext, + "xsltCompilePattern : sequence '::' expected\n"); + ctxt->error = 1; + goto error; + } + NEXT; + if (xmlStrEqual(token, (const xmlChar *) "child")) { + /* TODO: handle namespace */ + name = xsltScanName(ctxt); + if (name == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompilePattern : QName expected\n"); + ctxt->error = 1; + goto error; + } + PUSH(XSLT_OP_CHILD, name, NULL); + } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) { + /* TODO: handle namespace */ + name = xsltScanName(ctxt); + if (name == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompilePattern : QName expected\n"); + ctxt->error = 1; + goto error; + } + PUSH(XSLT_OP_ATTR, name, NULL); + } else { + xsltGenericError(xsltGenericErrorContext, + "xsltCompilePattern : 'child' or 'attribute' expected\n"); + ctxt->error = 1; + goto error; + } + xmlFree(token); } else if (CUR == '*') { @@ -488,3 +734,4 @@ } else if (CUR == '*') { - TODO; + NEXT; + PUSH(XSLT_OP_ALL, token, NULL); } else { @@ -490,5 +737,6 @@ } else { + /* TODO: handle namespace */ PUSH(XSLT_OP_ELEM, token, NULL); } SKIP_BLANKS; while (CUR == '[') { @@ -491,8 +739,24 @@ PUSH(XSLT_OP_ELEM, token, NULL); } SKIP_BLANKS; while (CUR == '[') { - TODO; + const xmlChar *q; + xmlChar *ret = NULL; + + NEXT; + q = CUR_PTR; + /* TODO: avoid breaking in strings ... */ + while ((IS_CHAR(CUR)) && (CUR != ']')) + NEXT; + if (!IS_CHAR(CUR)) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompilePattern : ']' expected\n"); + ctxt->error = 1; + goto error; + } + NEXT; + ret = xmlStrndup(q, CUR_PTR - q); + PUSH(XSLT_OP_PREDICATE, ret, NULL); } return; error: @@ -496,7 +760,10 @@ } return; error: - ctxt->error = 1; + if (token != NULL) + xmlFree(token); + if (name != NULL) + xmlFree(name); } /** @@ -586,7 +853,20 @@ } SKIP_BLANKS; if (CUR == '(') { - TODO + xsltCompileIdKeyPattern(ctxt, name, 1); + if ((CUR == '/') && (NXT(1) == '/')) { + PUSH(XSLT_OP_ANCESTOR, NULL, NULL); + NEXT; + NEXT; + SKIP_BLANKS; + xsltCompileRelativePathPattern(ctxt, NULL); + } else if (CUR == '/') { + PUSH(XSLT_OP_PARENT, NULL, NULL); + NEXT; + SKIP_BLANKS; + xsltCompileRelativePathPattern(ctxt, NULL); + } + return; } xsltCompileRelativePathPattern(ctxt, name); } @@ -653,6 +933,32 @@ */ xsltReverseCompMatch(ret); + /* + * Set-up the priority + */ + if (((ret->steps[0].op == XSLT_OP_ELEM) || + (ret->steps[0].op == XSLT_OP_ATTR)) && + (ret->steps[0].value != NULL) && + (ret->steps[1].op == XSLT_OP_END)) { + ret->priority = 0; + } else if ((ret->steps[0].op == XSLT_OP_PI) && + (ret->steps[0].value != NULL) && + (ret->steps[1].op == XSLT_OP_END)) { + ret->priority = 0; + } else if ((ret->steps[0].op == XSLT_OP_NS) && + (ret->steps[0].value != NULL) && + (ret->steps[1].op == XSLT_OP_END)) { + ret->priority = -0.25; + } else if (((ret->steps[0].op == XSLT_OP_PI) || + (ret->steps[0].op == XSLT_OP_TEXT) || + (ret->steps[0].op == XSLT_OP_NODE) || + (ret->steps[0].op == XSLT_OP_COMMENT)) && + (ret->steps[1].op == XSLT_OP_END)) { + ret->priority = -0.5; + } else { + ret->priority = 0.5; + } + xsltFreeParserContext(ctxt); return(ret); @@ -721,6 +1027,22 @@ "xsltAddTemplate: invalid compiled pattern\n"); xsltFreeCompMatch(pat); return(-1); + /* + * TODO: some flags at the top level about type based patterns + * would be faster than inclusion in the hash table. + */ + case XSLT_OP_PI: + name = (const xmlChar *) "processing-instruction()"; + break; + case XSLT_OP_COMMENT: + name = (const xmlChar *) "comment()"; + break; + case XSLT_OP_TEXT: + name = (const xmlChar *) "text()"; + break; + case XSLT_OP_NODE: + name = (const xmlChar *) "node()"; + break; } if (name == NULL) { xsltGenericError(xsltGenericErrorContext, diff --git a/libxslt/transform.c b/libxslt/transform.c index b6b38863dca56f285313a794a699305c15c97c87_bGlieHNsdC90cmFuc2Zvcm0uYw==..edf652d35df17788cb48390bab49e1c62044b2dd_bGlieHNsdC90cmFuc2Zvcm0uYw== 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -35,6 +35,7 @@ * To cleanup */ xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix); +void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs); /* * There is no XSLT specific error reporting module yet @@ -206,6 +207,7 @@ value = xmlNodeListGetString(inst->doc, inst->children, 1); if (value == NULL) { - if (ns) + if (ns) { +#if LIBXML_VERSION > 202111 attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, (const xmlChar *)""); @@ -210,6 +212,11 @@ attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, (const xmlChar *)""); - else +#else + xsltGenericError(xsltGenericErrorContext, + "xsl:attribute: recompile against newer libxml version\n"); + attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)""); +#endif + } else attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)""); } else { /* TODO: attribute value template */ @@ -213,5 +220,6 @@ attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)""); } else { /* TODO: attribute value template */ - if (ns) + if (ns) { +#if LIBXML_VERSION > 202111 attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value); @@ -217,5 +225,10 @@ attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value); - else +#else + xsltGenericError(xsltGenericErrorContext, + "xsl:attribute: recompile against newer libxml version\n"); + attr = xmlSetProp(ctxt->insert, ncname, value); +#endif + } else attr = xmlSetProp(ctxt->insert, ncname, value); }