source: trunk/third/libxslt/libxslt/functions.c @ 19102

Revision 19102, 24.4 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19101, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * functions.c: Implementation of the XSLT extra functions
3 *
4 * Reference:
5 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 * Bjorn Reese <breese@users.sourceforge.net> for number formatting
11 */
12
13#define IN_LIBXSLT
14#include "libxslt.h"
15
16#include <string.h>
17
18#ifdef HAVE_SYS_TYPES_H
19#include <sys/types.h>
20#endif
21#ifdef HAVE_CTYPE_H
22#include <ctype.h>
23#endif
24
25#include <libxml/xmlmemory.h>
26#include <libxml/parser.h>
27#include <libxml/tree.h>
28#include <libxml/valid.h>
29#include <libxml/hash.h>
30#include <libxml/xmlerror.h>
31#include <libxml/xpath.h>
32#include <libxml/xpathInternals.h>
33#include <libxml/parserInternals.h>
34#include <libxml/uri.h>
35#include <libxml/xpointer.h>
36#include "xslt.h"
37#include "xsltInternals.h"
38#include "xsltutils.h"
39#include "functions.h"
40#include "extensions.h"
41#include "numbersInternals.h"
42#include "keys.h"
43#include "documents.h"
44
45#ifdef WITH_XSLT_DEBUG
46#define WITH_XSLT_DEBUG_FUNCTION
47#endif
48
49/*
50 * Some versions of DocBook XSL use the vendor string to detect
51 * supporting chunking, this is a workaround to be considered
52 * in the list of decent XSLT processors <grin/>
53 */
54#define DOCBOOK_XSL_HACK
55
56/**
57 * xsltXPathFunctionLookup:
58 * @ctxt:  a void * but the XSLT transformation context actually
59 * @name:  the function name
60 * @ns_uri:  the function namespace URI
61 *
62 * This is the entry point when a function is needed by the XPath
63 * interpretor.
64 *
65 * Returns the callback function or NULL if not found
66 */
67xmlXPathFunction
68xsltXPathFunctionLookup (xmlXPathContextPtr ctxt,
69                         const xmlChar *name, const xmlChar *ns_uri) {
70    xmlXPathFunction ret;
71
72    if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL))
73        return (NULL);
74
75#ifdef WITH_XSLT_DEBUG_FUNCTION
76    xsltGenericDebug(xsltGenericDebugContext,
77            "Lookup function {%s}%s\n", ns_uri, name);
78#endif
79
80    /* give priority to context-level functions */
81    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
82
83    if (ret == NULL)
84        ret = xsltExtModuleFunctionLookup(name, ns_uri);
85
86#ifdef WITH_XSLT_DEBUG_FUNCTION
87    if (ret != NULL)
88        xsltGenericDebug(xsltGenericDebugContext,
89            "found function %s\n", name);
90#endif
91    return(ret);
92}
93
94
95/************************************************************************
96 *                                                                      *
97 *                      Module interfaces                               *
98 *                                                                      *
99 ************************************************************************/
100
101static void
102xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
103{
104    xsltTransformContextPtr tctxt;
105    xmlURIPtr uri;
106    xmlChar *fragment;
107    xsltDocumentPtr xsltdoc;
108    xmlDocPtr doc;
109    xmlXPathContextPtr xptrctxt;
110    xmlXPathObjectPtr object;
111
112    tctxt = xsltXPathGetTransformContext(ctxt);
113    if (tctxt == NULL) {
114        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
115                           "document() : internal error tctxt == NULL\n");
116        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
117        return;
118    }
119       
120    uri = xmlParseURI((const char *) URI);
121    if (uri == NULL) {
122        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
123                           "document() : failed to parse URI\n");
124        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
125        return;
126    }
127   
128    /*
129     * check for and remove fragment identifier
130     */
131    fragment = uri->fragment;
132    if (fragment != NULL) {
133        uri->fragment = NULL;
134        URI = xmlSaveUri(uri);
135        xsltdoc = xsltLoadDocument(tctxt, URI);
136        xmlFree(URI);
137    } else
138        xsltdoc = xsltLoadDocument(tctxt, URI);
139    xmlFreeURI(uri);
140   
141    if (xsltdoc == NULL) {
142        if ((URI == NULL) ||
143            (URI[0] == '#') ||
144            (xmlStrEqual(tctxt->style->doc->URL, URI))) {
145            doc = tctxt->style->doc;
146        } else {
147            valuePush(ctxt, xmlXPathNewNodeSet(NULL));
148
149            if (fragment != NULL)
150                xmlFree(fragment);
151
152            return;
153        }
154    } else
155        doc = xsltdoc->doc;
156
157    if ( fragment == NULL ) {
158        valuePush(ctxt,
159                  xmlXPathNewNodeSet((xmlNodePtr) doc));
160        return;
161    }
162       
163    /* use XPointer of HTML location for fragment ID */
164   
165    xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
166    if (xptrctxt == NULL) {
167        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
168                           "document() : internal error xptrctxt == NULL\n");
169        goto out_fragment;
170    }
171
172    object = xmlXPtrEval(fragment, xptrctxt);
173    xmlFree(fragment);
174    xmlXPathFreeContext(xptrctxt);
175
176    if (object == NULL)
177        goto out_fragment;
178       
179    switch (object->type) {
180    case XPATH_NODESET:
181        break;
182    case XPATH_UNDEFINED:
183    case XPATH_BOOLEAN:
184    case XPATH_NUMBER:
185    case XPATH_STRING:
186    case XPATH_POINT:
187    case XPATH_USERS:
188    case XPATH_XSLT_TREE:
189    case XPATH_RANGE:
190    case XPATH_LOCATIONSET:
191        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
192                           "document() : XPointer does not select a node set: #%s\n",
193                           fragment);
194        goto out_object;
195    }
196   
197    valuePush(ctxt, object);
198    return;
199
200out_object:
201    xmlXPathFreeObject(object);
202
203out_fragment:
204    valuePush(ctxt, xmlXPathNewNodeSet(NULL));
205}
206
207/**
208 * xsltDocumentFunction:
209 * @ctxt:  the XPath Parser context
210 * @nargs:  the number of arguments
211 *
212 * Implement the document() XSLT function
213 *   node-set document(object, node-set?)
214 */
215void
216xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
217{
218    xmlXPathObjectPtr obj, obj2 = NULL;
219    xmlChar *base = NULL, *URI;
220
221
222    if ((nargs < 1) || (nargs > 2)) {
223        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
224                         "document() : invalid number of args %d\n",
225                         nargs);
226        ctxt->error = XPATH_INVALID_ARITY;
227        return;
228    }
229    if (ctxt->value == NULL) {
230        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
231                         "document() : invalid arg value\n");
232        ctxt->error = XPATH_INVALID_TYPE;
233        return;
234    }
235
236    if (nargs == 2) {
237        if (ctxt->value->type != XPATH_NODESET) {
238            xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
239                             "document() : invalid arg expecting a nodeset\n");
240            ctxt->error = XPATH_INVALID_TYPE;
241            return;
242        }
243
244        obj2 = valuePop(ctxt);
245    }
246
247    if (ctxt->value->type == XPATH_NODESET) {
248        int i;
249        xmlXPathObjectPtr newobj, ret;
250
251        obj = valuePop(ctxt);
252        ret = xmlXPathNewNodeSet(NULL);
253
254        if (obj->nodesetval) {
255            for (i = 0; i < obj->nodesetval->nodeNr; i++) {
256                valuePush(ctxt,
257                          xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
258                xmlXPathStringFunction(ctxt, 1);
259                if (nargs == 2) {
260                    valuePush(ctxt, xmlXPathObjectCopy(obj2));
261                } else {
262                    valuePush(ctxt,
263                              xmlXPathNewNodeSet(obj->nodesetval->
264                                                 nodeTab[i]));
265                }
266                xsltDocumentFunction(ctxt, 2);
267                newobj = valuePop(ctxt);
268                ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
269                                                       newobj->nodesetval);
270                xmlXPathFreeObject(newobj);
271            }
272        }
273
274        xmlXPathFreeObject(obj);
275        if (obj2 != NULL)
276            xmlXPathFreeObject(obj2);
277        valuePush(ctxt, ret);
278        return;
279    }
280    /*
281     * Make sure it's converted to a string
282     */
283    xmlXPathStringFunction(ctxt, 1);
284    if (ctxt->value->type != XPATH_STRING) {
285        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
286                         "document() : invalid arg expecting a string\n");
287        ctxt->error = XPATH_INVALID_TYPE;
288        if (obj2 != NULL)
289            xmlXPathFreeObject(obj2);
290        return;
291    }
292    obj = valuePop(ctxt);
293    if (obj->stringval == NULL) {
294        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
295    } else {
296        if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
297            (obj2->nodesetval->nodeNr > 0) &&
298            IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
299            xmlNodePtr target;
300
301            target = obj2->nodesetval->nodeTab[0];
302            if (target->type == XML_ATTRIBUTE_NODE) {
303                target = ((xmlAttrPtr) target)->parent;
304            }
305            base = xmlNodeGetBase(target->doc, target);
306        } else {
307            xsltTransformContextPtr tctxt;
308
309            tctxt = xsltXPathGetTransformContext(ctxt);
310            if ((tctxt != NULL) && (tctxt->inst != NULL)) {
311                base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
312            } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
313                       (tctxt->style->doc != NULL)) {
314                base = xmlNodeGetBase(tctxt->style->doc,
315                                      (xmlNodePtr) tctxt->style->doc);
316            }
317        }
318        URI = xmlBuildURI(obj->stringval, base);
319        if (base != NULL)
320            xmlFree(base);
321        if (URI == NULL) {
322            valuePush(ctxt, xmlXPathNewNodeSet(NULL));
323        } else {
324            xsltDocumentFunctionLoadDocument( ctxt, URI );
325            xmlFree(URI);
326        }
327    }
328    xmlXPathFreeObject(obj);
329    if (obj2 != NULL)
330        xmlXPathFreeObject(obj2);
331}
332
333/**
334 * xsltKeyFunction:
335 * @ctxt:  the XPath Parser context
336 * @nargs:  the number of arguments
337 *
338 * Implement the key() XSLT function
339 *   node-set key(string, object)
340 */
341void
342xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
343    xmlNodeSetPtr nodelist;
344    xmlXPathObjectPtr obj1, obj2;
345    xmlChar *key = NULL, *value;
346    const xmlChar *keyURI;
347    xsltTransformContextPtr tctxt;
348
349    if (nargs != 2) {
350        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
351                "key() : expects two arguments\n");
352        ctxt->error = XPATH_INVALID_ARITY;
353        return;
354    }
355
356    obj2 = valuePop(ctxt);
357    xmlXPathStringFunction(ctxt, 1);
358    if ((obj2 == NULL) ||
359        (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
360        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
361            "key() : invalid arg expecting a string\n");
362        ctxt->error = XPATH_INVALID_TYPE;
363        xmlXPathFreeObject(obj2);
364
365        return;
366    }
367    obj1 = valuePop(ctxt);
368
369    if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) {
370        int i;
371        xmlXPathObjectPtr newobj, ret;
372
373        ret = xmlXPathNewNodeSet(NULL);
374
375        if (obj2->nodesetval != NULL) {
376            for (i = 0; i < obj2->nodesetval->nodeNr; i++) {
377                valuePush(ctxt, xmlXPathObjectCopy(obj1));
378                valuePush(ctxt,
379                          xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));
380                xmlXPathStringFunction(ctxt, 1);
381                xsltKeyFunction(ctxt, 2);
382                newobj = valuePop(ctxt);
383                ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
384                                                       newobj->nodesetval);
385                xmlXPathFreeObject(newobj);
386            }
387        }
388        valuePush(ctxt, ret);
389    } else {
390        xmlChar *qname, *prefix;
391
392        /*
393         * Get the associated namespace URI if qualified name
394         */
395        qname = obj1->stringval;
396        key = xmlSplitQName2(qname, &prefix);
397        if (key == NULL) {
398            key = xmlStrdup(obj1->stringval);
399            keyURI = NULL;
400            if (prefix != NULL)
401                xmlFree(prefix);
402        } else {
403            if (prefix != NULL) {
404                keyURI = xmlXPathNsLookup(ctxt->context, prefix);
405                if (keyURI == NULL) {
406                    xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
407                        "key() : prefix %s is not bound\n", prefix);
408                }
409                xmlFree(prefix);
410            } else {
411                keyURI = NULL;
412            }
413        }
414
415        /*
416         * Force conversion of first arg to string
417         */
418        valuePush(ctxt, obj2);
419        xmlXPathStringFunction(ctxt, 1);
420        if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
421            xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
422                "key() : invalid arg expecting a string\n");
423            ctxt->error = XPATH_INVALID_TYPE;
424            xmlXPathFreeObject(obj1);
425
426            return;
427        }
428        obj2 = valuePop(ctxt);
429        value = obj2->stringval;
430
431        tctxt = xsltXPathGetTransformContext(ctxt);
432
433        nodelist = xsltGetKey(tctxt, key, keyURI, value);
434        valuePush(ctxt, xmlXPathWrapNodeSet(
435                        xmlXPathNodeSetMerge(NULL, nodelist)));
436    }
437
438
439    if (obj1 != NULL)
440        xmlXPathFreeObject(obj1);
441    if (obj2 != NULL)
442        xmlXPathFreeObject(obj2);
443    if (key != NULL)
444        xmlFree(key);
445}
446
447/**
448 * xsltUnparsedEntityURIFunction:
449 * @ctxt:  the XPath Parser context
450 * @nargs:  the number of arguments
451 *
452 * Implement the unparsed-entity-uri() XSLT function
453 *   string unparsed-entity-uri(string)
454 */
455void
456xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
457    xmlXPathObjectPtr obj;
458    xmlChar *str;
459
460    if ((nargs != 1) || (ctxt->value == NULL)) {
461        xsltGenericError(xsltGenericErrorContext,
462                "unparsed-entity-uri() : expects one string arg\n");
463        ctxt->error = XPATH_INVALID_ARITY;
464        return;
465    }
466    obj = valuePop(ctxt);
467    if (obj->type != XPATH_STRING) {
468        obj = xmlXPathConvertString(obj);
469    }
470
471    str = obj->stringval;
472    if (str == NULL) {
473        valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
474    } else {
475        xmlEntityPtr entity;
476
477        entity = xmlGetDocEntity(ctxt->context->doc, str);
478        if (entity == NULL) {
479            valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
480        } else {
481            if (entity->URI != NULL)
482                valuePush(ctxt, xmlXPathNewString(entity->URI));
483            else
484                valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
485        }
486    }
487    xmlXPathFreeObject(obj);
488}
489
490/**
491 * xsltFormatNumberFunction:
492 * @ctxt:  the XPath Parser context
493 * @nargs:  the number of arguments
494 *
495 * Implement the format-number() XSLT function
496 *   string format-number(number, string, string?)
497 */
498void
499xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
500{
501    xmlXPathObjectPtr numberObj = NULL;
502    xmlXPathObjectPtr formatObj = NULL;
503    xmlXPathObjectPtr decimalObj = NULL;
504    xsltStylesheetPtr sheet;
505    xsltDecimalFormatPtr formatValues;
506    xmlChar *result;
507    xsltTransformContextPtr tctxt;
508
509    tctxt = xsltXPathGetTransformContext(ctxt);
510    if (tctxt == NULL)
511        return;
512    sheet = tctxt->style;
513    if (sheet == NULL)
514        return;
515    formatValues = sheet->decimalFormat;
516   
517    switch (nargs) {
518    case 3:
519        CAST_TO_STRING;
520        decimalObj = valuePop(ctxt);
521        formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);
522        if (formatValues == NULL) {
523            xsltTransformError(tctxt, NULL, NULL,
524                    "format-number() : undeclared decimal format '%s'\n",
525                    decimalObj->stringval);
526        }
527        /* Intentional fall-through */
528    case 2:
529        CAST_TO_STRING;
530        formatObj = valuePop(ctxt);
531        CAST_TO_NUMBER;
532        numberObj = valuePop(ctxt);
533        break;
534    default:
535        XP_ERROR(XPATH_INVALID_ARITY);
536    }
537
538    if (formatValues != NULL) {
539        if (xsltFormatNumberConversion(formatValues,
540                                       formatObj->stringval,
541                                       numberObj->floatval,
542                                       &result) == XPATH_EXPRESSION_OK) {
543            valuePush(ctxt, xmlXPathNewString(result));
544            xmlFree(result);
545        }
546    }
547
548    xmlXPathFreeObject(numberObj);
549    xmlXPathFreeObject(formatObj);
550    xmlXPathFreeObject(decimalObj);
551}
552
553/**
554 * xsltGenerateIdFunction:
555 * @ctxt:  the XPath Parser context
556 * @nargs:  the number of arguments
557 *
558 * Implement the generate-id() XSLT function
559 *   string generate-id(node-set?)
560 */
561void
562xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
563    xmlNodePtr cur = NULL;
564    unsigned long val;
565    xmlChar str[20];
566
567    if (nargs == 0) {
568        cur = ctxt->context->node;
569    } else if (nargs == 1) {
570        xmlXPathObjectPtr obj;
571        xmlNodeSetPtr nodelist;
572        int i, ret;
573
574        if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
575            ctxt->error = XPATH_INVALID_TYPE;
576            xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
577                "generate-id() : invalid arg expecting a node-set\n");
578            return;
579        }
580        obj = valuePop(ctxt);
581        nodelist = obj->nodesetval;
582        if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
583            xmlXPathFreeObject(obj);
584            valuePush(ctxt, xmlXPathNewCString(""));
585            return;
586        }
587        cur = nodelist->nodeTab[0];
588        for (i = 1;i < nodelist->nodeNr;i++) {
589            ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
590            if (ret == -1)
591                cur = nodelist->nodeTab[i];
592        }
593        xmlXPathFreeObject(obj);
594    } else {
595        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
596                "generate-id() : invalid number of args %d\n", nargs);
597        ctxt->error = XPATH_INVALID_ARITY;
598        return;
599    }
600    /*
601     * Okay this is ugly but should work, use the NodePtr address
602     * to forge the ID
603     */
604    val = (unsigned long)((char *)cur - (char *)0);
605    val /= sizeof(xmlNode);
606    sprintf((char *)str, "id%ld", val);
607    valuePush(ctxt, xmlXPathNewString(str));
608}
609
610/**
611 * xsltSystemPropertyFunction:
612 * @ctxt:  the XPath Parser context
613 * @nargs:  the number of arguments
614 *
615 * Implement the system-property() XSLT function
616 *   object system-property(string)
617 */
618void
619xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
620    xmlXPathObjectPtr obj;
621    xmlChar *prefix, *name;
622    const xmlChar *nsURI = NULL;
623
624    if (nargs != 1) {
625        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
626                "system-property() : expects one string arg\n");
627        ctxt->error = XPATH_INVALID_ARITY;
628        return;
629    }
630    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
631        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
632            "system-property() : invalid arg expecting a string\n");
633        ctxt->error = XPATH_INVALID_TYPE;
634        return;
635    }
636    obj = valuePop(ctxt);
637    if (obj->stringval == NULL) {
638        valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
639    } else {
640        name = xmlSplitQName2(obj->stringval, &prefix);
641        if (name == NULL) {
642            name = xmlStrdup(obj->stringval);
643        } else {
644            nsURI = xmlXPathNsLookup(ctxt->context, prefix);
645            if (nsURI == NULL) {
646                xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
647                    "system-property() : prefix %s is not bound\n", prefix);
648            }
649        }
650
651        if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) {
652#ifdef DOCBOOK_XSL_HACK
653            if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
654                xsltStylesheetPtr sheet;
655                xsltTransformContextPtr tctxt;
656
657                tctxt = xsltXPathGetTransformContext(ctxt);
658                if ((tctxt != NULL) && (tctxt->inst != NULL) &&
659                    (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) &&
660                    (tctxt->inst->parent != NULL) &&
661                    (xmlStrEqual(tctxt->inst->parent->name,
662                                 BAD_CAST "template")))
663                    sheet = tctxt->style;
664                else
665                    sheet = NULL;
666                if ((sheet != NULL) && (sheet->doc != NULL) &&
667                    (sheet->doc->URL != NULL) &&
668                    (xmlStrstr(sheet->doc->URL,
669                               (const xmlChar *)"chunk") != NULL)) {
670                    valuePush(ctxt, xmlXPathNewString(
671                        (const xmlChar *)"libxslt (SAXON 6.2 compatible)"));
672
673                } else {
674                    valuePush(ctxt, xmlXPathNewString(
675                        (const xmlChar *)XSLT_DEFAULT_VENDOR));
676                }
677            } else
678#else
679            if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
680                valuePush(ctxt, xmlXPathNewString(
681                          (const xmlChar *)XSLT_DEFAULT_VENDOR));
682            } else
683#endif
684            if (xmlStrEqual(name, (const xmlChar *)"version")) {
685                valuePush(ctxt, xmlXPathNewString(
686                    (const xmlChar *)XSLT_DEFAULT_VERSION));
687            } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) {
688                valuePush(ctxt, xmlXPathNewString(
689                    (const xmlChar *)XSLT_DEFAULT_URL));
690            } else {
691                valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
692            }
693        }
694        if (name != NULL)
695            xmlFree(name);
696        if (prefix != NULL)
697            xmlFree(prefix);
698    }
699    xmlXPathFreeObject(obj);
700}
701
702/**
703 * xsltElementAvailableFunction:
704 * @ctxt:  the XPath Parser context
705 * @nargs:  the number of arguments
706 *
707 * Implement the element-available() XSLT function
708 *   boolean element-available(string)
709 */
710void
711xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
712    xmlXPathObjectPtr obj;
713    xmlChar *prefix, *name;
714    const xmlChar *nsURI = NULL;
715    xsltTransformContextPtr tctxt;
716
717    if (nargs != 1) {
718        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
719                "element-available() : expects one string arg\n");
720        ctxt->error = XPATH_INVALID_ARITY;
721        return;
722    }
723    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
724        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
725            "element-available() : invalid arg expecting a string\n");
726        ctxt->error = XPATH_INVALID_TYPE;
727        return;
728    }
729    obj = valuePop(ctxt);
730    tctxt = xsltXPathGetTransformContext(ctxt);
731    if (tctxt == NULL) {
732        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
733                "element-available() : internal error tctxt == NULL\n");
734        xmlXPathFreeObject(obj);
735        valuePush(ctxt, xmlXPathNewBoolean(0));
736        return;
737    }
738
739
740    name = xmlSplitQName2(obj->stringval, &prefix);
741    if (name == NULL) {
742        xmlNsPtr ns;
743
744        name = xmlStrdup(obj->stringval);
745        ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
746        if (ns != NULL) nsURI = xmlStrdup(ns->href);
747    } else {
748        nsURI = xmlXPathNsLookup(ctxt->context, prefix);
749        if (nsURI == NULL) {
750            xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
751                "element-available() : prefix %s is not bound\n", prefix);
752        }
753    }
754
755    if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {
756        valuePush(ctxt, xmlXPathNewBoolean(1));
757    } else {
758        valuePush(ctxt, xmlXPathNewBoolean(0));
759    }
760
761    xmlXPathFreeObject(obj);
762    if (name != NULL)
763        xmlFree(name);
764    if (prefix != NULL)
765        xmlFree(prefix);
766}
767
768/**
769 * xsltFunctionAvailableFunction:
770 * @ctxt:  the XPath Parser context
771 * @nargs:  the number of arguments
772 *
773 * Implement the function-available() XSLT function
774 *   boolean function-available(string)
775 */
776void
777xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
778    xmlXPathObjectPtr obj;
779    xmlChar *prefix, *name;
780    const xmlChar *nsURI = NULL;
781
782    if (nargs != 1) {
783        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
784                "function-available() : expects one string arg\n");
785        ctxt->error = XPATH_INVALID_ARITY;
786        return;
787    }
788    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
789        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
790            "function-available() : invalid arg expecting a string\n");
791        ctxt->error = XPATH_INVALID_TYPE;
792        return;
793    }
794    obj = valuePop(ctxt);
795
796    name = xmlSplitQName2(obj->stringval, &prefix);
797    if (name == NULL) {
798        name = xmlStrdup(obj->stringval);
799    } else {
800        nsURI = xmlXPathNsLookup(ctxt->context, prefix);
801        if (nsURI == NULL) {
802            xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
803                "function-available() : prefix %s is not bound\n", prefix);
804        }
805    }
806
807    if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) {
808        valuePush(ctxt, xmlXPathNewBoolean(1));
809    } else {
810        valuePush(ctxt, xmlXPathNewBoolean(0));
811    }
812
813    xmlXPathFreeObject(obj);
814    if (name != NULL)
815        xmlFree(name);
816    if (prefix != NULL)
817        xmlFree(prefix);
818}
819
820/**
821 * xsltCurrentFunction:
822 * @ctxt:  the XPath Parser context
823 * @nargs:  the number of arguments
824 *
825 * Implement the current() XSLT function
826 *   node-set current()
827 */
828static void
829xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
830    xsltTransformContextPtr tctxt;
831
832    if (nargs != 0) {
833        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
834                "current() : function uses no argument\n");
835        ctxt->error = XPATH_INVALID_ARITY;
836        return;
837    }
838    tctxt = xsltXPathGetTransformContext(ctxt);
839    if (tctxt == NULL) {
840        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
841                "current() : internal error tctxt == NULL\n");
842        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
843    } else {
844        valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */
845    }
846}
847
848/************************************************************************
849 *                                                                      *
850 *              Registration of XSLT and libxslt functions              *
851 *                                                                      *
852 ************************************************************************/
853
854/**
855 * xsltRegisterAllFunctions:
856 * @ctxt:  the XPath context
857 *
858 * Registers all default XSLT functions in this context
859 */
860void
861xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)
862{
863    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",
864                         xsltCurrentFunction);
865    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",
866                         xsltDocumentFunction);
867    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);
868    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",
869                         xsltUnparsedEntityURIFunction);
870    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",
871                         xsltFormatNumberFunction);
872    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",
873                         xsltGenerateIdFunction);
874    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",
875                         xsltSystemPropertyFunction);
876    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",
877                         xsltElementAvailableFunction);
878    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
879                         xsltFunctionAvailableFunction);
880}
Note: See TracBrowser for help on using the repository browser.