diff --git a/ChangeLog b/ChangeLog index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_Q2hhbmdlTG9n..96ed246c7e7da2540cd70b1205c31e900fe7ce42_Q2hhbmdlTG9n 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Sat Jan 20 23:35:07 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> + + * libxslt/Makefile.am libxslt/template.[ch]: added a template + specific module. Added attribute value template, at least in + one spot. + * tests/REC2/Makefile.am tests/REC2/svg.xml: the SVG test from + the spec now works too. + * libxslt/variables.c: fixed the debug + * libxslt/xslt.c: fixed an ugly uninitialized variable + * libxslt/transform.c: now using attr template processing + Sat Jan 20 17:59:20 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> * libxslt/transform.c libxslt/variables.[ch] libxslt/xslt.c diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_bGlieHNsdC9NYWtlZmlsZS5hbQ==..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC9NYWtlZmlsZS5hbQ== 100644 --- a/libxslt/Makefile.am +++ b/libxslt/Makefile.am @@ -10,6 +10,8 @@ xsltutils.h \ pattern.c \ pattern.h \ + templates.c \ + templates.h \ variables.c \ variables.h \ transform.c \ diff --git a/libxslt/templates.c b/libxslt/templates.c new file mode 100644 index 0000000000000000000000000000000000000000..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC90ZW1wbGF0ZXMuYw== --- /dev/null +++ b/libxslt/templates.c @@ -0,0 +1,266 @@ +/* + * templates.c: Implementation of the template processing + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * Daniel.Veillard@imag.fr + */ + +#include "xsltconfig.h" + +#include <string.h> + +#include <libxml/xmlmemory.h> +#include <libxml/tree.h> +#include <libxml/xmlerror.h> +#include <libxml/xpathInternals.h> +#include <libxml/parserInternals.h> +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "variables.h" +#include "templates.h" + +#define DEBUG_TEMPLATES + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltEvalXPathString: + * @ctxt: the XSLT transformation context + * @str: the XPath expression + * + * Process the expression using XPath and get a string + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltEvalXPathString(xsltTransformContextPtr ctxt, const xmlChar *expr) { + xmlChar *ret = NULL; + xmlXPathObjectPtr res, tmp; + xmlXPathParserContextPtr xpathParserCtxt; + + if (ctxt->xpathCtxt == NULL) { + xmlXPathInit(); + ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc); + if (ctxt->xpathCtxt == NULL) + return(NULL); + XSLT_REGISTER_VARIABLE_LOOKUP(ctxt); + } + xpathParserCtxt = + xmlXPathNewParserContext(expr, ctxt->xpathCtxt); + if (xpathParserCtxt == NULL) + return(NULL); + ctxt->xpathCtxt->node = ctxt->node; + xmlXPathEvalExpr(xpathParserCtxt); + xmlXPathStringFunction(xpathParserCtxt, 1); + res = valuePop(xpathParserCtxt); + do { + tmp = valuePop(xpathParserCtxt); + if (tmp != NULL) { + xmlXPathFreeObject(tmp); + } + } while (tmp != NULL); + if (res != NULL) { + if (res->type == XPATH_STRING) { + ret = res->stringval; + res->stringval = NULL; + } else { + xsltGenericError(xsltGenericErrorContext, + "xpath : string() function didn't returned a String\n"); + } + xmlXPathFreeObject(res); + } + xmlXPathFreeParserContext(xpathParserCtxt); +#ifdef DEBUG_TEMPLATES + xsltGenericDebug(xsltGenericDebugContext, + "xsltEvalXPathString: %s returns %s\n", expr, ret); +#endif + return(ret); +} + +/** + * xsltAttrTemplateValueProcess: + * @ctxt: the XSLT transformation context + * @str: the attribute template node value + * + * Process the given node and return the new string value. + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) { + xmlChar *ret = NULL, *ret2; + const xmlChar *cur; + xmlChar *expr, *val; + + if (str == NULL) return(NULL); + cur = str; + while (*cur != 0) { + if (*cur == '{') { + ret2 = xmlStrncat(ret, str, cur - str); + if (ret != NULL) + xmlFree(ret); + ret = ret2; + str = cur; + cur++; + while ((*cur != 0) && (*cur != '}')) cur++; + if (*cur == 0) { + ret2 = xmlStrncat(ret, str, cur - str); + xmlFree(ret); + return(ret2); + } + str++; + expr = xmlStrndup(str, cur - str); + if (expr == NULL) + return(ret); + else { + val = xsltEvalXPathString(ctxt, expr); + xmlFree(expr); + if (val != NULL) { + ret2 = xmlStrcat(ret, val); + if (ret != NULL) + xmlFree(ret); + xmlFree(val); + ret = ret2; + } + } + cur++; + str = cur; + } else + cur++; + } + if (cur != str) { + ret2 = xmlStrncat(ret, str, cur - str); + if (ret != NULL) + xmlFree(ret); + ret = ret2; + } + + return(ret); +} + +/** + * xsltAttrTemplateProcess: + * @ctxt: the XSLT transformation context + * @target: the result node + * @cur: the attribute template node + * + * Process the given attribute and return the new processed copy. + * + * Returns the attribute replacement. + */ +xmlAttrPtr +xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, + xmlAttrPtr cur) { + xmlAttrPtr ret; + if ((ctxt == NULL) || (cur == NULL)) + return(NULL); + + if (cur->type != XML_ATTRIBUTE_NODE) + return(NULL); + + if ((cur->ns != NULL) && + (xmlStrEqual(cur->ns->href, XSLT_NAMESPACE))) { + /* TODO: check for replacement namespaces */ + return(NULL); + } + + ret = xmlNewDocProp(ctxt->output, cur->name, NULL); + if (ret == NULL) return(NULL); + ret->parent = target; + + if ((cur->ns != NULL) && (target != NULL)) { + if ((target != NULL) && (target->ns != NULL) && + (xmlStrEqual(target->ns->href, cur->ns->href))) { + ret->ns = target->ns; + } else { + xmlNsPtr ns; + + ns = xmlSearchNsByHref(ctxt->output, target, cur->ns->href); + if (ns != NULL) { + ret->ns = ns; + } else { + ns = xmlNewNs(target, cur->ns->href, cur->ns->prefix); + ret->ns = ns; + } + } + } else + ret->ns = NULL; + + if (cur->children != NULL) { + xmlChar *in = xmlNodeListGetString(ctxt->doc, cur->children, 1); + xmlChar *out; + + if (in != NULL) { + out = xsltAttrTemplateValueProcess(ctxt, in); + ret->children = xmlNewDocText(ctxt->output, out); + xmlFree(out); + xmlFree(in); + } else + ret->children = NULL; + + } else + ret->children = NULL; + return(ret); +} + + +/** + * xsltAttrListTemplateProcess: + * @ctxt: the XSLT transformation context + * @target: the element where the attributes will be grafted + * @cur: the first attribute + * + * Do a copy of an attribute list with attribute template processing + * + * Returns: a new xmlAttrPtr, or NULL in case of error. + */ +xmlAttrPtr +xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, + xmlNodePtr target, xmlAttrPtr cur) { + xmlAttrPtr ret = NULL; + xmlAttrPtr p = NULL,q; + + while (cur != NULL) { + q = xsltAttrTemplateProcess(ctxt, target, cur); + if (p == NULL) { + ret = p = q; + } else { + p->next = q; + q->prev = p; + p = q; + } + cur = cur->next; + } + return(ret); +} + + +/** + * xsltTemplateProcess: + * @ctxt: the XSLT transformation context + * @node: the attribute template node + * + * Process the given node and return the new string value. + * + * Returns the computed tree replacement + */ +xmlNodePtr * +xsltTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr node) { + if (node == NULL) + return(NULL); + + return(0); +} + + diff --git a/libxslt/templates.h b/libxslt/templates.h new file mode 100644 index 0000000000000000000000000000000000000000..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC90ZW1wbGF0ZXMuaA== --- /dev/null +++ b/libxslt/templates.h @@ -0,0 +1,37 @@ +/* + * templates.h: interface for the template processing + * + * See Copyright for the status of this software. + * + * Daniel.Veillard@imag.fr + */ + +#ifndef __XML_XSLT_TEMPLATES_H__ +#define __XML_XSLT_TEMPLATES_H__ + +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +xmlChar * xsltEvalXPathString (xsltTransformContextPtr ctxt, + const xmlChar *expr); +xmlNodePtr * xsltTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr node); +xmlAttrPtr xsltAttrListTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr target, + xmlAttrPtr cur); +xmlAttrPtr xsltAttrTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr target, + xmlAttrPtr attr); +xmlChar * xsltAttrTemplateValueProcess (xsltTransformContextPtr ctxt, + const xmlChar* attr); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_TEMPLATES_H__ */ + diff --git a/libxslt/transform.c b/libxslt/transform.c index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_bGlieHNsdC90cmFuc2Zvcm0uYw==..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC90cmFuc2Zvcm0uYw== 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -30,6 +30,7 @@ #include "pattern.h" #include "transform.h" #include "variables.h" +#include "templates.h" #define DEBUG_PROCESS @@ -839,7 +840,8 @@ * TODO: Do the substitution of {} XPath expressions !!! */ if (cur->properties != NULL) - copy->properties = xmlCopyPropList(copy, cur->properties); + copy->properties = xsltAttrListTemplateProcess(ctxt, + copy, cur->properties); } /* diff --git a/libxslt/variables.c b/libxslt/variables.c index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_bGlieHNsdC92YXJpYWJsZXMuYw==..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC92YXJpYWJsZXMuYw== 100644 --- a/libxslt/variables.c +++ b/libxslt/variables.c @@ -25,7 +25,7 @@ #include "xsltutils.h" #include "variables.h" -#define DEBUG_VARIABLES +#define DEBUG_VARIABLE /* * Types are private: @@ -293,6 +293,10 @@ if (name == NULL) return(-1); +#ifdef DEBUG_VARIABLE + xsltGenericDebug(xsltGenericDebugContext, + "Defineing variable %s\n", name); +#endif elem = xsltNewStackElem(); if (elem == NULL) return(-1); @@ -310,6 +314,7 @@ ctxt->xpathCtxt); if (xpathParserCtxt == NULL) goto error; + ctxt->xpathCtxt->node = ctxt->node; xmlXPathEvalExpr(xpathParserCtxt); result = valuePop(xpathParserCtxt); do { @@ -369,6 +374,5 @@ #endif TODO /* Variable value computation needed */ } -error: if (elem->value != NULL) return(xmlXPathObjectCopy(elem->value)); @@ -373,5 +377,9 @@ if (elem->value != NULL) return(xmlXPathObjectCopy(elem->value)); +#ifdef DEBUG_VARIABLE + xsltGenericDebug(xsltGenericDebugContext, + "variable not found %s\n", name); +#endif return(NULL); } @@ -426,9 +434,8 @@ } #ifdef DEBUG_VARIABLE - if (ret != NULL) - xsltGenericDebug(xsltGenericDebugContext, - "Parsing variable %s\n", name); + xsltGenericDebug(xsltGenericDebugContext, + "Parsing variable %s\n", name); #endif select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE); diff --git a/libxslt/xslt.c b/libxslt/xslt.c index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_bGlieHNsdC94c2x0LmM=..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC94c2x0LmM= 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -713,7 +713,7 @@ if (top == NULL) return; - prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE); + prop = xmlGetNsProp(top, (const xmlChar *)"version", XSLT_NAMESPACE); if (prop == NULL) { xsltGenericError(xsltGenericErrorContext, "xsl:version is missing: document may not be a stylesheet\n"); diff --git a/tests/REC2/Makefile.am b/tests/REC2/Makefile.am index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_dGVzdHMvUkVDMi9NYWtlZmlsZS5hbQ==..96ed246c7e7da2540cd70b1205c31e900fe7ce42_dGVzdHMvUkVDMi9NYWtlZmlsZS5hbQ== 100644 --- a/tests/REC2/Makefile.am +++ b/tests/REC2/Makefile.am @@ -8,6 +8,10 @@ @($(top_builddir)/libxslt/xsltproc vrml.xsl data.xml > vrml.res ; \ diff vrml.xml vrml.res ; \ grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\ - rm -f doc.res) + rm -f vrml.res) + @($(top_builddir)/libxslt/xsltproc svg.xsl data.xml > svg.res ; \ + diff svg.xml svg.res ; \ + grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\ + rm -f svg.res) diff --git a/tests/REC2/svg.xml b/tests/REC2/svg.xml index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_dGVzdHMvUkVDMi9zdmcueG1s..96ed246c7e7da2540cd70b1205c31e900fe7ce42_dGVzdHMvUkVDMi9zdmcueG1s 100644 --- a/tests/REC2/svg.xml +++ b/tests/REC2/svg.xml @@ -1,18 +1,18 @@ -<svg width="3in" height="3in" - xmlns="http://www.w3.org/Graphics/SVG/svg-19990412.dtd"> - <g style="stroke: #000000"> - <line x1="0" x2="150" y1="150" y2="150"/> - <line x1="0" x2="0" y1="0" y2="150"/> - <text x="0" y="10">Revenue</text> - <text x="150" y="165">Division</text> - <rect x="10" y="50" width="20" height="100"/> - <text x="10" y="165">North</text> - <text x="10" y="45">10</text> - <rect x="50" y="110" width="20" height="40"/> - <text x="50" y="165">South</text> - <text x="50" y="105">4</text> - <rect x="90" y="90" width="20" height="60"/> - <text x="90" y="165">West</text> - <text x="90" y="85">6</text> - </g> +<?xml version="1.0"?> +<svg xmlns="http://www.w3.org/Graphics/SVG/SVG-19990812.dtd" width="3in" height="3in"> + <g style="stroke: #000000"> + <line x1="0" x2="150" y1="150" y2="150"/> + <line x1="0" x2="0" y1="0" y2="150"/> + <text x="0" y="10">Revenue</text> + <text x="150" y="165">Division</text> + <rect x="10" y="50" width="20" height="100"/> + <text x="10" y="165">North</text> + <text x="10" y="45">10</text> + <rect x="50" y="110" width="20" height="40"/> + <text x="50" y="165">South</text> + <text x="50" y="105">4</text> + <rect x="90" y="90" width="20" height="60"/> + <text x="90" y="165">West</text> + <text x="90" y="85">6</text> + </g> </svg>