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.
9 * Daniel.Veillard@imag.fr
10 * Bjorn Reese <breese@users.sourceforge.net> for number formatting
13 #include "xsltconfig.h"
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 "numbersInternals.h"
40 #define DEBUG_FUNCTION
43 /************************************************************************
47 ************************************************************************/
50 * xsltDocumentFunction:
51 * @ctxt: the XPath Parser context
52 * @nargs: the number of arguments
54 * Implement the document() XSLT function
55 * node-set document(object, node-set?)
58 xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){
60 xmlXPathObjectPtr obj;
64 if ((nargs < 1) || (nargs > 2)) {
65 xsltGenericError(xsltGenericErrorContext,
66 "document() : invalid number of args %d\n", nargs);
67 ctxt->error = XPATH_INVALID_ARITY;
70 if (ctxt->value == NULL) {
71 xsltGenericError(xsltGenericErrorContext,
72 "document() : invalid arg value\n");
73 ctxt->error = XPATH_INVALID_TYPE;
76 if (ctxt->value->type == XPATH_NODESET) {
78 xsltGenericError(xsltGenericErrorContext,
79 "document() : with node-sets args not yet supported\n");
83 * Make sure it's converted to a string
85 xmlXPathStringFunction(ctxt, 1);
86 if (ctxt->value->type != XPATH_STRING) {
87 xsltGenericError(xsltGenericErrorContext,
88 "document() : invalid arg expecting a string\n");
89 ctxt->error = XPATH_INVALID_TYPE;
93 if (obj->stringval == NULL) {
94 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
96 base = xmlNodeGetBase(ctxt->context->doc, ctxt->context->node);
97 URI = xmlBuildURI(obj->stringval, base);
101 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
103 doc = xmlParseDoc(URI);
105 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
107 xsltTransformContextPtr tctxt;
110 * link it to the context for cleanup when done
112 tctxt = (xsltTransformContextPtr) ctxt->context->extra;
114 xsltGenericError(xsltGenericErrorContext,
115 "document() : internal error tctxt == NULL\n");
117 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
120 * Keep a link from the context to be able to deallocate
122 doc->next = (xmlNodePtr) tctxt->extraDocs;
123 tctxt->extraDocs = doc;
125 /* TODO: use XPointer of HTML location for fragment ID */
126 /* pbm #xxx can lead to location sets, not nodesets :-) */
127 valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
132 xmlXPathFreeObject(obj);
137 * @ctxt: the XPath Parser context
138 * @nargs: the number of arguments
140 * Implement the key() XSLT function
141 * node-set key(string, object)
144 xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
149 * xsltUnparsedEntityURIFunction:
150 * @ctxt: the XPath Parser context
151 * @nargs: the number of arguments
153 * Implement the unparsed-entity-uri() XSLT function
154 * string unparsed-entity-uri(string)
157 xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
158 xmlXPathObjectPtr obj;
162 xsltGenericError(xsltGenericErrorContext,
163 "system-property() : expects one string arg\n");
164 ctxt->error = XPATH_INVALID_ARITY;
167 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
168 xsltGenericError(xsltGenericErrorContext,
169 "generate-id() : invalid arg expecting a string\n");
170 ctxt->error = XPATH_INVALID_TYPE;
173 obj = valuePop(ctxt);
174 str = obj->stringval;
176 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
180 entity = xmlGetDocEntity(ctxt->context->doc, str);
181 if (entity == NULL) {
182 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
184 if (entity->URI != NULL)
185 valuePush(ctxt, xmlXPathNewString(entity->URI));
187 valuePush(ctxt, xmlXPathNewString(
188 xmlStrdup((const xmlChar *)"")));
191 xmlXPathFreeObject(obj);
195 * xsltFormatNumberFunction:
196 * @ctxt: the XPath Parser context
197 * @nargs: the number of arguments
199 * Implement the format-number() XSLT function
200 * string format-number(number, string, string?)
203 xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
205 xmlXPathObjectPtr numberObj = NULL;
206 xmlXPathObjectPtr formatObj = NULL;
207 xmlXPathObjectPtr decimalObj = NULL;
208 xsltStylesheetPtr sheet;
209 xsltDecimalFormatPtr formatValues;
212 sheet = ((xsltTransformContextPtr)ctxt->context->extra)->style;
213 formatValues = sheet->decimalFormat;
218 decimalObj = valuePop(ctxt);
219 formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);
220 /* Intentional fall-through */
223 formatObj = valuePop(ctxt);
225 numberObj = valuePop(ctxt);
228 XP_ERROR(XPATH_INVALID_ARITY);
232 if (xsltFormatNumberConversion(formatValues,
233 formatObj->stringval,
235 &result) == XPATH_EXPRESSION_OK) {
236 valuePush(ctxt, xmlXPathNewString(result));
240 xmlXPathFreeObject(numberObj);
241 xmlXPathFreeObject(formatObj);
242 xmlXPathFreeObject(decimalObj);
246 * xsltGenerateIdFunction:
247 * @ctxt: the XPath Parser context
248 * @nargs: the number of arguments
250 * Implement the generate-id() XSLT function
251 * string generate-id(node-set?)
254 xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
255 xmlNodePtr cur = NULL;
260 cur = ctxt->context->node;
261 } else if (nargs == 1) {
262 xmlXPathObjectPtr obj;
263 xmlNodeSetPtr nodelist;
266 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
267 ctxt->error = XPATH_INVALID_TYPE;
268 xsltGenericError(xsltGenericErrorContext,
269 "generate-id() : invalid arg expecting a node-set\n");
272 obj = valuePop(ctxt);
273 nodelist = obj->nodesetval;
274 if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
275 ctxt->error = XPATH_INVALID_TYPE;
276 xsltGenericError(xsltGenericErrorContext,
277 "generate-id() : got an empty node-set\n");
278 xmlXPathFreeObject(obj);
281 cur = nodelist->nodeTab[0];
282 for (i = 2;i <= nodelist->nodeNr;i++) {
283 ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
285 cur = nodelist->nodeTab[i];
287 xmlXPathFreeObject(obj);
289 xsltGenericError(xsltGenericErrorContext,
290 "generate-id() : invalid number of args %d\n", nargs);
291 ctxt->error = XPATH_INVALID_ARITY;
295 * Okay this is ugly but should work, use the NodePtr address
298 val = (unsigned long)((char *)cur - (char *)0);
299 val /= sizeof(xmlNode);
301 sprintf((char *)str, "id%10ld", val);
302 valuePush(ctxt, xmlXPathNewString(str));
306 * xsltSystemPropertyFunction:
307 * @ctxt: the XPath Parser context
308 * @nargs: the number of arguments
310 * Implement the system-property() XSLT function
311 * object system-property(string)
314 xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
315 xmlXPathObjectPtr obj;
319 xsltGenericError(xsltGenericErrorContext,
320 "system-property() : expects one string arg\n");
321 ctxt->error = XPATH_INVALID_ARITY;
324 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
325 xsltGenericError(xsltGenericErrorContext,
326 "generate-id() : invalid arg expecting a string\n");
327 ctxt->error = XPATH_INVALID_TYPE;
330 obj = valuePop(ctxt);
331 str = obj->stringval;
333 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
334 } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:version")) {
335 valuePush(ctxt, xmlXPathNewString(
336 (const xmlChar *)XSLT_DEFAULT_VERSION));
337 } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:vendor")) {
338 valuePush(ctxt, xmlXPathNewString(
339 (const xmlChar *)XSLT_DEFAULT_VENDOR));
340 } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:vendor-url")) {
341 valuePush(ctxt, xmlXPathNewString(
342 (const xmlChar *)XSLT_DEFAULT_URL));
344 /* TODO cheated with the QName resolution */
345 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
347 xmlXPathFreeObject(obj);
351 * xsltElementAvailableFunction:
352 * @ctxt: the XPath Parser context
353 * @nargs: the number of arguments
355 * Implement the element-available() XSLT function
356 * boolean element-available(string)
359 xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
360 xmlXPathObjectPtr obj;
363 xsltGenericError(xsltGenericErrorContext,
364 "element-available() : expects one string arg\n");
365 ctxt->error = XPATH_INVALID_ARITY;
368 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
369 xsltGenericError(xsltGenericErrorContext,
370 "element-available invalid arg expecting a string\n");
371 ctxt->error = XPATH_INVALID_TYPE;
374 obj = valuePop(ctxt);
375 xmlXPathFreeObject(obj);
376 valuePush(ctxt, xmlXPathNewBoolean(0));
380 * xsltFunctionAvailableFunction:
381 * @ctxt: the XPath Parser context
382 * @nargs: the number of arguments
384 * Implement the function-available() XSLT function
385 * boolean function-available(string)
388 xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
389 xmlXPathObjectPtr obj;
392 xsltGenericError(xsltGenericErrorContext,
393 "function-available() : expects one string arg\n");
394 ctxt->error = XPATH_INVALID_ARITY;
397 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
398 xsltGenericError(xsltGenericErrorContext,
399 "function-available invalid arg expecting a string\n");
400 ctxt->error = XPATH_INVALID_TYPE;
403 obj = valuePop(ctxt);
404 xmlXPathFreeObject(obj);
405 valuePush(ctxt, xmlXPathNewBoolean(0));
409 * xsltCurrentFunction:
410 * @ctxt: the XPath Parser context
411 * @nargs: the number of arguments
413 * Implement the current() XSLT function
417 xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
419 xsltGenericError(xsltGenericErrorContext,
420 "document() : function uses no argument\n");
421 ctxt->error = XPATH_INVALID_ARITY;
424 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
428 * xsltRegisterAllFunctions:
429 * @ctxt: the XPath context
431 * Registers all default XSLT functions in this context
434 xsltRegisterAllFunctions(xmlXPathContextPtr ctxt) {
435 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"current",
436 xsltCurrentFunction);
437 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"document",
438 xsltDocumentFunction);
439 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"key",
441 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"unparsed-entity-uri",
442 xsltUnparsedEntityURIFunction);
443 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"format-number",
444 xsltFormatNumberFunction);
445 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"generate-id",
446 xsltGenerateIdFunction);
447 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"system-property",
448 xsltSystemPropertyFunction);
449 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"element-available",
450 xsltElementAvailableFunction);
451 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"function-available",
452 xsltFunctionAvailableFunction);