Home | History | Annotate | Download | only in libexslt
      1 #define IN_LIBEXSLT
      2 #include "libexslt/libexslt.h"
      3 
      4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
      5 #include <win32config.h>
      6 #else
      7 #include "config.h"
      8 #endif
      9 
     10 #include <libxml/tree.h>
     11 #include <libxml/xpath.h>
     12 #include <libxml/xpathInternals.h>
     13 #include <libxml/parser.h>
     14 #include <libxml/encoding.h>
     15 #include <libxml/uri.h>
     16 
     17 #include <libxslt/xsltconfig.h>
     18 #include <libxslt/xsltutils.h>
     19 #include <libxslt/xsltInternals.h>
     20 #include <libxslt/extensions.h>
     21 
     22 #include "exslt.h"
     23 
     24 /**
     25  * exsltStrTokenizeFunction:
     26  * @ctxt: an XPath parser context
     27  * @nargs: the number of arguments
     28  *
     29  * Splits up a string on the characters of the delimiter string and returns a
     30  * node set of token elements, each containing one token from the string.
     31  */
     32 static void
     33 exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
     34 {
     35     xsltTransformContextPtr tctxt;
     36     xmlChar *str, *delimiters, *cur;
     37     const xmlChar *token, *delimiter;
     38     xmlNodePtr node;
     39     xmlDocPtr container;
     40     xmlXPathObjectPtr ret = NULL;
     41     int clen;
     42 
     43     if ((nargs < 1) || (nargs > 2)) {
     44         xmlXPathSetArityError(ctxt);
     45         return;
     46     }
     47 
     48     if (nargs == 2) {
     49         delimiters = xmlXPathPopString(ctxt);
     50         if (xmlXPathCheckError(ctxt))
     51             return;
     52     } else {
     53         delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");
     54     }
     55     if (delimiters == NULL)
     56         return;
     57 
     58     str = xmlXPathPopString(ctxt);
     59     if (xmlXPathCheckError(ctxt) || (str == NULL)) {
     60         xmlFree(delimiters);
     61         return;
     62     }
     63 
     64     /* Return a result tree fragment */
     65     tctxt = xsltXPathGetTransformContext(ctxt);
     66     if (tctxt == NULL) {
     67         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
     68 	      "exslt:tokenize : internal error tctxt == NULL\n");
     69 	goto fail;
     70     }
     71 
     72     container = xsltCreateRVT(tctxt);
     73     if (container != NULL) {
     74         xsltRegisterLocalRVT(tctxt, container);
     75         ret = xmlXPathNewNodeSet(NULL);
     76         if (ret != NULL) {
     77             for (cur = str, token = str; *cur != 0; cur += clen) {
     78 	        clen = xmlUTF8Size(cur);
     79 		if (*delimiters == 0) {	/* empty string case */
     80 		    xmlChar ctmp;
     81 		    ctmp = *(cur+clen);
     82 		    *(cur+clen) = 0;
     83                     node = xmlNewDocRawNode(container, NULL,
     84                                        (const xmlChar *) "token", cur);
     85 		    xmlAddChild((xmlNodePtr) container, node);
     86 		    xmlXPathNodeSetAddUnique(ret->nodesetval, node);
     87                     *(cur+clen) = ctmp; /* restore the changed byte */
     88                     token = cur + clen;
     89                 } else for (delimiter = delimiters; *delimiter != 0;
     90 				delimiter += xmlUTF8Size(delimiter)) {
     91                     if (!xmlUTF8Charcmp(cur, delimiter)) {
     92                         if (cur == token) {
     93                             /* discard empty tokens */
     94                             token = cur + clen;
     95                             break;
     96                         }
     97                         *cur = 0;	/* terminate the token */
     98                         node = xmlNewDocRawNode(container, NULL,
     99                                            (const xmlChar *) "token", token);
    100 			xmlAddChild((xmlNodePtr) container, node);
    101 			xmlXPathNodeSetAddUnique(ret->nodesetval, node);
    102                         *cur = *delimiter; /* restore the changed byte */
    103                         token = cur + clen;
    104                         break;
    105                     }
    106                 }
    107             }
    108             if (token != cur) {
    109 	    	node = xmlNewDocRawNode(container, NULL,
    110 				    (const xmlChar *) "token", token);
    111                 xmlAddChild((xmlNodePtr) container, node);
    112 	        xmlXPathNodeSetAddUnique(ret->nodesetval, node);
    113             }
    114 	    /*
    115 	     * Mark it as a function result in order to avoid garbage
    116 	     * collecting of tree fragments
    117 	     */
    118 	    xsltExtensionInstructionResultRegister(tctxt, ret);
    119         }
    120     }
    121 
    122 fail:
    123     if (str != NULL)
    124         xmlFree(str);
    125     if (delimiters != NULL)
    126         xmlFree(delimiters);
    127     if (ret != NULL)
    128         valuePush(ctxt, ret);
    129     else
    130         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
    131 }
    132 
    133 /**
    134  * exsltStrSplitFunction:
    135  * @ctxt: an XPath parser context
    136  * @nargs: the number of arguments
    137  *
    138  * Splits up a string on a delimiting string and returns a node set of token
    139  * elements, each containing one token from the string.
    140  */
    141 static void
    142 exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) {
    143     xsltTransformContextPtr tctxt;
    144     xmlChar *str, *delimiter, *cur;
    145     const xmlChar *token;
    146     xmlNodePtr node;
    147     xmlDocPtr container;
    148     xmlXPathObjectPtr ret = NULL;
    149     int delimiterLength;
    150 
    151     if ((nargs < 1) || (nargs > 2)) {
    152         xmlXPathSetArityError(ctxt);
    153         return;
    154     }
    155 
    156     if (nargs == 2) {
    157         delimiter = xmlXPathPopString(ctxt);
    158         if (xmlXPathCheckError(ctxt))
    159             return;
    160     } else {
    161         delimiter = xmlStrdup((const xmlChar *) " ");
    162     }
    163     if (delimiter == NULL)
    164         return;
    165     delimiterLength = xmlStrlen (delimiter);
    166 
    167     str = xmlXPathPopString(ctxt);
    168     if (xmlXPathCheckError(ctxt) || (str == NULL)) {
    169         xmlFree(delimiter);
    170         return;
    171     }
    172 
    173     /* Return a result tree fragment */
    174     tctxt = xsltXPathGetTransformContext(ctxt);
    175     if (tctxt == NULL) {
    176         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
    177 	      "exslt:tokenize : internal error tctxt == NULL\n");
    178 	goto fail;
    179     }
    180 
    181     /*
    182     * OPTIMIZE TODO: We are creating an xmlDoc for every split!
    183     */
    184     container = xsltCreateRVT(tctxt);
    185     if (container != NULL) {
    186         xsltRegisterLocalRVT(tctxt, container);
    187         ret = xmlXPathNewNodeSet(NULL);
    188         if (ret != NULL) {
    189             for (cur = str, token = str; *cur != 0; cur++) {
    190 		if (delimiterLength == 0) {
    191 		    if (cur != token) {
    192 			xmlChar tmp = *cur;
    193 			*cur = 0;
    194                         node = xmlNewDocRawNode(container, NULL,
    195                                            (const xmlChar *) "token", token);
    196 			xmlAddChild((xmlNodePtr) container, node);
    197 			xmlXPathNodeSetAddUnique(ret->nodesetval, node);
    198 			*cur = tmp;
    199 			token++;
    200 		    }
    201 		}
    202 		else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) {
    203 		    if (cur == token) {
    204 			/* discard empty tokens */
    205 			cur = cur + delimiterLength - 1;
    206 			token = cur + 1;
    207 			continue;
    208 		    }
    209 		    *cur = 0;
    210 		    node = xmlNewDocRawNode(container, NULL,
    211 				       (const xmlChar *) "token", token);
    212 		    xmlAddChild((xmlNodePtr) container, node);
    213 		    xmlXPathNodeSetAddUnique(ret->nodesetval, node);
    214 		    *cur = *delimiter;
    215 		    cur = cur + delimiterLength - 1;
    216 		    token = cur + 1;
    217                 }
    218             }
    219 	    if (token != cur) {
    220 		node = xmlNewDocRawNode(container, NULL,
    221 				   (const xmlChar *) "token", token);
    222 		xmlAddChild((xmlNodePtr) container, node);
    223 		xmlXPathNodeSetAddUnique(ret->nodesetval, node);
    224 	    }
    225 	    /*
    226 	     * Mark it as a function result in order to avoid garbage
    227 	     * collecting of tree fragments
    228 	     */
    229 	    xsltExtensionInstructionResultRegister(tctxt, ret);
    230         }
    231     }
    232 
    233 fail:
    234     if (str != NULL)
    235         xmlFree(str);
    236     if (delimiter != NULL)
    237         xmlFree(delimiter);
    238     if (ret != NULL)
    239         valuePush(ctxt, ret);
    240     else
    241         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
    242 }
    243 
    244 /**
    245  * exsltStrEncodeUriFunction:
    246  * @ctxt: an XPath parser context
    247  * @nargs: the number of arguments
    248  *
    249  * URI-Escapes a string
    250  */
    251 static void
    252 exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    253     int escape_all = 1, str_len = 0;
    254     xmlChar *str = NULL, *ret = NULL, *tmp;
    255 
    256     if ((nargs < 2) || (nargs > 3)) {
    257 	xmlXPathSetArityError(ctxt);
    258 	return;
    259     }
    260 
    261     if (nargs >= 3) {
    262         /* check for UTF-8 if encoding was explicitly given;
    263            we don't support anything else yet */
    264         tmp = xmlXPathPopString(ctxt);
    265         if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
    266 	    xmlXPathReturnEmptyString(ctxt);
    267 	    xmlFree(tmp);
    268 	    return;
    269 	}
    270 	xmlFree(tmp);
    271     }
    272 
    273     escape_all = xmlXPathPopBoolean(ctxt);
    274 
    275     str = xmlXPathPopString(ctxt);
    276     str_len = xmlUTF8Strlen(str);
    277 
    278     if (str_len == 0) {
    279 	xmlXPathReturnEmptyString(ctxt);
    280 	xmlFree(str);
    281 	return;
    282     }
    283 
    284     ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]"));
    285     xmlXPathReturnString(ctxt, ret);
    286 
    287     if (str != NULL)
    288 	xmlFree(str);
    289 }
    290 
    291 /**
    292  * exsltStrDecodeUriFunction:
    293  * @ctxt: an XPath parser context
    294  * @nargs: the number of arguments
    295  *
    296  * reverses URI-Escaping of a string
    297  */
    298 static void
    299 exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    300     int str_len = 0;
    301     xmlChar *str = NULL, *ret = NULL, *tmp;
    302 
    303     if ((nargs < 1) || (nargs > 2)) {
    304 	xmlXPathSetArityError(ctxt);
    305 	return;
    306     }
    307 
    308     if (nargs >= 2) {
    309         /* check for UTF-8 if encoding was explicitly given;
    310            we don't support anything else yet */
    311         tmp = xmlXPathPopString(ctxt);
    312         if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
    313 	    xmlXPathReturnEmptyString(ctxt);
    314 	    xmlFree(tmp);
    315 	    return;
    316 	}
    317 	xmlFree(tmp);
    318     }
    319 
    320     str = xmlXPathPopString(ctxt);
    321     str_len = xmlUTF8Strlen(str);
    322 
    323     if (str_len == 0) {
    324 	xmlXPathReturnEmptyString(ctxt);
    325 	xmlFree(str);
    326 	return;
    327     }
    328 
    329     ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL);
    330     if (!xmlCheckUTF8(ret)) {
    331 	/* FIXME: instead of throwing away the whole URI, we should
    332         only discard the invalid sequence(s). How to do that? */
    333 	xmlXPathReturnEmptyString(ctxt);
    334 	xmlFree(str);
    335 	xmlFree(ret);
    336 	return;
    337     }
    338 
    339     xmlXPathReturnString(ctxt, ret);
    340 
    341     if (str != NULL)
    342 	xmlFree(str);
    343 }
    344 
    345 /**
    346  * exsltStrPaddingFunction:
    347  * @ctxt: an XPath parser context
    348  * @nargs: the number of arguments
    349  *
    350  * Creates a padding string of a certain length.
    351  */
    352 static void
    353 exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    354     int number, str_len = 0;
    355     xmlChar *str = NULL, *ret = NULL, *tmp;
    356 
    357     if ((nargs < 1) || (nargs > 2)) {
    358 	xmlXPathSetArityError(ctxt);
    359 	return;
    360     }
    361 
    362     if (nargs == 2) {
    363 	str = xmlXPathPopString(ctxt);
    364 	str_len = xmlUTF8Strlen(str);
    365     }
    366     if (str_len == 0) {
    367 	if (str != NULL) xmlFree(str);
    368 	str = xmlStrdup((const xmlChar *) " ");
    369 	str_len = 1;
    370     }
    371 
    372     number = (int) xmlXPathPopNumber(ctxt);
    373 
    374     if (number <= 0) {
    375 	xmlXPathReturnEmptyString(ctxt);
    376 	xmlFree(str);
    377 	return;
    378     }
    379 
    380     while (number >= str_len) {
    381 	ret = xmlStrncat(ret, str, str_len);
    382 	number -= str_len;
    383     }
    384     tmp = xmlUTF8Strndup (str, number);
    385     ret = xmlStrcat(ret, tmp);
    386     if (tmp != NULL)
    387 	xmlFree (tmp);
    388 
    389     xmlXPathReturnString(ctxt, ret);
    390 
    391     if (str != NULL)
    392 	xmlFree(str);
    393 }
    394 
    395 /**
    396  * exsltStrAlignFunction:
    397  * @ctxt: an XPath parser context
    398  * @nargs: the number of arguments
    399  *
    400  * Aligns a string within another string.
    401  */
    402 static void
    403 exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    404     xmlChar *str, *padding, *alignment, *ret;
    405     int str_l, padding_l;
    406 
    407     if ((nargs < 2) || (nargs > 3)) {
    408 	xmlXPathSetArityError(ctxt);
    409 	return;
    410     }
    411 
    412     if (nargs == 3)
    413 	alignment = xmlXPathPopString(ctxt);
    414     else
    415 	alignment = NULL;
    416 
    417     padding = xmlXPathPopString(ctxt);
    418     str = xmlXPathPopString(ctxt);
    419 
    420     str_l = xmlUTF8Strlen (str);
    421     padding_l = xmlUTF8Strlen (padding);
    422 
    423     if (str_l == padding_l) {
    424 	xmlXPathReturnString (ctxt, str);
    425 	xmlFree(padding);
    426 	xmlFree(alignment);
    427 	return;
    428     }
    429 
    430     if (str_l > padding_l) {
    431 	ret = xmlUTF8Strndup (str, padding_l);
    432     } else {
    433 	if (xmlStrEqual(alignment, (const xmlChar *) "right")) {
    434 	    ret = xmlUTF8Strndup (padding, padding_l - str_l);
    435 	    ret = xmlStrcat (ret, str);
    436 	} else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {
    437 	    int left = (padding_l - str_l) / 2;
    438 	    int right_start;
    439 
    440 	    ret = xmlUTF8Strndup (padding, left);
    441 	    ret = xmlStrcat (ret, str);
    442 
    443 	    right_start = xmlUTF8Strsize (padding, left + str_l);
    444 	    ret = xmlStrcat (ret, padding + right_start);
    445 	} else {
    446 	    int str_s;
    447 
    448 	    str_s = xmlStrlen (str);
    449 	    ret = xmlStrdup (str);
    450 	    ret = xmlStrcat (ret, padding + str_s);
    451 	}
    452     }
    453 
    454     xmlXPathReturnString (ctxt, ret);
    455 
    456     xmlFree(str);
    457     xmlFree(padding);
    458     xmlFree(alignment);
    459 }
    460 
    461 /**
    462  * exsltStrConcatFunction:
    463  * @ctxt: an XPath parser context
    464  * @nargs: the number of arguments
    465  *
    466  * Takes a node set and returns the concatenation of the string values
    467  * of the nodes in that node set.  If the node set is empty, it
    468  * returns an empty string.
    469  */
    470 static void
    471 exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    472     xmlXPathObjectPtr obj;
    473     xmlChar *ret = NULL;
    474     int i;
    475 
    476     if (nargs  != 1) {
    477 	xmlXPathSetArityError(ctxt);
    478 	return;
    479     }
    480 
    481     if (!xmlXPathStackIsNodeSet(ctxt)) {
    482 	xmlXPathSetTypeError(ctxt);
    483 	return;
    484     }
    485 
    486     obj = valuePop (ctxt);
    487 
    488     if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
    489 	xmlXPathReturnEmptyString(ctxt);
    490 	return;
    491     }
    492 
    493     for (i = 0; i < obj->nodesetval->nodeNr; i++) {
    494 	xmlChar *tmp;
    495 	tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
    496 
    497 	ret = xmlStrcat (ret, tmp);
    498 
    499 	xmlFree(tmp);
    500     }
    501 
    502     xmlXPathFreeObject (obj);
    503 
    504     xmlXPathReturnString(ctxt, ret);
    505 }
    506 
    507 /**
    508  * exsltStrReplaceInternal:
    509  * @str: string to modify
    510  * @searchStr: string to find
    511  * @replaceStr: string to replace occurrences of searchStr
    512  *
    513  * Search and replace string function used by exsltStrReplaceFunction
    514  */
    515 static xmlChar*
    516 exsltStrReplaceInternal(const xmlChar* str, const xmlChar* searchStr,
    517                         const xmlChar* replaceStr)
    518 {
    519     const xmlChar *curr, *next;
    520     xmlChar *ret = NULL;
    521     int searchStrSize;
    522 
    523     curr = str;
    524     searchStrSize = xmlStrlen(searchStr);
    525 
    526     do {
    527       next = xmlStrstr(curr, searchStr);
    528       if (next == NULL) {
    529         ret = xmlStrcat (ret, curr);
    530         break;
    531       }
    532 
    533       ret = xmlStrncat (ret, curr, next - curr);
    534       ret = xmlStrcat (ret, replaceStr);
    535       curr = next + searchStrSize;
    536     } while (*curr != 0);
    537 
    538     return ret;
    539 }
    540 /**
    541  * exsltStrReplaceFunction:
    542  * @ctxt: an XPath parser context
    543  * @nargs: the number of arguments
    544  *
    545  * Takes a string, and two node sets and returns the string with all strings in
    546  * the first node set replaced by all strings in the second node set.
    547  */
    548 static void
    549 exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    550     xmlChar *str = NULL, *searchStr = NULL, *replaceStr = NULL;
    551     xmlNodeSetPtr replaceSet = NULL, searchSet = NULL;
    552     xmlChar *ret = NULL, *retSwap = NULL;
    553     int i;
    554 
    555     if (nargs  != 3) {
    556       xmlXPathSetArityError(ctxt);
    557       return;
    558     }
    559 
    560     /* pull out replace argument */
    561     if (!xmlXPathStackIsNodeSet(ctxt)) {
    562       replaceStr = xmlXPathPopString(ctxt);
    563     }
    564 		else {
    565       replaceSet = xmlXPathPopNodeSet(ctxt);
    566       if (xmlXPathCheckError(ctxt)) {
    567         xmlXPathSetTypeError(ctxt);
    568         goto fail;
    569       }
    570     }
    571 
    572     /* behavior driven by search argument from here on */
    573     if (!xmlXPathStackIsNodeSet(ctxt)) {
    574       searchStr = xmlXPathPopString(ctxt);
    575       str = xmlXPathPopString(ctxt);
    576 
    577       if (replaceStr == NULL) {
    578         xmlXPathSetTypeError(ctxt);
    579         goto fail;
    580       }
    581 
    582       ret = exsltStrReplaceInternal(str, searchStr, replaceStr);
    583     }
    584 		else {
    585       searchSet = xmlXPathPopNodeSet(ctxt);
    586       if (searchSet == NULL || xmlXPathCheckError(ctxt)) {
    587         xmlXPathSetTypeError(ctxt);
    588         goto fail;
    589       }
    590 
    591       str = xmlXPathPopString(ctxt);
    592       ret = xmlStrdup(str);
    593 
    594       for (i = 0; i < searchSet->nodeNr; i++) {
    595 	searchStr = xmlXPathCastNodeToString(searchSet->nodeTab[i]);
    596 
    597         if (replaceSet != NULL) {
    598           replaceStr = NULL;
    599           if (i < replaceSet->nodeNr) {
    600             replaceStr = xmlXPathCastNodeToString(replaceSet->nodeTab[i]);
    601           }
    602 
    603           retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr);
    604 
    605           if (replaceStr != NULL) {
    606             xmlFree(replaceStr);
    607             replaceStr = NULL;
    608           }
    609         }
    610         else {
    611           retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr);
    612         }
    613 
    614 				xmlFree(ret);
    615         if (searchStr != NULL) {
    616           xmlFree(searchStr);
    617           searchStr = NULL;
    618         }
    619 
    620 				ret = retSwap;
    621 			}
    622 
    623       if (replaceSet != NULL)
    624         xmlXPathFreeNodeSet(replaceSet);
    625 
    626       if (searchSet != NULL)
    627         xmlXPathFreeNodeSet(searchSet);
    628 		}
    629 
    630     xmlXPathReturnString(ctxt, ret);
    631 
    632  fail:
    633     if (replaceStr != NULL)
    634       xmlFree(replaceStr);
    635 
    636     if (searchStr != NULL)
    637       xmlFree(searchStr);
    638 
    639     if (str != NULL)
    640       xmlFree(str);
    641 }
    642 
    643 /**
    644  * exsltStrRegister:
    645  *
    646  * Registers the EXSLT - Strings module
    647  */
    648 
    649 void
    650 exsltStrRegister (void) {
    651     xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
    652 				   EXSLT_STRINGS_NAMESPACE,
    653 				   exsltStrTokenizeFunction);
    654     xsltRegisterExtModuleFunction ((const xmlChar *) "split",
    655 				   EXSLT_STRINGS_NAMESPACE,
    656 				   exsltStrSplitFunction);
    657     xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri",
    658 				   EXSLT_STRINGS_NAMESPACE,
    659 				   exsltStrEncodeUriFunction);
    660     xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri",
    661 				   EXSLT_STRINGS_NAMESPACE,
    662 				   exsltStrDecodeUriFunction);
    663     xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
    664 				   EXSLT_STRINGS_NAMESPACE,
    665 				   exsltStrPaddingFunction);
    666     xsltRegisterExtModuleFunction ((const xmlChar *) "align",
    667 				   EXSLT_STRINGS_NAMESPACE,
    668 				   exsltStrAlignFunction);
    669     xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
    670 				   EXSLT_STRINGS_NAMESPACE,
    671 				   exsltStrConcatFunction);
    672     xsltRegisterExtModuleFunction ((const xmlChar *) "replace",
    673 				   EXSLT_STRINGS_NAMESPACE,
    674 				   exsltStrReplaceFunction);
    675 }
    676 
    677 /**
    678  * exsltStrXpathCtxtRegister:
    679  *
    680  * Registers the EXSLT - Strings module for use outside XSLT
    681  */
    682 int
    683 exsltStrXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix)
    684 {
    685     if (ctxt
    686         && prefix
    687         && !xmlXPathRegisterNs(ctxt,
    688                                prefix,
    689                                (const xmlChar *) EXSLT_STRINGS_NAMESPACE)
    690         && !xmlXPathRegisterFuncNS(ctxt,
    691                                    (const xmlChar *) "encode-uri",
    692                                    (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
    693                                    exsltStrEncodeUriFunction)
    694         && !xmlXPathRegisterFuncNS(ctxt,
    695                                    (const xmlChar *) "decode-uri",
    696                                    (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
    697                                    exsltStrDecodeUriFunction)
    698         && !xmlXPathRegisterFuncNS(ctxt,
    699                                    (const xmlChar *) "padding",
    700                                    (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
    701                                    exsltStrPaddingFunction)
    702         && !xmlXPathRegisterFuncNS(ctxt,
    703                                    (const xmlChar *) "align",
    704                                    (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
    705                                    exsltStrAlignFunction)
    706         && !xmlXPathRegisterFuncNS(ctxt,
    707                                    (const xmlChar *) "concat",
    708                                    (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
    709                                    exsltStrConcatFunction)
    710         && !xmlXPathRegisterFuncNS(ctxt,
    711                                    (const xmlChar *) "replace",
    712                                    (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
    713                                    exsltStrReplaceFunction)) {
    714         return 0;
    715     }
    716     return -1;
    717 }
    718