diff options
author | Daniel Veillard <veillard@src.gnome.org> | 2001-01-17 16:47:36 +0000 |
---|---|---|
committer | Daniel Veillard <veillard@src.gnome.org> | 2001-01-17 16:47:36 +0000 |
commit | 72698cec5af4011028af68ec8dac334d9a1a0a3d (patch) | |
tree | 7002a8a53894ffee6c17697dff6bdb64c1e7ae5c | |
parent | 52862c898778e5602e1f4c5a45926a9db98c3df6 (diff) | |
download | libxslt-72698cec5af4011028af68ec8dac334d9a1a0a3d.tar.gz libxslt-72698cec5af4011028af68ec8dac334d9a1a0a3d.tar.bz2 libxslt-72698cec5af4011028af68ec8dac334d9a1a0a3d.zip |
Continuous hacking ...
- TODO: guess what, it's growing :-(
- configure.in: setup hacking values when compiling in my
own environment.
- libxslt/transform.c libxslt/xsltutils.[hc]: added a first
very rudimentary version of xsl:sort
Daniel
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | TODO | 6 | ||||
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | libxslt/transform.c | 149 | ||||
-rw-r--r-- | libxslt/xsltutils.c | 56 | ||||
-rw-r--r-- | libxslt/xsltutils.h | 12 |
6 files changed, 229 insertions, 5 deletions
@@ -1,3 +1,11 @@ +Wed Jan 17 17:45:20 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> + + * TODO: guess what, it's growing :-( + * configure.in: setup hacking values when compiling in my + own environment. + * libxslt/transform.c libxslt/xsltutils.[hc]: added a first + very rudimentary version of xsl:sort + Wed Jan 17 14:25:25 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> * TODO: more stuff @@ -34,3 +34,9 @@ Error handling: Support Attribute value templates: -> starts to be urgent. Design it in flexible ways but try to optimize to handle most of it at the stylesheet parse time ... + +Sorting: + -> add support for imbricated sorts + -> add lang and case-order + -> add foreign sorting functions (interfaces ?). + diff --git a/configure.in b/configure.in index d506a875..a812342e 100644 --- a/configure.in +++ b/configure.in @@ -10,12 +10,13 @@ AM_MAINTAINER_MODE dnl dnl Debug for DV dnl -if test "${LOGNAME}" = "veillard" ; then +if test "${LOGNAME}" = "veillard" -a "`pwd`" = "/u/veillard/XSLT" ; then if test "${with_mem_debug}" = "" ; then with_mem_debug="yes" fi CFLAGS="-Wall -g -pedantic" fi + AC_ARG_WITH(mem_debug, [ --with-mem-debug Add the memory debugging module (off)]) if test "$with_mem_debug" = "yes" ; then echo Enabling memory debug support diff --git a/libxslt/transform.c b/libxslt/transform.c index 0c15d130..849795c3 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -559,7 +559,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, ctxt->insert = oldInsert; } else { #ifdef DEBUG_PROCESS - xsltGenericDebug(xsltGenericDebugContext, + xsltGenericError(xsltGenericDebugContext, "xsltApplyOneTemplate: found xslt:%s\n", cur->name); #endif TODO @@ -715,6 +715,141 @@ error: } /** + * xsltSort: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt sort node + * + * Process the xslt sort node on the source node + */ +void +xsltSort(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst) { + xmlXPathObjectPtr *results = NULL; + xmlNodeSetPtr list = NULL; + xmlXPathParserContextPtr xpathParserCtxt = NULL; + xmlChar *prop; + xmlXPathObjectPtr res, tmp; + const xmlChar *start; + int descending = 0; + int number = 0; + int len; + int i; + + if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) + return; + + list = ctxt->nodeList; + if ((list == NULL) || (list->nodeNr <= 1)) + goto error; /* nothing to do */ + + len = list->nodeNr; + + prop = xmlGetNsProp(inst, (const xmlChar *)"data-type", XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "text")) + number = 0; + else if (xmlStrEqual(prop, (const xmlChar *) "number")) + number = 1; + else { + xsltGenericError(xsltGenericErrorContext, + "xsltSort: no support for data-type = %s\n", prop); + goto error; + } + xmlFree(prop); + } + prop = xmlGetNsProp(inst, (const xmlChar *)"order", XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "ascending")) + descending = 0; + else if (xmlStrEqual(prop, (const xmlChar *) "descending")) + descending = 1; + else { + xsltGenericError(xsltGenericErrorContext, + "xsltSort: invalid value %s for order\n", prop); + goto error; + } + xmlFree(prop); + } + /* TODO: xsl:sort lang attribute */ + /* TODO: xsl:sort order attribute */ + /* TODO: xsl:sort case-order attribute */ + + prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE); + if (prop == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltSort: select is not defined\n"); + return; + } + + xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt); + if (xpathParserCtxt == NULL) + goto error; + results = xmlMalloc(len * sizeof(xmlXPathObjectPtr)); + if (results == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltSort: memory allocation failure\n"); + goto error; + } + + start = xpathParserCtxt->cur; + for (i = 0;i < len;i++) { + xpathParserCtxt->cur = start; + node = ctxt->node = list->nodeTab[i]; + ctxt->xpathCtxt->proximityPosition = i + 1; + valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node)); + xmlXPathEvalExpr(xpathParserCtxt); + xmlXPathStringFunction(xpathParserCtxt, 1); + if (number) + xmlXPathNumberFunction(xpathParserCtxt, 1); + res = valuePop(xpathParserCtxt); + do { + tmp = valuePop(xpathParserCtxt); + if (tmp != NULL) { + xmlXPathFreeObject(tmp); + } + } while (tmp != NULL); + + if (res != NULL) { + if (number) { + if (res->type == XPATH_NUMBER) { + results[i] = res; + } else { +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltSort: select didn't evaluate to a number\n"); +#endif + results[i] = NULL; + } + } else { + if (res->type == XPATH_STRING) { + results[i] = res; + } else { +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltSort: select didn't evaluate to a string\n"); +#endif + results[i] = NULL; + } + } + } + } + + xsltSortFunction(list, &results[0], descending, number); + +error: + if (xpathParserCtxt != NULL) + xmlXPathFreeParserContext(xpathParserCtxt); + if (prop != NULL) + xmlFree(prop); + if (results != NULL) { + for (i = 0;i < len;i++) + xmlXPathFreeObject(results[i]); + xmlFree(results); + } +} + +/** * xsltForEach: * @ctxt: a XSLT process context * @node: the node in the source tree. @@ -782,14 +917,22 @@ xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltGenericDebug(xsltGenericDebugContext, "xsltForEach: select evaluate to %d nodes\n", list->nodeNr); #endif - /* TODO: handle and skip the xsl:sort */ - replacement = inst->children; oldlist = ctxt->nodeList; ctxt->nodeList = list; oldContextSize = ctxt->xpathCtxt->contextSize; oldProximityPosition = ctxt->xpathCtxt->proximityPosition; ctxt->xpathCtxt->contextSize = list->nodeNr; + + /* + * handle and skip the xsl:sort + */ + replacement = inst->children; + while (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "sort"))) { + xsltSort(ctxt, node, replacement); + replacement = replacement->next; + } + for (i = 0;i < list->nodeNr;i++) { ctxt->node = list->nodeTab[i]; ctxt->xpathCtxt->proximityPosition = i + 1; diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c index ee9ae3bf..ddfddfe5 100644 --- a/libxslt/xsltutils.c +++ b/libxslt/xsltutils.c @@ -118,3 +118,59 @@ xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) { xsltGenericDebug = xsltGenericDebugDefaultFunc; } +/************************************************************************ + * * + * Sorting * + * * + ************************************************************************/ + +/** + * xsltSortFunction: + * @list: the node set + * @results: the results + * @descending: direction of order + * @number: the type of the result + * + * reorder the current node list @list accordingly to the values + * present in the array of results @results + */ +void +xsltSortFunction(xmlNodeSetPtr list, xmlXPathObjectPtr *results, + int descending, int number) { + int i, j; + int len, tst; + xmlNodePtr node; + xmlXPathObjectPtr tmp; + + if ((list == NULL) || (results == NULL)) + return; + len = list->nodeNr; + if (len <= 1) + return; + /* TODO: sort is really not optimized, does it needs to ? */ + for (i = 0;i < len -1;i++) { + for (j = i + 1; j < len; j++) { + if (results[i] == NULL) + tst = 0; + else if (results[j] == NULL) + tst = 1; + else if (number) { + tst = (results[i]->floatval > results[j]->floatval); + if (descending) + tst = !tst; + } else { + tst = xmlStrcmp(results[i]->stringval, results[j]->stringval); + if (descending) + tst = !tst; + } + if (tst) { + tmp = results[i]; + results[i] = results[j]; + results[j] = tmp; + node = list->nodeTab[i]; + list->nodeTab[i] = list->nodeTab[j]; + list->nodeTab[j] = node; + } + } + } +} diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h index 7994127e..44dbbf2d 100644 --- a/libxslt/xsltutils.h +++ b/libxslt/xsltutils.h @@ -37,7 +37,8 @@ void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs); __FILE__, __LINE__); #define IS_XSLT_ELEM(n) \ - ((n)->ns != NULL) && (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)) + (((n) != NULL) && ((n)->ns != NULL) && \ + (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE))) #define IS_XSLT_NAME(n, val) \ (xmlStrEqual((n)->name, (const xmlChar *) (val))) @@ -55,6 +56,15 @@ void xsltSetGenericErrorFunc (void *ctx, xmlGenericErrorFunc handler); void xsltSetGenericDebugFunc (void *ctx, xmlGenericErrorFunc handler); + +/* + * Sorting ... this is definitely a temporary interface ! + */ + +void xsltSortFunction (xmlNodeSetPtr list, + xmlXPathObjectPtr *results, + int descending, + int number); #ifdef __cplusplus } #endif |