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