2 * functions.c: Implementation of the XSLT extra functions
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
10 * Bjorn Reese <breese@users.sourceforge.net> for number formatting
17 #ifdef HAVE_SYS_TYPES_H
18 #include <sys/types.h>
24 #include <libxml/xmlmemory.h>
25 #include <libxml/parser.h>
26 #include <libxml/tree.h>
27 #include <libxml/valid.h>
28 #include <libxml/hash.h>
29 #include <libxml/xmlerror.h>
30 #include <libxml/xpath.h>
31 #include <libxml/xpathInternals.h>
32 #include <libxml/parserInternals.h>
33 #include <libxml/uri.h>
35 #include "xsltInternals.h"
36 #include "xsltutils.h"
37 #include "functions.h"
38 #include "extensions.h"
39 #include "numbersInternals.h"
41 #include "documents.h"
43 #ifdef WITH_XSLT_DEBUG
44 #define WITH_XSLT_DEBUG_FUNCTION
48 * Some versions of DocBook XSL use the vendor string to detect
49 * supporting chunking, this is a workaround to be considered
50 * in the list of decent XSLT processors <grin/>
52 #define DOCBOOK_XSL_HACK
55 * xsltXPathFunctionLookup:
56 * @ctxt: a void * but the XSLT transformation context actually
57 * @name: the function name
58 * @ns_uri: the function namespace URI
60 * This is the entry point when a function is needed by the XPath
63 * Returns the callback function or NULL if not found
66 xsltXPathFunctionLookup (xmlXPathContextPtr ctxt,
67 const xmlChar *name, const xmlChar *ns_uri) {
70 if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL))
73 #ifdef WITH_XSLT_DEBUG_FUNCTION
74 xsltGenericDebug(xsltGenericDebugContext,
75 "Lookup function {%s}%s\n", ns_uri, name);
78 /* give priority to context-level functions */
79 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
82 ret = xsltExtModuleFunctionLookup(name, ns_uri);
84 #ifdef WITH_XSLT_DEBUG_FUNCTION
86 xsltGenericDebug(xsltGenericDebugContext,
87 "found function %s\n", name);
93 /************************************************************************
97 ************************************************************************/
100 * xsltDocumentFunction:
101 * @ctxt: the XPath Parser context
102 * @nargs: the number of arguments
104 * Implement the document() XSLT function
105 * node-set document(object, node-set?)
108 xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){
110 xmlXPathObjectPtr obj, obj2 = NULL;
111 xmlChar *base = NULL, *URI;
114 if ((nargs < 1) || (nargs > 2)) {
115 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
116 xsltGenericError(xsltGenericErrorContext,
117 "document() : invalid number of args %d\n", nargs);
118 ctxt->error = XPATH_INVALID_ARITY;
121 if (ctxt->value == NULL) {
122 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
123 xsltGenericError(xsltGenericErrorContext,
124 "document() : invalid arg value\n");
125 ctxt->error = XPATH_INVALID_TYPE;
130 if (ctxt->value->type != XPATH_NODESET) {
131 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
133 xsltGenericError(xsltGenericErrorContext,
134 "document() : invalid arg expecting a nodeset\n");
135 ctxt->error = XPATH_INVALID_TYPE;
139 obj2 = valuePop(ctxt);
142 if (ctxt->value->type == XPATH_NODESET) {
144 xmlXPathObjectPtr newobj, ret;
146 obj = valuePop(ctxt);
147 ret = xmlXPathNewNodeSet(NULL);
149 if (obj->nodesetval) {
150 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
152 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
153 xmlXPathStringFunction(ctxt, 1);
155 valuePush(ctxt, xmlXPathObjectCopy(obj2));
158 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
160 xsltDocumentFunction(ctxt, 2);
161 newobj = valuePop(ctxt);
162 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
164 xmlXPathFreeObject(newobj);
168 xmlXPathFreeObject(obj);
170 xmlXPathFreeObject(obj2);
171 valuePush(ctxt, ret);
175 * Make sure it's converted to a string
177 xmlXPathStringFunction(ctxt, 1);
178 if (ctxt->value->type != XPATH_STRING) {
179 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
180 xsltGenericError(xsltGenericErrorContext,
181 "document() : invalid arg expecting a string\n");
182 ctxt->error = XPATH_INVALID_TYPE;
184 xmlXPathFreeObject(obj2);
187 obj = valuePop(ctxt);
188 if (obj->stringval == NULL) {
189 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
191 if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
192 (obj2->nodesetval->nodeNr > 0) &&
193 IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
196 target = obj2->nodesetval->nodeTab[0];
197 if (target->type == XML_ATTRIBUTE_NODE) {
198 target = ((xmlAttrPtr) target)->parent;
200 base = xmlNodeGetBase(target->doc, target);
202 xsltTransformContextPtr tctxt;
204 tctxt = xsltXPathGetTransformContext(ctxt);
205 if ((tctxt != NULL) && (tctxt->inst != NULL)) {
206 base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
207 } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
208 (tctxt->style->doc != NULL)) {
209 base = xmlNodeGetBase(tctxt->style->doc,
210 (xmlNodePtr) tctxt->style->doc);
213 URI = xmlBuildURI(obj->stringval, base);
217 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
219 xsltTransformContextPtr tctxt;
221 tctxt = xsltXPathGetTransformContext(ctxt);
223 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
225 xsltGenericError(xsltGenericErrorContext,
226 "document() : internal error tctxt == NULL\n");
227 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
229 if (xmlStrEqual(tctxt->style->doc->URL, URI)) {
230 valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr)tctxt->style->doc));
233 doc = xsltLoadDocument(tctxt, URI);
235 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
237 /* TODO: use XPointer of HTML location for fragment ID */
238 /* pbm #xxx can lead to location sets, not nodesets :-) */
239 valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc->doc));
246 xmlXPathFreeObject(obj);
248 xmlXPathFreeObject(obj2);
253 * @ctxt: the XPath Parser context
254 * @nargs: the number of arguments
256 * Implement the key() XSLT function
257 * node-set key(string, object)
260 xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
261 xmlNodeSetPtr nodelist;
262 xmlXPathObjectPtr obj1, obj2;
263 xmlChar *key = NULL, *value;
264 const xmlChar *keyURI;
265 xsltTransformContextPtr tctxt;
268 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
269 xsltGenericError(xsltGenericErrorContext,
270 "key() : expects two arguments\n");
271 ctxt->error = XPATH_INVALID_ARITY;
275 obj2 = valuePop(ctxt);
276 if ((obj2 == NULL) ||
277 (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
278 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
279 xsltGenericError(xsltGenericErrorContext,
280 "key() : invalid arg expecting a string\n");
281 ctxt->error = XPATH_INVALID_TYPE;
282 xmlXPathFreeObject(obj2);
286 obj1 = valuePop(ctxt);
288 if (obj2->type == XPATH_NODESET) {
290 xmlXPathObjectPtr newobj, ret;
292 ret = xmlXPathNewNodeSet(NULL);
294 if (obj2->nodesetval != NULL) {
295 for (i = 0; i < obj2->nodesetval->nodeNr; i++) {
296 valuePush(ctxt, xmlXPathObjectCopy(obj1));
298 xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));
299 xmlXPathStringFunction(ctxt, 1);
300 xsltKeyFunction(ctxt, 2);
301 newobj = valuePop(ctxt);
302 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
304 xmlXPathFreeObject(newobj);
307 valuePush(ctxt, ret);
309 xmlChar *qname, *prefix;
312 * Get the associated namespace URI if qualified name
314 qname = obj1->stringval;
315 key = xmlSplitQName2(qname, &prefix);
317 key = xmlStrdup(obj1->stringval);
322 if (prefix != NULL) {
323 keyURI = xmlXPathNsLookup(ctxt->context, prefix);
324 if (keyURI == NULL) {
325 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
327 xsltGenericError(xsltGenericErrorContext,
328 "key() : prefix %s is not bound\n", prefix);
337 * Force conversion of first arg to string
339 valuePush(ctxt, obj2);
340 xmlXPathStringFunction(ctxt, 1);
341 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
342 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
344 xsltGenericError(xsltGenericErrorContext,
345 "key() : invalid arg expecting a string\n");
346 ctxt->error = XPATH_INVALID_TYPE;
347 xmlXPathFreeObject(obj1);
351 obj2 = valuePop(ctxt);
352 value = obj2->stringval;
354 tctxt = xsltXPathGetTransformContext(ctxt);
356 nodelist = xsltGetKey(tctxt, key, keyURI, value);
357 valuePush(ctxt, xmlXPathWrapNodeSet(
358 xmlXPathNodeSetMerge(NULL, nodelist)));
363 xmlXPathFreeObject(obj1);
365 xmlXPathFreeObject(obj2);
371 * xsltUnparsedEntityURIFunction:
372 * @ctxt: the XPath Parser context
373 * @nargs: the number of arguments
375 * Implement the unparsed-entity-uri() XSLT function
376 * string unparsed-entity-uri(string)
379 xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
380 xmlXPathObjectPtr obj;
383 if ((nargs != 1) || (ctxt->value == NULL)) {
384 xsltGenericError(xsltGenericErrorContext,
385 "unparsed-entity-uri() : expects one string arg\n");
386 ctxt->error = XPATH_INVALID_ARITY;
389 obj = valuePop(ctxt);
390 if (obj->type != XPATH_STRING) {
391 obj = xmlXPathConvertString(obj);
394 str = obj->stringval;
396 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
400 entity = xmlGetDocEntity(ctxt->context->doc, str);
401 if (entity == NULL) {
402 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
404 if (entity->URI != NULL)
405 valuePush(ctxt, xmlXPathNewString(entity->URI));
407 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
410 xmlXPathFreeObject(obj);
414 * xsltFormatNumberFunction:
415 * @ctxt: the XPath Parser context
416 * @nargs: the number of arguments
418 * Implement the format-number() XSLT function
419 * string format-number(number, string, string?)
422 xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
424 xmlXPathObjectPtr numberObj = NULL;
425 xmlXPathObjectPtr formatObj = NULL;
426 xmlXPathObjectPtr decimalObj = NULL;
427 xsltStylesheetPtr sheet;
428 xsltDecimalFormatPtr formatValues;
430 xsltTransformContextPtr tctxt;
432 tctxt = xsltXPathGetTransformContext(ctxt);
435 sheet = tctxt->style;
438 formatValues = sheet->decimalFormat;
443 decimalObj = valuePop(ctxt);
444 formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);
445 /* Intentional fall-through */
448 formatObj = valuePop(ctxt);
450 numberObj = valuePop(ctxt);
453 XP_ERROR(XPATH_INVALID_ARITY);
456 if (xsltFormatNumberConversion(formatValues,
457 formatObj->stringval,
459 &result) == XPATH_EXPRESSION_OK) {
460 valuePush(ctxt, xmlXPathNewString(result));
464 xmlXPathFreeObject(numberObj);
465 xmlXPathFreeObject(formatObj);
466 xmlXPathFreeObject(decimalObj);
470 * xsltGenerateIdFunction:
471 * @ctxt: the XPath Parser context
472 * @nargs: the number of arguments
474 * Implement the generate-id() XSLT function
475 * string generate-id(node-set?)
478 xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
479 xmlNodePtr cur = NULL;
484 cur = ctxt->context->node;
485 } else if (nargs == 1) {
486 xmlXPathObjectPtr obj;
487 xmlNodeSetPtr nodelist;
490 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
491 ctxt->error = XPATH_INVALID_TYPE;
492 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
494 xsltGenericError(xsltGenericErrorContext,
495 "generate-id() : invalid arg expecting a node-set\n");
498 obj = valuePop(ctxt);
499 nodelist = obj->nodesetval;
500 if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
501 xmlXPathFreeObject(obj);
502 valuePush(ctxt, xmlXPathNewCString(""));
505 cur = nodelist->nodeTab[0];
506 for (i = 1;i < nodelist->nodeNr;i++) {
507 ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
509 cur = nodelist->nodeTab[i];
511 xmlXPathFreeObject(obj);
513 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
514 xsltGenericError(xsltGenericErrorContext,
515 "generate-id() : invalid number of args %d\n", nargs);
516 ctxt->error = XPATH_INVALID_ARITY;
520 * Okay this is ugly but should work, use the NodePtr address
523 val = (unsigned long)((char *)cur - (char *)0);
524 val /= sizeof(xmlNode);
525 sprintf((char *)str, "id%ld", val);
526 valuePush(ctxt, xmlXPathNewString(str));
530 * xsltSystemPropertyFunction:
531 * @ctxt: the XPath Parser context
532 * @nargs: the number of arguments
534 * Implement the system-property() XSLT function
535 * object system-property(string)
538 xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
539 xmlXPathObjectPtr obj;
540 xmlChar *prefix, *name;
541 const xmlChar *nsURI = NULL;
544 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
545 xsltGenericError(xsltGenericErrorContext,
546 "system-property() : expects one string arg\n");
547 ctxt->error = XPATH_INVALID_ARITY;
550 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
551 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
552 xsltGenericError(xsltGenericErrorContext,
553 "system-property() : invalid arg expecting a string\n");
554 ctxt->error = XPATH_INVALID_TYPE;
557 obj = valuePop(ctxt);
558 if (obj->stringval == NULL) {
559 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
561 name = xmlSplitQName2(obj->stringval, &prefix);
563 name = xmlStrdup(obj->stringval);
565 nsURI = xmlXPathNsLookup(ctxt->context, prefix);
567 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
569 xsltGenericError(xsltGenericErrorContext,
570 "system-property() : prefix %s is not bound\n", prefix);
574 if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) {
575 #ifdef DOCBOOK_XSL_HACK
576 if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
577 xsltStylesheetPtr sheet;
578 xsltTransformContextPtr tctxt;
580 tctxt = xsltXPathGetTransformContext(ctxt);
581 if ((tctxt != NULL) && (tctxt->inst != NULL) &&
582 (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) &&
583 (tctxt->inst->parent != NULL) &&
584 (xmlStrEqual(tctxt->inst->parent->name,
585 BAD_CAST "template")))
586 sheet = tctxt->style;
589 if ((sheet != NULL) && (sheet->doc != NULL) &&
590 (sheet->doc->URL != NULL) &&
591 (xmlStrstr(sheet->doc->URL,
592 (const xmlChar *)"chunk") != NULL)) {
593 valuePush(ctxt, xmlXPathNewString(
594 (const xmlChar *)"libxslt (SAXON 6.2 compatible)"));
597 valuePush(ctxt, xmlXPathNewString(
598 (const xmlChar *)XSLT_DEFAULT_VENDOR));
602 if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
603 valuePush(ctxt, xmlXPathNewString(
604 (const xmlChar *)XSLT_DEFAULT_VENDOR));
607 if (xmlStrEqual(name, (const xmlChar *)"version")) {
608 valuePush(ctxt, xmlXPathNewString(
609 (const xmlChar *)XSLT_DEFAULT_VERSION));
610 } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) {
611 valuePush(ctxt, xmlXPathNewString(
612 (const xmlChar *)XSLT_DEFAULT_URL));
614 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
622 xmlXPathFreeObject(obj);
626 * xsltElementAvailableFunction:
627 * @ctxt: the XPath Parser context
628 * @nargs: the number of arguments
630 * Implement the element-available() XSLT function
631 * boolean element-available(string)
634 xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
635 xmlXPathObjectPtr obj;
636 xmlChar *prefix, *name;
637 const xmlChar *nsURI = NULL;
638 xsltTransformContextPtr tctxt;
641 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
642 xsltGenericError(xsltGenericErrorContext,
643 "element-available() : expects one string arg\n");
644 ctxt->error = XPATH_INVALID_ARITY;
647 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
648 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
649 xsltGenericError(xsltGenericErrorContext,
650 "element-available() : invalid arg expecting a string\n");
651 ctxt->error = XPATH_INVALID_TYPE;
654 obj = valuePop(ctxt);
655 tctxt = xsltXPathGetTransformContext(ctxt);
657 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
658 xsltGenericError(xsltGenericErrorContext,
659 "element-available() : internal error tctxt == NULL\n");
660 xmlXPathFreeObject(obj);
661 valuePush(ctxt, xmlXPathNewBoolean(0));
666 name = xmlSplitQName2(obj->stringval, &prefix);
670 name = xmlStrdup(obj->stringval);
671 ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
672 nsURI = xmlStrdup(ns->href);
674 nsURI = xmlXPathNsLookup(ctxt->context, prefix);
676 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
678 xsltGenericError(xsltGenericErrorContext,
679 "element-available() : prefix %s is not bound\n", prefix);
683 if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {
684 valuePush(ctxt, xmlXPathNewBoolean(1));
686 valuePush(ctxt, xmlXPathNewBoolean(0));
689 xmlXPathFreeObject(obj);
697 * xsltFunctionAvailableFunction:
698 * @ctxt: the XPath Parser context
699 * @nargs: the number of arguments
701 * Implement the function-available() XSLT function
702 * boolean function-available(string)
705 xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
706 xmlXPathObjectPtr obj;
707 xmlChar *prefix, *name;
708 const xmlChar *nsURI = NULL;
711 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
712 xsltGenericError(xsltGenericErrorContext,
713 "function-available() : expects one string arg\n");
714 ctxt->error = XPATH_INVALID_ARITY;
717 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
718 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
719 xsltGenericError(xsltGenericErrorContext,
720 "function-available() : invalid arg expecting a string\n");
721 ctxt->error = XPATH_INVALID_TYPE;
724 obj = valuePop(ctxt);
726 name = xmlSplitQName2(obj->stringval, &prefix);
728 name = xmlStrdup(obj->stringval);
730 nsURI = xmlXPathNsLookup(ctxt->context, prefix);
732 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
734 xsltGenericError(xsltGenericErrorContext,
735 "function-available() : prefix %s is not bound\n", prefix);
739 if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) {
740 valuePush(ctxt, xmlXPathNewBoolean(1));
742 valuePush(ctxt, xmlXPathNewBoolean(0));
745 xmlXPathFreeObject(obj);
753 * xsltCurrentFunction:
754 * @ctxt: the XPath Parser context
755 * @nargs: the number of arguments
757 * Implement the current() XSLT function
761 xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
762 xsltTransformContextPtr tctxt;
765 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
766 xsltGenericError(xsltGenericErrorContext,
767 "current() : function uses no argument\n");
768 ctxt->error = XPATH_INVALID_ARITY;
771 tctxt = xsltXPathGetTransformContext(ctxt);
773 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
774 xsltGenericError(xsltGenericErrorContext,
775 "current() : internal error tctxt == NULL\n");
776 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
778 valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */
782 /************************************************************************
784 * Registration of XSLT and libxslt functions *
786 ************************************************************************/
789 * xsltRegisterAllFunctions:
790 * @ctxt: the XPath context
792 * Registers all default XSLT functions in this context
795 xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)
797 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",
798 xsltCurrentFunction);
799 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",
800 xsltDocumentFunction);
801 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);
802 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",
803 xsltUnparsedEntityURIFunction);
804 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",
805 xsltFormatNumberFunction);
806 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",
807 xsltGenerateIdFunction);
808 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",
809 xsltSystemPropertyFunction);
810 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",
811 xsltElementAvailableFunction);
812 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
813 xsltFunctionAvailableFunction);