seems I never commited to CVS the example from Richard Jinks Daniel
authorDaniel Veillard <veillard@src.gnome.org>
Tue, 29 Jun 2004 07:26:34 +0000 (07:26 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Tue, 29 Jun 2004 07:26:34 +0000 (07:26 +0000)
* Makefile.am examples/xsltICUSort.c: seems I never commited to CVS
  the example from Richard Jinks
Daniel

ChangeLog
Makefile.am
examples/xsltICUSort.c [new file with mode: 0644]

index f1498f5..32532b6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Tue Jun 29 09:23:03 CEST 2004 Daniel Veillard <daniel@veillard.com>
+
+       * Makefile.am examples/xsltICUSort.c: seems I never commited to CVS
+         the example from Richard Jinks
+
 Wed Jun  9 16:33:56 CEST 2004 Igor Zlatkovic <igor@zlatkovic.com>
 
        * win32/configure.js win32/Makefile.* minor changes for the new
index 31fff1c..5b0dddd 100644 (file)
@@ -14,7 +14,7 @@ confexec_DATA = xsltConf.sh
 bin_SCRIPTS = xslt-config
 
 dist-hook: cleanup libxslt.spec
-       (cd $(srcdir) ; tar -cf - --exclude CVS win32 vms) | (cd $(distdir); tar xf -)
+       (cd $(srcdir) ; tar -cf - --exclude CVS win32 vms examples) | (cd $(distdir); tar xf -)
 
 EXTRA_DIST = xsltConf.sh.in xslt-config.in libxslt.spec libxslt.spec.in \
              FEATURES TODO Copyright libxslt.m4 \
diff --git a/examples/xsltICUSort.c b/examples/xsltICUSort.c
new file mode 100644 (file)
index 0000000..ba6ec4e
--- /dev/null
@@ -0,0 +1,304 @@
+/**
+ * xsltICUSort.c: module provided by Richard Jinks to provide a 
+ *                sort function replacement using ICU, it is not
+ *                included in standard due to the size of the ICU
+ *                library
+ *
+ * See http://mail.gnome.org/archives/xslt/2002-November/msg00093.html
+ *     http://oss.software.ibm.com/icu/index.html
+ *
+ * Copyright Richard Jinks
+ */
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <libxml/parserInternals.h>
+
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "transform.h"
+#include "templates.h"
+
+#include <unicode/ucnv.h>
+#include <unicode/ustring.h>
+#include <unicode/utypes.h>
+#include <unicode/uloc.h>
+#include <unicode/ucol.h>
+
+/**
+ * xsltICUSortFunction:
+ * @ctxt:  a XSLT process context
+ * @sorts:  array of sort nodes
+ * @nbsorts:  the number of sorts in the array
+ *
+ * reorder the current node list accordingly to the set of sorting
+ * requirement provided by the arry of nodes.
+ * uses the ICU library
+ */
+void
+xsltICUSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
+                  int nbsorts) {
+    xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
+    xmlXPathObjectPtr *results = NULL, *res;
+    xmlNodeSetPtr list = NULL;
+    int descending, number, desc, numb;
+    int len = 0;
+    int i, j, incr;
+    int tst;
+    int depth;
+    xmlNodePtr node;
+    xmlXPathObjectPtr tmp;
+    xsltStylePreCompPtr comp;
+    int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
+
+    /* Start ICU change */
+    UCollator *coll = 0;
+    UConverter *conv;
+    UErrorCode status;
+    UChar *target,*target2;
+    int targetlen, target2len;
+    /* End ICU change */
+
+    if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
+       (nbsorts >= XSLT_MAX_SORT))
+       return;
+    if (sorts[0] == NULL)
+       return;
+    comp = sorts[0]->_private;
+    if (comp == NULL)
+       return;
+
+    list = ctxt->nodeList;
+    if ((list == NULL) || (list->nodeNr <= 1))
+       return; /* nothing to do */
+
+    for (j = 0; j < nbsorts; j++) {
+       comp = sorts[j]->_private;
+       tempstype[j] = 0;
+       if ((comp->stype == NULL) && (comp->has_stype != 0)) {
+           comp->stype =
+               xsltEvalAttrValueTemplate(ctxt, sorts[j],
+                                         (const xmlChar *) "data-type",
+                                         XSLT_NAMESPACE);
+           if (comp->stype != NULL) {
+               tempstype[j] = 1;
+               if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
+                   comp->number = 0;
+               else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
+                   comp->number = 1;
+               else {
+                   xsltTransformError(ctxt, NULL, sorts[j],
+                         "xsltDoSortFunction: no support for data-type = %s\n",
+                                    comp->stype);
+                   comp->number = 0; /* use default */
+               }
+           }
+       }
+       temporder[j] = 0;
+       if ((comp->order == NULL) && (comp->has_order != 0)) {
+           comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
+                                                   (const xmlChar *) "order",
+                                                   XSLT_NAMESPACE);
+           if (comp->order != NULL) {
+               temporder[j] = 1;
+               if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
+                   comp->descending = 0;
+               else if (xmlStrEqual(comp->order,
+                                    (const xmlChar *) "descending"))
+                   comp->descending = 1;
+               else {
+                   xsltTransformError(ctxt, NULL, sorts[j],
+                            "xsltDoSortFunction: invalid value %s for order\n",
+                                    comp->order);
+                   comp->descending = 0; /* use default */
+               }
+           }
+       }
+    }
+
+    len = list->nodeNr;
+
+    resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
+    for (i = 1;i < XSLT_MAX_SORT;i++)
+       resultsTab[i] = NULL;
+
+    results = resultsTab[0];
+
+    comp = sorts[0]->_private;
+    descending = comp->descending;
+    number = comp->number;
+    if (results == NULL)
+       return;
+
+    /* Start ICU change */
+    status = U_ZERO_ERROR;
+    conv = ucnv_open("UTF8", &status);
+    if(U_FAILURE(status)) {
+       xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening converter\n");
+    }  
+    if(comp->has_lang) 
+       coll = ucol_open(comp->lang, &status);
+    if(U_FAILURE(status) || !comp->has_lang) {
+       status = U_ZERO_ERROR;
+       coll = ucol_open("en", &status);
+    }
+    if(U_FAILURE(status)) {
+       xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening collator\n");
+    }
+    if(comp->lower_first) 
+       ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_LOWER_FIRST,&status);
+    else 
+       ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_UPPER_FIRST,&status);
+    if(U_FAILURE(status)) {
+       xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error setting collator attribute\n");
+    }
+    /* End ICU change */
+
+    /* Shell's sort of node-set */
+    for (incr = len / 2; incr > 0; incr /= 2) {
+       for (i = incr; i < len; i++) {
+           j = i - incr;
+           if (results[i] == NULL)
+               continue;
+           
+           while (j >= 0) {
+               if (results[j] == NULL)
+                   tst = 1;
+               else {
+                   if (number) {
+                       if (results[j]->floatval == results[j + incr]->floatval)
+                           tst = 0;
+                       else if (results[j]->floatval > 
+                               results[j + incr]->floatval)
+                           tst = 1;
+                       else tst = -1;
+                   } else {
+/*                     tst = xmlStrcmp(results[j]->stringval,
+                                    results[j + incr]->stringval); */
+                       /* Start ICU change */
+                       targetlen = xmlStrlen(results[j]->stringval) * 2;
+                       target2len = xmlStrlen(results[j + incr]->stringval) * 2;
+                       target = xmlMalloc(targetlen * sizeof(UChar));
+                       target2 = xmlMalloc(target2len * sizeof(UChar));
+                       targetlen = ucnv_toUChars(conv, target, targetlen, results[j]->stringval, -1, &status);
+                       target2len = ucnv_toUChars(conv, target2, target2len, results[j+incr]->stringval, -1, &status);
+                       tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2));
+                       /* End ICU change */
+                   }
+                   if (descending)
+                       tst = -tst;
+               }
+               if (tst == 0) {
+                   /*
+                    * Okay we need to use multi level sorts
+                    */
+                   depth = 1;
+                   while (depth < nbsorts) {
+                       if (sorts[depth] == NULL)
+                           break;
+                       comp = sorts[depth]->_private;
+                       if (comp == NULL)
+                           break;
+                       desc = comp->descending;
+                       numb = comp->number;
+
+                       /*
+                        * Compute the result of the next level for the
+                        * full set, this might be optimized ... or not
+                        */
+                       if (resultsTab[depth] == NULL) 
+                           resultsTab[depth] = xsltComputeSortResult(ctxt,
+                                                       sorts[depth]);
+                       res = resultsTab[depth];
+                       if (res == NULL) 
+                           break;
+                       if (res[j] == NULL)
+                           tst = 1;
+                       else {
+                           if (numb) {
+                               if (res[j]->floatval == res[j + incr]->floatval)
+                                   tst = 0;
+                               else if (res[j]->floatval > 
+                                       res[j + incr]->floatval)
+                                   tst = 1;
+                               else tst = -1;
+                           } else {
+/*                             tst = xmlStrcmp(res[j]->stringval,
+                                            res[j + incr]->stringval); */
+                               /* Start ICU change */
+                               targetlen = xmlStrlen(res[j]->stringval) * 2;
+                               target2len = xmlStrlen(res[j + incr]->stringval) * 2;
+                               target = xmlMalloc(targetlen * sizeof(UChar));
+                               target2 = xmlMalloc(target2len * sizeof(UChar));
+                               targetlen = ucnv_toUChars(conv, target, targetlen, res[j]->stringval, -1, &status);
+                               target2len = ucnv_toUChars(conv, target2, target2len, res[j+incr]->stringval, -1, &status);
+                               tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2));
+                               /* End ICU change */
+                           }
+                           if (desc)
+                             tst = -tst;
+                       }
+                       /*
+                        * if we still can't differenciate at this level
+                        * try one level deeper.
+                        */
+                       if (tst != 0)
+                           break;
+                       depth++;
+                   }
+               }
+               if (tst == 0) {
+                   tst = results[j]->index > results[j + incr]->index;
+               }
+               if (tst > 0) {
+                   tmp = results[j];
+                   results[j] = results[j + incr];
+                   results[j + incr] = tmp;
+                   node = list->nodeTab[j];
+                   list->nodeTab[j] = list->nodeTab[j + incr];
+                   list->nodeTab[j + incr] = node;
+                   depth = 1;
+                   while (depth < nbsorts) {
+                       if (sorts[depth] == NULL)
+                           break;
+                       if (resultsTab[depth] == NULL)
+                           break;
+                       res = resultsTab[depth];
+                       tmp = res[j];
+                       res[j] = res[j + incr];
+                       res[j + incr] = tmp;
+                       depth++;
+                   }
+                   j -= incr;
+               } else
+                   break;
+           }
+       }
+    }
+
+    /* Start ICU change */
+    ucol_close(coll);
+    ucnv_close(conv);
+    /* End ICU change */
+
+    for (j = 0; j < nbsorts; j++) {
+       comp = sorts[j]->_private;
+       if (tempstype[j] == 1) {
+           /* The data-type needs to be recomputed each time */
+           xmlFree(comp->stype);
+           comp->stype = NULL;
+       }
+       if (temporder[j] == 1) {
+           /* The order needs to be recomputed each time */
+           xmlFree(comp->order);
+           comp->order = NULL;
+       }
+       if (resultsTab[j] != NULL) {
+           for (i = 0;i < len;i++)
+               xmlXPathFreeObject(resultsTab[j][i]);
+           xmlFree(resultsTab[j]);
+       }
+    }
+}
+