From 50b5fc7b3610274a70d9b50c7cd686838498d793 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 13 Feb 2004 16:07:08 +0000 Subject: [PATCH] added new code to handle attribute value templates also a lot of work to * libxslt/attrvt.c libxslt/Makefile.am: added new code to handle attribute value templates * libxslt/*.c libxslt/*.h: also a lot of work to reuse the dictionaries at the stylesheet and transformation level. * configure.in: this relies on a recent version of libxml2 with the sub dictionnary catalog. Daniel --- ChangeLog | 9 ++ configure.in | 2 +- libxslt/Makefile.am | 1 + libxslt/attributes.c | 111 +++++------------ libxslt/attributes.h | 2 +- libxslt/attrvt.c | 304 +++++++++++++++++++++++++++++++++++++++++++++ libxslt/documents.c | 64 ++++++++-- libxslt/keys.c | 4 +- libxslt/numbers.c | 13 +- libxslt/numbersInternals.h | 10 +- libxslt/pattern.c | 2 +- libxslt/preproc.c | 190 +++++++++++++--------------- libxslt/templates.c | 70 ++++++----- libxslt/templates.h | 2 +- libxslt/transform.c | 79 ++++++------ libxslt/variables.c | 85 +++++-------- libxslt/xslt.c | 43 +++++-- libxslt/xsltInternals.h | 69 +++++++--- libxslt/xsltutils.c | 147 ++++++++++++++++++++++ libxslt/xsltutils.h | 29 ++++- 20 files changed, 859 insertions(+), 377 deletions(-) create mode 100644 libxslt/attrvt.c diff --git a/ChangeLog b/ChangeLog index f91f3c4..b98c126 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Fri Feb 13 16:59:46 CET 2004 Daniel Veillard + + * libxslt/attrvt.c libxslt/Makefile.am: added new code to handle + attribute value templates + * libxslt/*.c libxslt/*.h: also a lot of work to reuse the + dictionaries at the stylesheet and transformation level. + * configure.in: this relies on a recent version of libxml2 + with the sub dictionnary catalog. + Sun Feb 8 16:53:14 HKT 2004 William Brack * libxslt/transform.c: added check for "?>" in PI content diff --git a/configure.in b/configure.in index bae6457..23cfda2 100644 --- a/configure.in +++ b/configure.in @@ -11,7 +11,7 @@ PACKAGE=libxslt LIBEXSLT_MAJOR_VERSION=0 LIBEXSLT_MINOR_VERSION=8 LIBEXSLT_MICRO_VERSION=2 -LIBXML_REQUIRED_VERSION=2.6.3 +LIBXML_REQUIRED_VERSION=2.6.5 LIBXSLT_VERSION=$LIBXSLT_MAJOR_VERSION.$LIBXSLT_MINOR_VERSION.$LIBXSLT_MICRO_VERSION diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am index dff2e53..c0dc1a3 100644 --- a/libxslt/Makefile.am +++ b/libxslt/Makefile.am @@ -27,6 +27,7 @@ xsltinc_HEADERS = \ xsltexports.h libxslt_la_SOURCES = \ + attrvt.c \ xslt.c \ xsltutils.c \ pattern.c \ diff --git a/libxslt/attributes.c b/libxslt/attributes.c index 6931130..c3b2cce 100644 --- a/libxslt/attributes.c +++ b/libxslt/attributes.c @@ -123,10 +123,6 @@ xsltNewAttrElem(xmlNodePtr attr) { */ static void xsltFreeAttrElem(xsltAttrElemPtr attr) { - if (attr->set != NULL) - xmlFree((char *)attr->set); - if (attr->ns != NULL) - xmlFree((char *)attr->ns); xmlFree(attr); } @@ -275,11 +271,11 @@ xsltMergeAttrElemList(xsltAttrElemPtr list, xsltAttrElemPtr old) { void xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { - xmlChar *prop = NULL; - xmlChar *ncname = NULL; - xmlChar *prefix = NULL; + const xmlChar *ncname; + const xmlChar *prefix; + const xmlChar *attrib, *endattr; + xmlChar *prop; xmlChar *attributes; - xmlChar *attrib, *endattr; xmlNodePtr list; xsltAttrElemPtr values; @@ -290,15 +286,11 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { if (prop == NULL) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : name is missing\n"); - goto error; + return; } - ncname = xmlSplitQName2(prop, &prefix); - if (ncname == NULL) { - ncname = prop; - prop = NULL; - prefix = NULL; - } + ncname = xsltSplitQName(style->dict, prop, &prefix); + xmlFree(prop); if (style->attributeSets == NULL) { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES @@ -308,7 +300,7 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { style->attributeSets = xmlHashCreate(10); } if (style->attributeSets == NULL) - goto error; + return; values = xmlHashLookup2(style->attributeSets, ncname, prefix); @@ -354,36 +346,24 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { break; endattr = attrib; while ((*endattr != 0) && (!IS_BLANK(*endattr))) endattr++; - attrib = xmlStrndup(attrib, endattr - attrib); + attrib = xmlDictLookup(style->dict, attrib, endattr - attrib); if (attrib) { - xmlChar *ncname2 = NULL; - xmlChar *prefix2 = NULL; + const xmlChar *ncname2 = NULL; + const xmlChar *prefix2 = NULL; xsltAttrElemPtr values2; + #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "xsl:attribute-set : %s adds use %s\n", ncname, attrib); #endif - ncname2 = xmlSplitQName2(attrib, &prefix2); - if (ncname2 == NULL) { - ncname2 = attrib; - attrib = NULL; - prefix = NULL; - } + ncname2 = xsltSplitQName(style->dict, attrib, &prefix2); values2 = xsltNewAttrElem(NULL); if (values2 != NULL) { values2->set = ncname2; values2->ns = prefix2; values = xsltMergeAttrElemList(values, values2); xsltFreeAttrElem(values2); - } else { - if (ncname2 != NULL) - xmlFree(ncname2); - if (prefix2 != NULL) - xmlFree(prefix2); } - - if (attrib != NULL) - xmlFree(attrib); } attrib = endattr; } @@ -400,14 +380,6 @@ done: xsltGenericDebug(xsltGenericDebugContext, "updated attribute list %s\n", ncname); #endif - -error: - if (prop != NULL) - xmlFree(prop); - if (ncname != NULL) - xmlFree(ncname); - if (prefix != NULL) - xmlFree(prefix); } /** @@ -597,8 +569,9 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node, int fromset) { xmlChar *prop = NULL; - xmlChar *ncname = NULL, *name, *namespace; - xmlChar *prefix = NULL; + xmlChar *namespace; + const xmlChar *name = NULL; + const xmlChar *prefix = NULL; xmlChar *value = NULL; xmlNsPtr ns = NULL; xmlAttrPtr attr; @@ -639,22 +612,17 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node, "xsl:attribute : name is missing\n"); goto error; } - name = prop; + if (xmlValidateQName(prop, 0)) { + xsltTransformError(ctxt, NULL, inst, + "xsl:attribute : invalid QName\n"); + /* we fall through to catch any further errors, if possible */ + } + name = xsltSplitQName(ctxt->dict, prop, &prefix); + xmlFree(prop); } else { - name = comp->name; + name = xsltSplitQName(ctxt->dict, comp->name, &prefix); } - if (xmlValidateQName(name, 0)) { - xsltTransformError(ctxt, NULL, inst, - "xsl:attribute : invalid QName\n"); - /* we fall through to catch any further errors, if possible */ - } - ncname = xmlSplitQName2(name, &prefix); - if (ncname == NULL) { - prefix = NULL; - } else { - name = ncname; - } if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, @@ -721,13 +689,7 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node, } } - error: - if (prop != NULL) - xmlFree(prop); - if (ncname != NULL) - xmlFree(ncname); - if (prefix != NULL) - xmlFree(prefix); +error: if (value != NULL) xmlFree(value); } @@ -760,11 +722,11 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node, void xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst ATTRIBUTE_UNUSED, - xmlChar * attributes) + const xmlChar * attributes) { - xmlChar *ncname = NULL; - xmlChar *prefix = NULL; - xmlChar *attrib, *endattr; + const xmlChar *ncname = NULL; + const xmlChar *prefix = NULL; + const xmlChar *attrib, *endattr; xsltAttrElemPtr values; xsltStylesheetPtr style; @@ -781,18 +743,13 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node, endattr = attrib; while ((*endattr != 0) && (!IS_BLANK(*endattr))) endattr++; - attrib = xmlStrndup(attrib, endattr - attrib); + attrib = xmlDictLookup(ctxt->dict, attrib, endattr - attrib); if (attrib) { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "apply attribute set %s\n", attrib); #endif - ncname = xmlSplitQName2(attrib, &prefix); - if (ncname == NULL) { - ncname = attrib; - attrib = NULL; - prefix = NULL; - } + ncname = xsltSplitQName(ctxt->dict, attrib, &prefix); style = ctxt->style; #ifdef WITH_DEBUGGER @@ -817,12 +774,6 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node, } style = xsltNextImport(style); } - if (attrib != NULL) - xmlFree(attrib); - if (ncname != NULL) - xmlFree(ncname); - if (prefix != NULL) - xmlFree(prefix); } attrib = endattr; } diff --git a/libxslt/attributes.h b/libxslt/attributes.h index 5e219b1..d61ebb0 100644 --- a/libxslt/attributes.h +++ b/libxslt/attributes.h @@ -27,7 +27,7 @@ XSLTPUBFUN void XSLTCALL xsltApplyAttributeSet (xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, - xmlChar *attributes); + const xmlChar *attributes); XSLTPUBFUN void XSLTCALL xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style); #ifdef __cplusplus diff --git a/libxslt/attrvt.c b/libxslt/attrvt.c new file mode 100644 index 0000000..29d4337 --- /dev/null +++ b/libxslt/attrvt.c @@ -0,0 +1,304 @@ +/* + * attrvt.c: Implementation of the XSL Transformation 1.0 engine + * attribute value template handling part. + * + * References: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * Michael Kay "XSLT Programmer's Reference" pp 637-643 + * Writing Multiple Output Files + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include "xslt.h" +#include "xsltutils.h" +#include "xsltInternals.h" +#include "templates.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_AVT +#define WITH_XSLT_DEBUG_AVT +#endif + +static struct xsltIsAttVTStruct { + int key; +} xsltIsAttVTStruct = { 0xdeadbeef }; + +void *xsltIsAttVT = (void *) &xsltIsAttVTStruct; + +#define MAX_AVT_SEG 10 + +typedef struct _xsltAttrVT xsltAttrVT; +typedef xsltAttrVT *xsltAttrVTPtr; +struct _xsltAttrVT { + struct _xsltAttrVT *next; /* next xsltAttrVT */ + int nb_seg; /* Number of segments */ + int strstart; /* is the start a string */ + /* + * the namespaces in scope + */ + xmlNsPtr *nsList; + int nsNr; + /* + * the content is an alternate of string and xmlXPathCompExprPtr + */ + void *segments[MAX_AVT_SEG]; +}; + +/** + * xsltNewAttrVT: + * @style: a XSLT process context + * + * Build a new xsltAttrVT structure + * + * Returns the structure or NULL in case of error + */ +static xsltAttrVTPtr +xsltNewAttrVT(xsltStylesheetPtr style) { + xsltAttrVTPtr cur; + + cur = (xsltAttrVTPtr) xmlMalloc(sizeof(xsltAttrVT)); + if (cur == NULL) { + xsltTransformError(NULL, style, NULL, + "xsltNewAttrVTPtr : malloc failed\n"); + if (style != NULL) style->errors++; + return(NULL); + } + memset(cur, 0, sizeof(xsltAttrVT)); + + cur->nb_seg = 0; + cur->strstart = 0; + cur->next = style->attVTs; + style->attVTs = (xsltAttrVTPtr) cur; + + return(cur); +} + +/** + * xsltFreeAttrVT: + * @avt: pointer to an xsltAttrVT structure + * + * Free up the memory associated to the attribute value template + */ +static void +xsltFreeAttrVT(xsltAttrVTPtr avt) { + int i; + + if (avt == NULL) return; + + if (avt->strstart == 1) { + for (i = 0;i < avt->nb_seg; i += 2) + xmlFree((xmlChar *) avt->segments[i]); + for (i = 1;i < avt->nb_seg; i += 2) + xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]); + } else { + for (i = 0;i < avt->nb_seg; i += 2) + xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]); + for (i = 1;i < avt->nb_seg; i += 2) + xmlFree((xmlChar *) avt->segments[i]); + } + if (avt->nsList != NULL) + xmlFree(avt->nsList); + xmlFree(avt); +} + +/** + * xsltFreeAVTList: + * @avt: pointer to an list of AVT structures + * + * Free up the memory associated to the attribute value templates + */ +void +xsltFreeAVTList(void *avt) { + xsltAttrVTPtr cur = (xsltAttrVTPtr) avt, next; + + while (cur != NULL) { + next = cur->next; + xsltFreeAttrVT(cur); + cur = next; + } +} + +/** + * xsltCompileAttr: + * @style: a XSLT process context + * @attr: the attribute coming from the stylesheet. + * + * Precompile an attribute in a stylesheet, basically it checks if it is + * an attrubute value template, and if yes establish some structures needed + * to process it at transformation time. + */ +void +xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) { + const xmlChar *str; + const xmlChar *cur; + xmlChar *ret = NULL; + xmlChar *expr = NULL; + xsltAttrVTPtr avt; + int i = 0; + + if ((style == NULL) || (attr == NULL) || (attr->children == NULL)) + return; + if ((attr->children->type != XML_TEXT_NODE) || + (attr->children->next != NULL)) { + xsltTransformError(NULL, style, attr->parent, + "Attribute %s content is not a text node\n", attr->name); + style->errors++; + return; + } + str = attr->children->content; + if (xmlStrchr(str, '{') == NULL) return; + + avt = xsltNewAttrVT(style); + if (avt == NULL) return; + attr->_private = avt; + + avt->nsList = xmlGetNsList(attr->doc, attr->parent); + if (avt->nsList != NULL) { + while (avt->nsList[i] != NULL) + i++; + } + avt->nsNr = i; + + cur = str; + while (*cur != 0) { + if (*cur == '{') { + if (*(cur+1) == '{') { /* escaped '{' */ + cur++; + ret = xmlStrncat(ret, str, cur - str); + cur++; + str = cur; + continue; + } + if (*(cur+1) == '}') { /* skip empty AVT */ + ret = xmlStrncat(ret, str, cur - str); + cur+=2; + str = cur; + continue; + } + if ((ret != NULL) || (cur - str > 0)) { + ret = xmlStrncat(ret, str, cur - str); + str = cur; + if (avt->nb_seg == 0) + avt->strstart = 1; + avt->segments[avt->nb_seg++] = (void *) ret; + ret = NULL; + } + + cur++; + while ((*cur != 0) && (*cur != '}')) cur++; + if (*cur == 0) { + xsltTransformError(NULL, style, attr->parent, + "Attribute template %s: unmatched '{'\n", attr->name); + style->errors++; + goto error; + } + str++; + expr = xmlStrndup(str, cur - str); + if (expr == NULL) { + XSLT_TODO + goto error; + } else { + xmlXPathCompExprPtr comp; + + comp = xsltXPathCompile(style, expr); + if (comp == NULL) { + xsltTransformError(NULL, style, attr->parent, + "Attribute template %s: failed to compile %s\n", + attr->name, expr); + style->errors++; + goto error; + } + if (avt->nb_seg == 0) + avt->strstart = 0; + avt->segments[avt->nb_seg++] = (void *) comp; + xmlFree(expr); + expr = NULL; + } + cur++; + str = cur; + } else if (*cur == '}') { + cur++; + if (*cur == '}') { /* escaped '}' */ + ret = xmlStrncat(ret, str, cur - str); + cur++; + str = cur; + continue; + } else { + xsltTransformError(NULL, style, attr->parent, + "Attribute template %s: unmatched '}'\n", attr->name); + goto error; + } + } else + cur++; + } + if ((ret != NULL) || (cur - str > 0)) { + ret = xmlStrncat(ret, str, cur - str); + str = cur; + if (avt->nb_seg == 0) + avt->strstart = 1; + avt->segments[avt->nb_seg++] = (void *) ret; + ret = NULL; + } + +error: + if (ret != NULL) + xmlFree(ret); + if (expr != NULL) + xmlFree(expr); +} + + +/** + * xsltEvalAVT: + * @ctxt: the XSLT transformation context + * @avt: the prevompiled attribute value template info + * @node: the node hosting the attribute + * + * Process the given AVT, and return the new string value. + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltEvalAVT(xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node) { + xmlChar *ret = NULL, *tmp; + xmlXPathCompExprPtr comp; + xsltAttrVTPtr cur = (xsltAttrVTPtr) avt; + int i; + int str; + + if ((ctxt == NULL) || (avt == NULL) || (node == NULL)) + return(NULL); + str = cur->strstart; + for (i = 0;i < cur->nb_seg;i++) { + if (str) { + ret = xmlStrcat(ret, (const xmlChar *) cur->segments[i]); + } else { + comp = (xmlXPathCompExprPtr) cur->segments[i]; + tmp = xsltEvalXPathStringNs(ctxt, comp, cur->nsNr, cur->nsList); + if (tmp != NULL) { + if (ret != NULL) { + ret = xmlStrcat(ret, tmp); + xmlFree(tmp); + } else { + ret = tmp; + } + } + } + str = !str; + } + return(ret); +} diff --git a/libxslt/documents.c b/libxslt/documents.c index b38ed51..e7f7396 100644 --- a/libxslt/documents.c +++ b/libxslt/documents.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" @@ -147,6 +149,55 @@ xsltFreeDocuments(xsltTransformContextPtr ctxt) { } } +/** + * xsltParseDocument: + * @URI: the URI to load. + * @dict: the dictionnary to use + * @options: the options to use + * + * Specialized parsing function + * + * Returns NULL in case of error or the Document parsed. + */ +static xmlDocPtr +xsltParseDocument(const xmlChar *URI, xmlDictPtr dict, int options) { + xmlParserCtxtPtr pctxt; + xmlParserInputPtr inputStream; + xmlDocPtr doc; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) + return(NULL); + if (pctxt->dict != NULL) { + xmlDictFree(pctxt->dict); + pctxt->dict = dict; + xmlDictReference(pctxt->dict); + } + xmlCtxtUseOptions(pctxt, options); + inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt); + if (inputStream == NULL) { + xmlFreeParserCtxt(pctxt); + return(NULL); + } + inputPush(pctxt, inputStream); + if (pctxt->directory == NULL) + pctxt->directory = xmlParserGetDirectory((const char *) URI); + + xmlParseDocument(pctxt); + + if (pctxt->wellFormed) { + doc = pctxt->myDoc; + xmlDictReference(pctxt->dict); + } + else { + doc = NULL; + xmlFreeDoc(pctxt->myDoc); + pctxt->myDoc = NULL; + } + xmlFreeParserCtxt(pctxt); + + return(doc); +} /** * xsltLoadDocument: @@ -192,11 +243,8 @@ xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) { ret = ret->next; } -#ifdef XSLT_PARSE_OPTIONS - doc = xmlReadFile((const char *) URI, NULL, ctxt->parserOptions); -#else - doc = xmlParseFile((const char *) URI); -#endif + doc = xsltParseDocument(URI, ctxt->dict, ctxt->parserOptions); + if (doc == NULL) return(NULL); @@ -270,11 +318,7 @@ xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) { ret = ret->next; } -#ifdef XSLT_PARSE_OPTIONS - doc = xmlReadFile((const char *) URI, NULL, XSLT_PARSE_OPTIONS); -#else - doc = xmlParseFile((const char *) URI); -#endif + doc = xsltParseDocument(URI, style->dict, XSLT_PARSE_OPTIONS); if (doc == NULL) return(NULL); diff --git a/libxslt/keys.c b/libxslt/keys.c index 664175d..6d0e757 100644 --- a/libxslt/keys.c +++ b/libxslt/keys.c @@ -369,14 +369,14 @@ xsltAddKey(xsltStylesheetPtr style, const xmlChar *name, xsltGenericDebug(xsltGenericDebugContext, " resulting pattern %s\n", pattern); #endif - key->comp = xmlXPathCompile(pattern); + key->comp = xsltXPathCompile(style, pattern); if (key->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:key : XPath pattern compilation failed '%s'\n", pattern); if (style != NULL) style->errors++; } - key->usecomp = xmlXPathCompile(use); + key->usecomp = xsltXPathCompile(style, use); if (key->usecomp == NULL) { xsltTransformError(NULL, style, inst, "xsl:key : XPath pattern compilation failed '%s'\n", diff --git a/libxslt/numbers.c b/libxslt/numbers.c index 0068276..6382bcd 100644 --- a/libxslt/numbers.c +++ b/libxslt/numbers.c @@ -315,7 +315,7 @@ xsltNumberFormatRoman(xmlBufferPtr buffer, } static void -xsltNumberFormatTokenize(xmlChar *format, +xsltNumberFormatTokenize(const xmlChar *format, xsltFormatPtr tokens) { int index = 0; @@ -534,8 +534,8 @@ xsltNumberFormatInsertNumbers(xsltNumberDataPtr data, static int xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context, xmlNodePtr node, - xmlChar *count, - xmlChar *from, + const xmlChar *count, + const xmlChar *from, double *array, xmlDocPtr doc, xmlNodePtr elem) @@ -623,8 +623,8 @@ xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context, static int xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context, xmlNodePtr node, - xmlChar *count, - xmlChar *from, + const xmlChar *count, + const xmlChar *from, double *array, int max, xmlDocPtr doc, @@ -698,7 +698,7 @@ xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context, static int xsltNumberFormatGetValue(xmlXPathContextPtr context, xmlNodePtr node, - xmlChar *value, + const xmlChar *value, double *number) { int amount = 0; @@ -842,7 +842,6 @@ xsltNumberFormat(xsltTransformContextPtr ctxt, XSLT_NUMBER_FORMAT_END: if (tempformat == 1) { /* The format need to be recomputed each time */ - xmlFree(data->format); data->format = NULL; } if (output != NULL) diff --git a/libxslt/numbersInternals.h b/libxslt/numbersInternals.h index 6e1343b..7b3cb17 100644 --- a/libxslt/numbersInternals.h +++ b/libxslt/numbersInternals.h @@ -26,11 +26,11 @@ typedef struct _xsltNumberData xsltNumberData; typedef xsltNumberData *xsltNumberDataPtr; struct _xsltNumberData { - xmlChar *level; - xmlChar *count; - xmlChar *from; - xmlChar *value; - xmlChar *format; + const xmlChar *level; + const xmlChar *count; + const xmlChar *from; + const xmlChar *value; + const xmlChar *format; int has_format; int digitsPerGroup; int groupingCharacter; diff --git a/libxslt/pattern.c b/libxslt/pattern.c index 7e2ed99..dd82eb3 100644 --- a/libxslt/pattern.c +++ b/libxslt/pattern.c @@ -289,7 +289,7 @@ xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp, xsltAllocateExtra(ctxt->style); } if (op == XSLT_OP_PREDICATE) { - comp->steps[comp->nbStep].comp = xmlXPathCompile(value); + comp->steps[comp->nbStep].comp = xsltXPathCompile(ctxt->style, value); } comp->nbStep++; return (0); diff --git a/libxslt/preproc.c b/libxslt/preproc.c index 1bcf913..d77faf4 100644 --- a/libxslt/preproc.c +++ b/libxslt/preproc.c @@ -142,38 +142,7 @@ static void xsltFreeStylePreComp(xsltStylePreCompPtr comp) { if (comp == NULL) return; - if (comp->stype != NULL) - xmlFree(comp->stype); - if (comp->order != NULL) - xmlFree(comp->order); - if (comp->use != NULL) - xmlFree(comp->use); - if (comp->name != NULL) - xmlFree(comp->name); - if (comp->ns != NULL) - xmlFree(comp->ns); - if (comp->mode != NULL) - xmlFree(comp->mode); - if (comp->modeURI != NULL) - xmlFree(comp->modeURI); - if (comp->test != NULL) - xmlFree(comp->test); - if (comp->select != NULL) - xmlFree(comp->select); - - if (comp->filename != NULL) - xmlFree(comp->filename); - - if (comp->numdata.level != NULL) - xmlFree(comp->numdata.level); - if (comp->numdata.count != NULL) - xmlFree(comp->numdata.count); - if (comp->numdata.from != NULL) - xmlFree(comp->numdata.from); - if (comp->numdata.value != NULL) - xmlFree(comp->numdata.value); - if (comp->numdata.format != NULL) - xmlFree(comp->numdata.format); + if (comp->comp != NULL) xmlXPathFreeCompExpr(comp->comp); if (comp->nsList != NULL) @@ -203,7 +172,7 @@ xsltElemPreCompPtr xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function ATTRIBUTE_UNUSED) { xsltStylePreCompPtr comp; - xmlChar *filename = NULL; + const xmlChar *filename = NULL; comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); if (comp == NULL) @@ -330,16 +299,16 @@ xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) { (const xmlChar *)"lang", XSLT_NAMESPACE, &comp->has_lang); - comp->select = xsltGetNsProp(inst,(const xmlChar *)"select", XSLT_NAMESPACE); + comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select == NULL) { /* * The default value of the select attribute is ., which will * cause the string-value of the current node to be used as * the sort key. */ - comp->select = xmlStrdup((const xmlChar *)"."); + comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1); } - comp->comp = xmlXPathCompile(comp->select); + comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsltSortComp: could not compile select expression '%s'\n", @@ -374,7 +343,7 @@ xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) { comp->inst = inst; - comp->use = xsltGetNsProp(inst, (const xmlChar *)"use-attribute-sets", + comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets", XSLT_NAMESPACE); if (comp->use == NULL) comp->has_use = 0; @@ -384,7 +353,7 @@ xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltTextComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt text node * * Process the xslt text node on the source node @@ -392,7 +361,7 @@ xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) { xsltStylePreCompPtr comp; - xmlChar *prop; + const xmlChar *prop; if ((style == NULL) || (inst == NULL)) return; @@ -403,7 +372,7 @@ xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) { comp->inst = inst; comp->noescape = 0; - prop = xsltGetNsProp(inst, + prop = xsltGetCNsProp(style, inst, (const xmlChar *)"disable-output-escaping", XSLT_NAMESPACE); if (prop != NULL) { @@ -415,13 +384,12 @@ xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) { "xsl:text: disable-output-escaping allows only yes or no\n"); if (style != NULL) style->warnings++; } - xmlFree(prop); } } /** * xsltElementComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt element node * * Process the xslt element node on the source node @@ -438,12 +406,16 @@ xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) { inst->_private = comp; comp->inst = inst; - /* - * TODO: more computation can be done there, especially namespace lookup - */ comp->name = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE, &comp->has_name); + if (comp->name != NULL) { + if (xmlValidateQName(comp->name, 0)) { + xsltTransformError(NULL, style, inst, + "xsl:element : invalid name\n"); + if (style != NULL) style->errors++; + } + } comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"namespace", XSLT_NAMESPACE, &comp->has_ns); @@ -452,7 +424,7 @@ xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) { defaultNs = xmlSearchNs(inst->doc, inst, NULL); if (defaultNs != NULL) { - comp->ns = xmlStrdup(defaultNs->href); + comp->ns = xmlDictLookup(style->dict, defaultNs->href, -1); comp->has_ns = 1; } } @@ -463,7 +435,7 @@ xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltAttributeComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt attribute node * * Process the xslt attribute node on the source node @@ -486,6 +458,13 @@ xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) { comp->name = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE, &comp->has_name); + if (comp->name != NULL) { + if (xmlValidateQName(comp->name, 0)) { + xsltTransformError(NULL, style, inst, + "xsl:attribute : invalid QName\n"); + if (style != NULL) style->errors++; + } + } comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"namespace", XSLT_NAMESPACE, &comp->has_ns); @@ -494,7 +473,7 @@ xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltCommentComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt comment node * * Process the xslt comment node on the source node @@ -514,7 +493,7 @@ xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltProcessingInstructionComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt processing-instruction node * * Process the xslt processing-instruction node on the source node @@ -538,7 +517,7 @@ xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltCopyOfComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt copy-of node * * Process the xslt copy-of node on the source node @@ -555,7 +534,7 @@ xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { inst->_private = comp; comp->inst = inst; - comp->select = xsltGetNsProp(inst, (const xmlChar *)"select", + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select == NULL) { xsltTransformError(NULL, style, inst, @@ -563,7 +542,7 @@ xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { if (style != NULL) style->errors++; return; } - comp->comp = xmlXPathCompile(comp->select); + comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:copy-of : could not compile select expression '%s'\n", @@ -574,7 +553,7 @@ xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltValueOfComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt value-of node * * Process the xslt value-of node on the source node @@ -582,7 +561,7 @@ xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { xsltStylePreCompPtr comp; - xmlChar *prop; + const xmlChar *prop; if ((style == NULL) || (inst == NULL)) return; @@ -592,7 +571,7 @@ xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { inst->_private = comp; comp->inst = inst; - prop = xsltGetNsProp(inst, + prop = xsltGetCNsProp(style, inst, (const xmlChar *)"disable-output-escaping", XSLT_NAMESPACE); if (prop != NULL) { @@ -604,9 +583,8 @@ xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { "xsl:value-of : disable-output-escaping allows only yes or no\n"); if (style != NULL) style->warnings++; } - xmlFree(prop); } - comp->select = xsltGetNsProp(inst, (const xmlChar *)"select", + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select == NULL) { xsltTransformError(NULL, style, inst, @@ -614,7 +592,7 @@ xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { if (style != NULL) style->errors++; return; } - comp->comp = xmlXPathCompile(comp->select); + comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:value-of : could not compile select expression '%s'\n", @@ -625,7 +603,7 @@ xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltWithParamComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt with-param node * * Process the xslt with-param node on the source node @@ -633,7 +611,7 @@ xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { xsltStylePreCompPtr comp; - xmlChar *prop; + const xmlChar *prop; if ((style == NULL) || (inst == NULL)) return; @@ -646,7 +624,7 @@ xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { /* * The full namespace resolution can be done statically */ - prop = xsltGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE); if (prop == NULL) { xsltTransformError(NULL, style, inst, "xsl:with-param : name is missing\n"); @@ -669,10 +647,10 @@ xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { } } - comp->select = xsltGetNsProp(inst, (const xmlChar *)"select", + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select != NULL) { - comp->comp = xmlXPathCompile(comp->select); + comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:param : could not compile select expression '%s'\n", @@ -689,7 +667,7 @@ xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltNumberComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @cur: the xslt number node * * Process the xslt number node on the source node @@ -697,7 +675,7 @@ xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { xsltStylePreCompPtr comp; - xmlChar *prop; + const xmlChar *prop; if ((style == NULL) || (cur == NULL)) return; @@ -711,24 +689,24 @@ xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { comp->numdata.doc = cur->doc; comp->numdata.node = cur; - comp->numdata.value = xsltGetNsProp(cur, (const xmlChar *)"value", + comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value", XSLT_NAMESPACE); prop = xsltEvalStaticAttrValueTemplate(style, cur, (const xmlChar *)"format", XSLT_NAMESPACE, &comp->numdata.has_format); if (comp->numdata.has_format == 0) { - comp->numdata.format = xmlStrdup(BAD_CAST("")); + comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0); } else { comp->numdata.format = prop; } - comp->numdata.count = xsltGetNsProp(cur, (const xmlChar *)"count", + comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count", XSLT_NAMESPACE); - comp->numdata.from = xsltGetNsProp(cur, (const xmlChar *)"from", + comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from", XSLT_NAMESPACE); - prop = xsltGetNsProp(cur, (const xmlChar *)"level", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE); if (prop != NULL) { if (xmlStrEqual(prop, BAD_CAST("single")) || xmlStrEqual(prop, BAD_CAST("multiple")) || @@ -742,13 +720,13 @@ xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { } } - prop = xsltGetNsProp(cur, (const xmlChar *)"lang", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE); if (prop != NULL) { XSLT_TODO; /* xsl:number lang attribute */ xmlFree(prop); } - prop = xsltGetNsProp(cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE); if (prop != NULL) { if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) { xsltTransformError(NULL, style, cur, @@ -765,22 +743,19 @@ xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { "xsl:number : invalid value %s for letter-value\n", prop); if (style != NULL) style->warnings++; } - xmlFree(prop); } - prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-separator", + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator", XSLT_NAMESPACE); if (prop != NULL) { comp->numdata.groupingCharacterLen = xmlStrlen(prop); comp->numdata.groupingCharacter = xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen)); - xmlFree(prop); } - prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE); if (prop != NULL) { sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup); - xmlFree(prop); } else { comp->numdata.groupingCharacter = 0; } @@ -788,7 +763,8 @@ xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { /* Set default values */ if (comp->numdata.value == NULL) { if (comp->numdata.level == NULL) { - comp->numdata.level = xmlStrdup(BAD_CAST("single")); + comp->numdata.level = xmlDictLookup(style->dict, + BAD_CAST"single", 6); } } @@ -796,7 +772,7 @@ xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { /** * xsltApplyImportsComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt apply-imports node * * Process the xslt apply-imports node on the source node @@ -816,7 +792,7 @@ xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltCallTemplateComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt call-template node * * Process the xslt call-template node on the source node @@ -824,7 +800,7 @@ xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) { xsltStylePreCompPtr comp; - xmlChar *prop; + const xmlChar *prop; if ((style == NULL) || (inst == NULL)) return; @@ -837,7 +813,7 @@ xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) { /* * The full template resolution can be done statically */ - prop = xsltGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE); if (prop == NULL) { xsltTransformError(NULL, style, inst, "xsl:call-template : name is missing\n"); @@ -864,7 +840,7 @@ xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltApplyTemplatesComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the apply-templates node * * Process the apply-templates node on the source node @@ -872,7 +848,7 @@ xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) { xsltStylePreCompPtr comp; - xmlChar *prop; + const xmlChar *prop; if ((style == NULL) || (inst == NULL)) return; @@ -885,7 +861,7 @@ xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) { /* * Get mode if any */ - prop = xsltGetNsProp(inst, (const xmlChar *)"mode", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, inst, (const xmlChar *)"mode", XSLT_NAMESPACE); if (prop != NULL) { const xmlChar *URI; @@ -901,10 +877,10 @@ xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) { } } } - comp->select = xsltGetNsProp(inst, (const xmlChar *)"select", + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select != NULL) { - comp->comp = xmlXPathCompile(comp->select); + comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:apply-templates : could not compile select expression '%s'\n", @@ -918,7 +894,7 @@ xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltChooseComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt choose node * * Process the xslt choose node on the source node @@ -938,7 +914,7 @@ xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltIfComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt if node * * Process the xslt if node on the source node @@ -955,14 +931,14 @@ xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) { inst->_private = comp; comp->inst = inst; - comp->test = xsltGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE); + comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); if (comp->test == NULL) { xsltTransformError(NULL, style, inst, "xsl:if : test is not defined\n"); if (style != NULL) style->errors++; return; } - comp->comp = xmlXPathCompile(comp->test); + comp->comp = xsltXPathCompile(style, comp->test); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:if : could not compile test expression '%s'\n", @@ -973,7 +949,7 @@ xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltWhenComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt if node * * Process the xslt if node on the source node @@ -990,14 +966,14 @@ xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) { inst->_private = comp; comp->inst = inst; - comp->test = xsltGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE); + comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); if (comp->test == NULL) { xsltTransformError(NULL, style, inst, "xsl:when : test is not defined\n"); if (style != NULL) style->errors++; return; } - comp->comp = xmlXPathCompile(comp->test); + comp->comp = xsltXPathCompile(style, comp->test); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:when : could not compile test expression '%s'\n", @@ -1008,7 +984,7 @@ xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltForEachComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt for-each node * * Process the xslt for-each node on the source node @@ -1025,14 +1001,14 @@ xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) { inst->_private = comp; comp->inst = inst; - comp->select = xsltGetNsProp(inst, (const xmlChar *)"select", + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select == NULL) { xsltTransformError(NULL, style, inst, "xsl:for-each : select is missing\n"); if (style != NULL) style->errors++; } else { - comp->comp = xmlXPathCompile(comp->select); + comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:for-each : could not compile select expression '%s'\n", @@ -1045,7 +1021,7 @@ xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltVariableComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt variable node * * Process the xslt variable node on the source node @@ -1053,7 +1029,7 @@ xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { xsltStylePreCompPtr comp; - xmlChar *prop; + const xmlChar *prop; if ((style == NULL) || (inst == NULL)) return; @@ -1066,7 +1042,7 @@ xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { /* * The full template resolution can be done statically */ - prop = xsltGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE); if (prop == NULL) { xsltTransformError(NULL, style, inst, "xsl:variable : name is missing\n"); @@ -1089,10 +1065,10 @@ xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { } } - comp->select = xsltGetNsProp(inst, (const xmlChar *)"select", + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select != NULL) { - comp->comp = xmlXPathCompile(comp->select); + comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:variable : could not compile select expression '%s'\n", @@ -1109,7 +1085,7 @@ xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { /** * xsltParamComp: - * @style: a XSLT process context + * @style: an XSLT compiled stylesheet * @inst: the xslt param node * * Process the xslt param node on the source node @@ -1117,7 +1093,7 @@ xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { xsltStylePreCompPtr comp; - xmlChar *prop; + const xmlChar *prop; if ((style == NULL) || (inst == NULL)) return; @@ -1130,7 +1106,7 @@ xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { /* * The full template resolution can be done statically */ - prop = xsltGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE); + prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE); if (prop == NULL) { xsltTransformError(NULL, style, inst, "xsl:param : name is missing\n"); @@ -1153,10 +1129,10 @@ xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { } } - comp->select = xsltGetNsProp(inst, (const xmlChar *)"select", + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select != NULL) { - comp->comp = xmlXPathCompile(comp->select); + comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:param : could not compile select expression '%s'\n", diff --git a/libxslt/templates.c b/libxslt/templates.c index 1af31c9..f120a5d 100644 --- a/libxslt/templates.c +++ b/libxslt/templates.c @@ -393,7 +393,7 @@ xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, * Returns the static string value or NULL, must be deallocated by the * caller. */ -xmlChar * +const xmlChar * xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr node, const xmlChar *name, const xmlChar *ns, int *found) { const xmlChar *ret; @@ -414,7 +414,9 @@ xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr node, xmlFree(expr); return(NULL); } - return(expr); + ret = xmlDictLookup(style->dict, expr, -1); + xmlFree(expr); + return(ret); } /** @@ -430,6 +432,7 @@ xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr node, xmlAttrPtr xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, xmlAttrPtr cur) { + const xmlChar *value; xmlNsPtr ns; xmlAttrPtr ret; if ((ctxt == NULL) || (cur == NULL)) @@ -438,20 +441,18 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, if (cur->type != XML_ATTRIBUTE_NODE) return(NULL); + if ((cur->children == NULL) || (cur->children->type != XML_TEXT_NODE) || + (cur->children->next != NULL)) { + xsltTransformError(ctxt, NULL, cur->parent, + "attribute %s content problem\n", cur->name); + return(NULL); + } + value = cur->children->content; + if (value == NULL) value = BAD_CAST ""; if ((cur->ns != NULL) && (xmlStrEqual(cur->ns->href, XSLT_NAMESPACE))) { if (xmlStrEqual(cur->name, (const xmlChar *)"use-attribute-sets")) { - xmlChar *in; - - if (ctxt->document != NULL) - in = xmlNodeListGetString(ctxt->document->doc, - cur->children, 1); - else - in = xmlNodeListGetString(NULL, cur->children, 1); - if (in != NULL) { - xsltApplyAttributeSet(ctxt, ctxt->node, NULL, in); - xmlFree(in); - } + xsltApplyAttributeSet(ctxt, ctxt->node, NULL, value); } return(NULL); } @@ -460,27 +461,28 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, else ns = NULL; - if (cur->children != NULL) { - xmlChar *in; - xmlChar *out; - - if (ctxt->document != NULL) - in = xmlNodeListGetString(ctxt->document->doc, cur->children, 1); - else - in = xmlNodeListGetString(NULL, cur->children, 1); - - /* TODO: optimize if no template value was detected */ - if (in != NULL) { - out = xsltAttrTemplateValueProcessNode(ctxt, in, cur->parent); - ret = xmlSetNsProp(target, ns, cur->name, out); - if (out != NULL) - xmlFree(out); - xmlFree(in); - } else - ret = xmlSetNsProp(target, ns, cur->name, (const xmlChar *)""); - - } else - ret = xmlSetNsProp(target, ns, cur->name, (const xmlChar *)""); + /* TODO output doc->dict, use xmlNewNsPropEatName() instead */ + ret = xmlNewNsProp(target, ns, cur->name, NULL); + if (ret != NULL) { + xmlNodePtr text; + + text = xmlNewText(NULL); + if (text != NULL) { + ret->last = ret->children = text; + text->parent = (xmlNodePtr) ret; + if (cur->_private != NULL) { + xmlChar *val; + val = xsltEvalAVT(ctxt, cur->_private, cur->parent); + if (val == NULL) { + text->content = xmlStrdup("runtime error"); + } else { + text->content = val; + } + } else { + text->content = xmlStrdup(value); + } + } + } return(ret); } diff --git a/libxslt/templates.h b/libxslt/templates.h index f54948e..b9a6e8f 100644 --- a/libxslt/templates.h +++ b/libxslt/templates.h @@ -34,7 +34,7 @@ XSLTPUBFUN xmlChar * XSLTCALL xmlNodePtr node, const xmlChar *name, const xmlChar *ns); -XSLTPUBFUN xmlChar * XSLTCALL +XSLTPUBFUN const xmlChar * XSLTCALL xsltEvalStaticAttrValueTemplate (xsltStylesheetPtr style, xmlNodePtr node, const xmlChar *name, diff --git a/libxslt/transform.c b/libxslt/transform.c index 1a69100..c83d154 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -65,6 +65,8 @@ static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, int xsltMaxDepth = 5000; +xmlDictPtr xmlDictCreateSub(xmlDictPtr sub); + /* * Useful macros */ @@ -450,6 +452,8 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { cur->traceCode = (unsigned long*) &xsltDefaultTrace; cur->parserOptions = XSLT_PARSE_OPTIONS; + cur->dict = xmlDictCreateSub(style->dict); + return(cur); } @@ -494,6 +498,7 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) { xsltFreeDocuments(ctxt); xsltFreeCtxtExts(ctxt); xsltFreeRVTs(ctxt); + xmlDictFree(ctxt->dict); memset(ctxt, -1, sizeof(xsltTransformContext)); xmlFree(ctxt); } @@ -2161,6 +2166,8 @@ xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, res = xmlNewDoc(style->version); if (res == NULL) goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); } else { xsltTransformError(ctxt, NULL, inst, "xsltDocumentElem: unsupported method %s\n", @@ -2172,6 +2179,8 @@ xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, res = xmlNewDoc(style->version); if (res == NULL) goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); } res->charset = XML_CHAR_ENCODING_UTF8; if (style->encoding != NULL) @@ -2499,10 +2508,9 @@ xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, void xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr comp) { - xmlChar *prop = NULL, *attributes = NULL; - xmlChar *ncname = NULL, *name, *namespace; - xmlChar *prefix = NULL; - xmlChar *value = NULL; + xmlChar *prop = NULL, *attributes = NULL, *namespace; + const xmlChar *name; + const xmlChar *prefix; xmlNsPtr ns = NULL, oldns = NULL; xmlNodePtr copy; xmlNodePtr oldInsert; @@ -2526,33 +2534,27 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, if (prop == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:element : name is missing\n"); - goto error; + return; } - name = prop; - } else { - name = comp->name; - } - - if (xmlValidateQName(name, 0)) { - xsltTransformError(ctxt, NULL, inst, - "xsl:element : invalid name\n"); - /* we fall through to catch any other errors if possible */ - } - ncname = xmlSplitQName2(name, &prefix); - if (ncname == NULL) { - prefix = NULL; + if (xmlValidateQName(prop, 0)) { + xsltTransformError(ctxt, NULL, inst, + "xsl:element : invalid name\n"); + /* we fall through to catch any other errors if possible */ + } + name = xsltSplitQName(ctxt->dict, prop, &prefix); + xmlFree(prop); } else { - name = ncname; + name = xsltSplitQName(ctxt->dict, comp->name, &prefix); } /* * Create the new element */ - copy = xmlNewDocNode(ctxt->output, NULL, name, NULL); + copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL); if (copy == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:element : creation of %s failed\n", name); - goto error; + return; } xmlAddChild(ctxt->insert, copy); ctxt->insert = copy; @@ -2577,7 +2579,7 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltGenericDebug(xsltGenericDebugContext, "xsltElement: xml prefix forbidden\n"); #endif - goto error; + return; } oldns = xmlSearchNs(inst->doc, inst, prefix); if (oldns == NULL) { @@ -2623,16 +2625,6 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltApplyOneTemplate(ctxt, ctxt->node, inst->children, NULL, NULL); ctxt->insert = oldInsert; - -error: - if (prop != NULL) - xmlFree(prop); - if (ncname != NULL) - xmlFree(ncname); - if (prefix != NULL) - xmlFree(prefix); - if (value != NULL) - xmlFree(value); } @@ -2692,7 +2684,7 @@ xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node, void xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr comp) { - xmlChar *ncname = NULL, *name; + const xmlChar *name; xmlChar *value = NULL; xmlNodePtr pi; @@ -2702,14 +2694,13 @@ xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, if (comp->has_name == 0) return; if (comp->name == NULL) { - ncname = xsltEvalAttrValueTemplate(ctxt, inst, + name = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name", XSLT_NAMESPACE); - if (ncname == NULL) { + if (name == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:processing-instruction : name is missing\n"); goto error; } - name = ncname; } else { name = comp->name; } @@ -2725,10 +2716,10 @@ xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, #ifdef WITH_XSLT_DEBUG_PROCESS if (value == NULL) { XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, - "xsltProcessingInstruction: %s empty\n", ncname)); + "xsltProcessingInstruction: %s empty\n", name)); } else { XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, - "xsltProcessingInstruction: %s content %s\n", ncname, value)); + "xsltProcessingInstruction: %s content %s\n", name, value)); } #endif @@ -2736,8 +2727,8 @@ xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlAddChild(ctxt->insert, pi); error: - if (ncname != NULL) - xmlFree(ncname); + if ((name != NULL) && (name != comp->name)) + xmlFree((xmlChar *) name); if (value != NULL) xmlFree(value); } @@ -3963,6 +3954,8 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, } if (res == NULL) goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n", @@ -3971,11 +3964,15 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, res = htmlNewDoc(doctypeSystem, doctypePublic); if (res == NULL) goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); } else if (xmlStrEqual(method, (const xmlChar *) "text")) { ctxt->type = XSLT_OUTPUT_TEXT; res = xmlNewDoc(style->version); if (res == NULL) goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); } else { xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, "xsltApplyStylesheetInternal: unsupported method %s\n", @@ -3987,6 +3984,8 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, res = xmlNewDoc(style->version); if (res == NULL) goto error; + res->dict = ctxt->dict; + xmlDictReference(ctxt->dict); } res->charset = XML_CHAR_ENCODING_UTF8; if (style->encoding != NULL) diff --git a/libxslt/variables.c b/libxslt/variables.c index 323487f..9e7a491 100644 --- a/libxslt/variables.c +++ b/libxslt/variables.c @@ -57,6 +57,8 @@ xsltCreateRVT(xsltTransformContextPtr ctxt) container = xmlNewDoc(NULL); if (container == NULL) return(NULL); + container->dict = ctxt->dict; + xmlDictReference(container->dict); container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt"); container->doc = container; @@ -184,9 +186,9 @@ xsltCopyStackElem(xsltStackElemPtr elem) { "xsltCopyStackElem : malloc failed\n"); return(NULL); } - cur->name = xmlStrdup(elem->name); - cur->nameURI = xmlStrdup(elem->nameURI); - cur->select = xmlStrdup(elem->select); + cur->name = elem->name; + cur->nameURI = elem->nameURI; + cur->select = elem->select; cur->tree = elem->tree; cur->comp = elem->comp; cur->computed = 0; @@ -204,12 +206,6 @@ static void xsltFreeStackElem(xsltStackElemPtr elem) { if (elem == NULL) return; - if (elem->name != NULL) - xmlFree(elem->name); - if (elem->nameURI != NULL) - xmlFree(elem->nameURI); - if (elem->select != NULL) - xmlFree(elem->select); if (elem->value != NULL) xmlXPathFreeObject(elem->value); @@ -255,8 +251,6 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, * Do the lookup from the top of the stack, but * don't use params being computed in a call-param */ - ; - for (i = ctxt->varsNr; i > ctxt->varsBase; i--) { cur = ctxt->varsTab[i-1]; while (cur != NULL) { @@ -507,7 +501,7 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) { xmlNodePtr oldInst; int oldNsNr; xmlNsPtr *oldNamespaces; - xmlChar *name; + const xmlChar *name; if ((ctxt == NULL) || (elem == NULL)) return(NULL); @@ -761,8 +755,8 @@ xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name, if (elem == NULL) return(-1); elem->comp = comp; - elem->name = xmlStrdup(name); - elem->select = xmlStrdup(select); + elem->name = xmlDictLookup(style->dict, name, -1); + elem->select = xmlDictLookup(style->dict, select, -1); if (ns_uri) elem->nameURI = xmlStrdup(ns_uri); elem->tree = tree; @@ -834,8 +828,7 @@ xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, int eval) { xsltStylesheetPtr style; - xmlChar *ncname; - xmlChar *prefix; + const xmlChar *prefix; const xmlChar *href; xmlXPathCompExprPtr comp; xmlXPathObjectPtr result; @@ -865,40 +858,29 @@ xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, * Name lookup */ - ncname = xmlSplitQName2(name, &prefix); + name = xsltSplitQName(ctxt->dict, name, &prefix); href = NULL; - if (ncname != NULL) { - if (prefix != NULL) { - xmlNsPtr ns; - - ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc), - prefix); - if (ns == NULL) { - xsltTransformError(ctxt, style, NULL, - "user param : no namespace bound to prefix %s\n", prefix); - href = NULL; - } else { - href = ns->href; - } - xmlFree(prefix); - prefix = NULL; - } else { + if (prefix != NULL) { + xmlNsPtr ns; + + ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc), + prefix); + if (ns == NULL) { + xsltTransformError(ctxt, style, NULL, + "user param : no namespace bound to prefix %s\n", prefix); href = NULL; + } else { + href = ns->href; } - xmlFree(ncname); - ncname = NULL; - } else { - href = NULL; - ncname = xmlStrdup(name); } - if (ncname == NULL) + if (name == NULL) return (-1); - res_ptr = xmlHashLookup2(ctxt->globalVars, ncname, href); + res_ptr = xmlHashLookup2(ctxt->globalVars, name, href); if (res_ptr != 0) { xsltTransformError(ctxt, style, NULL, - "Global parameter %s already defined\n", ncname); + "Global parameter %s already defined\n", name); } /* @@ -909,9 +891,8 @@ xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, while (elem != NULL) { if ((elem->comp != NULL) && (elem->comp->type == XSLT_FUNC_VARIABLE) && - (xmlStrEqual(elem->name, ncname)) && + (xmlStrEqual(elem->name, name)) && (xmlStrEqual(elem->nameURI, href))) { - xmlFree(ncname); return(0); } elem = elem->next; @@ -953,7 +934,6 @@ xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, xsltTransformError(ctxt, style, NULL, "Evaluating user parameter %s failed\n", name); ctxt->state = XSLT_STATE_STOPPED; - xmlFree(ncname); return(-1); } } @@ -980,13 +960,13 @@ xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, elem = xsltNewStackElem(); if (elem != NULL) { - elem->name = xmlStrdup(ncname); + elem->name = name; if (value != NULL) - elem->select = xmlStrdup(value); + elem->select = xmlDictLookup(ctxt->dict, value, -1); else elem->select = NULL; if (href) - elem->nameURI = xmlStrdup(href); + elem->nameURI = xmlDictLookup(ctxt->dict, href, -1); elem->tree = NULL; elem->computed = 1; if (eval == 0) { @@ -1001,13 +981,12 @@ xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, * Global parameters are stored in the XPath context variables pool. */ - res = xmlHashAddEntry2(ctxt->globalVars, ncname, href, elem); + res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem); if (res != 0) { xsltFreeStackElem(elem); xsltTransformError(ctxt, style, NULL, - "Global parameter %s already defined\n", ncname); + "Global parameter %s already defined\n", name); } - xmlFree(ncname); return(0); } @@ -1148,13 +1127,13 @@ xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp, if (elem == NULL) return(NULL); elem->comp = comp; - elem->name = xmlStrdup(comp->name); + elem->name = comp->name; if (comp->select != NULL) - elem->select = xmlStrdup(comp->select); + elem->select = comp->select; else elem->select = NULL; if (comp->ns) - elem->nameURI = xmlStrdup(comp->ns); + elem->nameURI = comp->ns; elem->tree = tree; if (elem->computed == 0) { elem->value = xsltEvalVariable(ctxt, elem, comp); diff --git a/libxslt/xslt.c b/libxslt/xslt.c index 8e3fdf7..dfe191d 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -372,6 +372,7 @@ xsltNewStylesheet(void) { cur->exclPrefixTab = NULL; cur->extInfos = NULL; cur->extrasNr = 0; + cur->dict = xmlDictCreate(); xsltInit(); @@ -513,10 +514,14 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) xmlFree(sheet->doctypeSystem); if (sheet->mediaType != NULL) xmlFree(sheet->mediaType); + if (sheet->attVTs) + xsltFreeAVTList(sheet->attVTs); if (sheet->imports != NULL) xsltFreeStylesheetList(sheet->imports); + xmlDictFree(sheet->dict); + memset(sheet, -1, sizeof(xsltStylesheet)); xmlFree(sheet); } @@ -1194,6 +1199,7 @@ xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) { goto skip_children; } } + /* * Remove excluded prefixes */ @@ -1243,6 +1249,7 @@ xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) { exclPrefixPop(style); goto skip_children; } + } else if (cur->type == XML_TEXT_NODE) { if (IS_BLANK_NODE(cur)) { if (xmlNodeGetSpacePreserve(cur) != 1) { @@ -1469,12 +1476,24 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { delete = cur; goto skip_children; } - } else if ((cur->ns != NULL) && (style->nsDefs != NULL)) { - if (xsltCheckExtPrefix(style, cur->ns->prefix)) { - /* - * okay this is an extension element compile it too - */ - xsltStylePreCompute(style, cur); + } else if ((cur->ns != NULL) && (style->nsDefs != NULL) && + (xsltCheckExtPrefix(style, cur->ns->prefix))) { + /* + * okay this is an extension element compile it too + */ + xsltStylePreCompute(style, cur); + } else { + /* + * This is an element which will be output as part of the + * template exectution, precompile AVT if found. + */ + if (cur->properties != NULL) { + xmlAttrPtr attr = cur->properties; + + while (attr != NULL) { + xsltCompileAttr(style, attr); + attr = attr->next; + } } } @@ -2007,6 +2026,11 @@ xsltParseStylesheetImportedDoc(xmlDocPtr doc, xsltStylesheetPtr style) { ret = xsltNewStylesheet(); if (ret == NULL) return(NULL); + if (doc->dict != NULL) { + xmlDictFree(ret->dict); + ret->dict = doc->dict; + xmlDictReference(ret->dict); + } ret->doc = doc; ret->parent = style; /* needed to prevent loops */ @@ -2089,11 +2113,7 @@ xsltParseStylesheetFile(const xmlChar* filename) { } } -#ifdef XSLT_PARSE_OPTIONS doc = xmlReadFile((const char *) filename, NULL, XSLT_PARSE_OPTIONS); -#else - doc = xmlParseFile((const char *) filename); -#endif if (doc == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltParseStylesheetFile : cannot parse %s\n", filename); @@ -2288,14 +2308,13 @@ xsltLoadStylesheetPI(xmlDocPtr doc) { subtree = ID->parent; fake = xmlNewDoc(NULL); if (fake != NULL) { -#if LIBXML_VERSION >= 20600 /* * the dictionnary should be shared since nodes are * moved over. */ fake->dict = doc->dict; xmlDictReference(doc->dict); -#endif + xmlUnlinkNode(subtree); xmlAddChild((xmlNodePtr) fake, subtree); ret = xsltParseStylesheetDoc(fake); diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index bdc5076..64902a8 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "xsltexports.h" #include "numbersInternals.h" @@ -252,38 +253,38 @@ struct _xsltStylePreComp { * Pre computed values. */ - xmlChar *stype; /* sort */ + const xmlChar *stype; /* sort */ int has_stype; /* sort */ int number; /* sort */ - xmlChar *order; /* sort */ + const xmlChar *order; /* sort */ int has_order; /* sort */ int descending; /* sort */ - xmlChar *lang; /* sort */ + const xmlChar *lang; /* sort */ int has_lang; /* sort */ - xmlChar *case_order; /* sort */ + const xmlChar *case_order; /* sort */ int lower_first; /* sort */ - xmlChar *use; /* copy, element */ + const xmlChar *use; /* copy, element */ int has_use; /* copy, element */ int noescape; /* text */ - xmlChar *name; /* element, attribute, pi */ + const xmlChar *name; /* element, attribute, pi */ int has_name; /* element, attribute, pi */ - xmlChar *ns; /* element */ + const xmlChar *ns; /* element */ int has_ns; /* element */ - xmlChar *mode; /* apply-templates */ - xmlChar *modeURI; /* apply-templates */ + const xmlChar *mode; /* apply-templates */ + const xmlChar *modeURI; /* apply-templates */ - xmlChar *test; /* if */ + const xmlChar *test; /* if */ xsltTemplatePtr templ; /* call-template */ - xmlChar *select; /* sort, copy-of, value-of, apply-templates */ + const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ int ver11; /* document */ - xmlChar *filename; /* document URL */ + const xmlChar *filename; /* document URL */ int has_filename; /* document */ xsltNumberData numdata; /* number */ @@ -303,12 +304,12 @@ typedef xsltStackElem *xsltStackElemPtr; struct _xsltStackElem { struct _xsltStackElem *next;/* chained list */ xsltStylePreCompPtr comp; /* the compiled form */ - int computed; /* was the evaluation done */ - xmlChar *name; /* the local part of the name QName */ - xmlChar *nameURI; /* the URI part of the name QName */ - xmlChar *select; /* the eval string */ - xmlNodePtr tree; /* the tree if no eval string or the location */ - xmlXPathObjectPtr value; /* The value if computed */ + int computed; /* was the evaluation done */ + const xmlChar *name; /* the local part of the name QName */ + const xmlChar *nameURI; /* the URI part of the name QName */ + const xmlChar *select; /* the eval string */ + xmlNodePtr tree; /* the tree if no eval string or the location */ + xmlXPathObjectPtr value; /* The value if computed */ }; /* @@ -421,6 +422,15 @@ struct _xsltStylesheet { * For keeping track of nested includes */ xsltDocumentPtr includes; /* points to last nested include */ + + /* + * dictionnary: shared between stylesheet, context and documents. + */ + xmlDictPtr dict; + /* + * precompiled attribute value templates. + */ + void *attVTs; }; /* @@ -527,6 +537,11 @@ struct _xsltTransformContext { unsigned long* traceCode; /* pointer to the variable holding the mask */ int parserOptions; /* parser options xmlParserOption */ + + /* + * dictionnary: shared between stylesheet, context and documents. + */ + xmlDictPtr dict; }; /** @@ -554,6 +569,12 @@ struct _xsltTransformContext { #define CHECK_STOPPED0 if (ctxt->state == XSLT_STATE_STOPPED) return(0); /* + * internal value used to indicate attribute value templates + */ + +XSLTPUBVAR void *xsltIsAttVT; + +/* * Functions associated to the internal types xsltDecimalFormatPtr xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name); @@ -616,6 +637,18 @@ XSLTPUBFUN int XSLTCALL XSLTPUBFUN void XSLTCALL xsltFreeRVTs (xsltTransformContextPtr ctxt); +/* + * Extra functions for Attribute Value Templates + */ +XSLTPUBFUN void XSLTCALL + xsltCompileAttr (xsltStylesheetPtr style, + xmlAttrPtr attr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalAVT (xsltTransformContextPtr ctxt, + void *avt, + xmlNodePtr node); +XSLTPUBFUN void XSLTCALL + xsltFreeAVTList (void *avt); #ifdef __cplusplus } #endif diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c index bc6f6a3..b984e46 100644 --- a/libxslt/xsltutils.c +++ b/libxslt/xsltutils.c @@ -58,6 +58,95 @@ ************************************************************************/ /** + * xsltGetCNsProp: + * @style: the stylesheet + * @node: the node + * @name: the attribute name + * @nameSpace: the URI of the namespace + * + * Similar to xmlGetNsProp() but with a slightly different semantic + * + * Search and get the value of an attribute associated to a node + * This attribute has to be anchored in the namespace specified, + * or has no namespace and the element is in that namespace. + * + * This does the entity substitution. + * This function looks in DTD attribute declaration for #FIXED or + * default declaration values unless DTD use has been turned off. + * + * Returns the attribute value or NULL if not found. The string is allocated + * in the stylesheet dictionnary. + */ +const xmlChar * +xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node, + const xmlChar *name, const xmlChar *nameSpace) { + xmlAttrPtr prop; + xmlDocPtr doc; + xmlNsPtr ns; + xmlChar *tmp; + const xmlChar *ret; + + if ((node == NULL) || (style == NULL) || (style->dict == NULL)) + return(NULL); + + prop = node->properties; + if (nameSpace == NULL) { + tmp = xmlGetProp(node, name); + goto found; + } + while (prop != NULL) { + /* + * One need to have + * - same attribute names + * - and the attribute carrying that namespace + */ + if ((xmlStrEqual(prop->name, name)) && + (((prop->ns == NULL) && (node->ns != NULL) && + (xmlStrEqual(node->ns->href, nameSpace))) || + ((prop->ns != NULL) && + (xmlStrEqual(prop->ns->href, nameSpace))))) { + + tmp = xmlNodeListGetString(node->doc, prop->children, 1); + goto found; + } + prop = prop->next; + } + + /* + * Check if there is a default declaration in the internal + * or external subsets + */ + doc = node->doc; + if (doc != NULL) { + if (doc->intSubset != NULL) { + xmlAttributePtr attrDecl; + + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); + + if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) { + /* + * The DTD declaration only allows a prefix search + */ + ns = xmlSearchNs(doc, node, attrDecl->prefix); + if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace))) + return(xmlDictLookup(style->dict, + attrDecl->defaultValue, -1)); + } + } + } + return(NULL); +found: + if (tmp == NULL) + ret = xmlDictLookup(style->dict, BAD_CAST "", 0); + else { + ret = xmlDictLookup(style->dict, tmp, -1); + xmlFree(tmp); + } + return(ret); +} +/** * xsltGetNsProp: * @node: the node * @name: the attribute name @@ -506,6 +595,32 @@ xsltTransformError(xsltTransformContextPtr ctxt, ************************************************************************/ /** + * xsltSplitQName: + * @dict: a dictionnary + * @name: the full QName + * @prefix: the return value + * + * Split QNames into prefix and local names, both allocated from a dictionnary. + * + * Returns: the localname or NULL in case of error. + */ +const xmlChar * +xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) { + int len = 0; + const xmlChar *ret = NULL; + + *prefix = NULL; + if ((name == NULL) || (dict == NULL)) return(NULL); + if (name[0] == ':') + return(xmlDictLookup(dict, name, -1)); + while ((name[len] != 0) && (name[len] != ':')) len++; + if (name[len] == 0) return(xmlDictLookup(dict, name, -1)); + *prefix = xmlDictLookup(dict, name, len); + ret = xmlDictLookup(dict, &name[len + 1], -1); + return(ret); +} + +/** * xsltGetQNameURI: * @node: the node holding the QName * @name: pointer to the initial QName value @@ -1723,6 +1838,38 @@ xsltGetProfileInformation(xsltTransformContextPtr ctxt) /************************************************************************ * * + * Hooks for libxml2 XPath * + * * + ************************************************************************/ + +/** + * xsltXPathCompile: + * @style: the stylesheet + * @str: the XPath expression + * + * Compile an XPath expression + * + * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. + * the caller has to free the object. + */ +xmlXPathCompExprPtr +xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) { + xmlXPathContext xctxt; + xmlXPathCompExprPtr ret; + + memset(&xctxt, 0, sizeof(xctxt)); + if (style != NULL) + xctxt.dict = style->dict; + ret = xmlXPathCtxtCompile(&xctxt, str); + /* + * TODO: there is a lot of optimizations which should be possible + * like variable slot precomputations, function precomputations, etc. + */ + + return(ret); +} +/************************************************************************ + * * * Hooks for the debugger * * * ************************************************************************/ diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h index 547c82b..d1f0cfe 100644 --- a/libxslt/xsltutils.h +++ b/libxslt/xsltutils.h @@ -21,6 +21,7 @@ #include #endif #include +#include #include #include "xsltexports.h" #include "xsltInternals.h" @@ -83,11 +84,18 @@ extern "C" { /* * Our own version of namespaced atributes lookup. */ -XSLTPUBFUN xmlChar * XSLTCALL xsltGetNsProp (xmlNodePtr node, - const xmlChar *name, - const xmlChar *nameSpace); -XSLTPUBFUN int XSLTCALL xsltGetUTF8Char (const unsigned char *utf, - int *len); +XSLTPUBFUN xmlChar * XSLTCALL + xsltGetNsProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *nameSpace); +XSLTPUBFUN const xmlChar * XSLTCALL + xsltGetCNsProp (xsltStylesheetPtr style, + xmlNodePtr node, + const xmlChar *name, + const xmlChar *nameSpace); +XSLTPUBFUN int XSLTCALL + xsltGetUTF8Char (const unsigned char *utf, + int *len); /* * XSLT Debug Tracing Tracing Types @@ -191,6 +199,10 @@ XSLTPUBFUN xmlXPathObjectPtr * XSLTCALL * QNames handling. */ +XSLTPUBFUN const xmlChar * XSLTCALL + xsltSplitQName (xmlDictPtr dict, + const xmlChar *name, + const xmlChar **prefix); XSLTPUBFUN const xmlChar * XSLTCALL xsltGetQNameURI (xmlNodePtr node, xmlChar **name); @@ -222,6 +234,13 @@ XSLTPUBFUN int XSLTCALL xsltStylesheetPtr style); /* + * XPath interface + */ +XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + xsltXPathCompile (xsltStylesheetPtr style, + const xmlChar *str); + +/* * Profiling. */ XSLTPUBFUN void XSLTCALL -- 2.7.4