Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(691)

Side by Side Diff: third_party/libxslt/libxslt/functions.c

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

Powered by Google App Engine
This is Rietveld 408576698