| Index: third_party/libxslt/examples/xsltICUSort.c
|
| diff --git a/third_party/libxslt/examples/xsltICUSort.c b/third_party/libxslt/examples/xsltICUSort.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6f7612149302e9ca54cd1b6757a5f94e6e4f9af7
|
| --- /dev/null
|
| +++ b/third_party/libxslt/examples/xsltICUSort.c
|
| @@ -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]);
|
| + }
|
| + }
|
| +}
|
| +
|
|
|