- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / libxslt / libexslt / strings.c
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 }