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
15 #include <libxml/xpointer.h>
17 #ifdef WITH_XSLT_DEBUG
18 #define WITH_XSLT_DEBUG_FUNCTION
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/>
26 #define DOCBOOK_XSL_HACK
29 * xsltXPathFunctionLookup:
30 * @ctxt: a void * but the XSLT transformation context actually
31 * @name: the function name
32 * @ns_uri: the function namespace URI
34 * This is the entry point when a function is needed by the XPath
37 * Returns the callback function or NULL if not found
40 xsltXPathFunctionLookup (xmlXPathContextPtr ctxt
,
41 const xmlChar
*name
, const xmlChar
*ns_uri
) {
44 if ((ctxt
== NULL
) || (name
== NULL
) || (ns_uri
== NULL
))
47 #ifdef WITH_XSLT_DEBUG_FUNCTION
48 xsltGenericDebug(xsltGenericDebugContext
,
49 "Lookup function {%s}%s\n", ns_uri
, name
);
52 /* give priority to context-level functions */
54 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
56 XML_CAST_FPTR(ret
) = xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
59 ret
= xsltExtModuleFunctionLookup(name
, ns_uri
);
61 #ifdef WITH_XSLT_DEBUG_FUNCTION
63 xsltGenericDebug(xsltGenericDebugContext
,
64 "found function %s\n", name
);
70 /************************************************************************
74 ************************************************************************/
77 xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt
, xmlChar
* URI
)
79 xsltTransformContextPtr tctxt
;
82 xsltDocumentPtr idoc
; /* document info */
84 xmlXPathContextPtr xptrctxt
= NULL
;
85 xmlXPathObjectPtr resObj
= NULL
;
87 tctxt
= xsltXPathGetTransformContext(ctxt
);
89 xsltTransformError(NULL
, NULL
, NULL
,
90 "document() : internal error tctxt == NULL\n");
91 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
95 uri
= xmlParseURI((const char *) URI
);
97 xsltTransformError(tctxt
, NULL
, NULL
,
98 "document() : failed to parse URI\n");
99 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
104 * check for and remove fragment identifier
106 fragment
= (xmlChar
*)uri
->fragment
;
107 if (fragment
!= NULL
) {
109 uri
->fragment
= NULL
;
110 newURI
= xmlSaveUri(uri
);
111 idoc
= xsltLoadDocument(tctxt
, newURI
);
114 idoc
= xsltLoadDocument(tctxt
, URI
);
120 ((tctxt
->style
->doc
!= NULL
) &&
121 (xmlStrEqual(tctxt
->style
->doc
->URL
, URI
))))
124 * This selects the stylesheet's doc itself.
126 doc
= tctxt
->style
->doc
;
128 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
130 if (fragment
!= NULL
)
138 if (fragment
== NULL
) {
139 valuePush(ctxt
, xmlXPathNewNodeSet((xmlNodePtr
) doc
));
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");
152 resObj
= xmlXPtrEval(fragment
, xptrctxt
);
153 xmlXPathFreeContext(xptrctxt
);
159 switch (resObj
->type
) {
162 case XPATH_UNDEFINED
:
168 case XPATH_XSLT_TREE
:
170 case XPATH_LOCATIONSET
:
171 xsltTransformError(tctxt
, NULL
, NULL
,
172 "document() : XPointer does not select a node set: #%s\n",
177 valuePush(ctxt
, resObj
);
182 xmlXPathFreeObject(resObj
);
185 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
190 * xsltDocumentFunction:
191 * @ctxt: the XPath Parser context
192 * @nargs: the number of arguments
194 * Implement the document() XSLT function
195 * node-set document(object, node-set?)
198 xsltDocumentFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
200 xmlXPathObjectPtr obj
, obj2
= NULL
;
201 xmlChar
*base
= NULL
, *URI
;
204 if ((nargs
< 1) || (nargs
> 2)) {
205 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
206 "document() : invalid number of args %d\n",
208 ctxt
->error
= XPATH_INVALID_ARITY
;
211 if (ctxt
->value
== NULL
) {
212 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
213 "document() : invalid arg value\n");
214 ctxt
->error
= XPATH_INVALID_TYPE
;
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
;
226 obj2
= valuePop(ctxt
);
229 if (ctxt
->value
->type
== XPATH_NODESET
) {
231 xmlXPathObjectPtr newobj
, ret
;
233 obj
= valuePop(ctxt
);
234 ret
= xmlXPathNewNodeSet(NULL
);
236 if ((obj
!= NULL
) && obj
->nodesetval
) {
237 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
239 xmlXPathNewNodeSet(obj
->nodesetval
->nodeTab
[i
]));
240 xmlXPathStringFunction(ctxt
, 1);
242 valuePush(ctxt
, xmlXPathObjectCopy(obj2
));
245 xmlXPathNewNodeSet(obj
->nodesetval
->
248 xsltDocumentFunction(ctxt
, 2);
249 newobj
= valuePop(ctxt
);
250 ret
->nodesetval
= xmlXPathNodeSetMerge(ret
->nodesetval
,
252 xmlXPathFreeObject(newobj
);
257 xmlXPathFreeObject(obj
);
259 xmlXPathFreeObject(obj2
);
260 valuePush(ctxt
, ret
);
264 * Make sure it's converted to a string
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
;
272 xmlXPathFreeObject(obj2
);
275 obj
= valuePop(ctxt
);
276 if (obj
->stringval
== NULL
) {
277 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
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])) {
286 target
= obj2
->nodesetval
->nodeTab
[0];
287 if ((target
->type
== XML_ATTRIBUTE_NODE
) ||
288 (target
->type
== XML_PI_NODE
)) {
289 target
= ((xmlAttrPtr
) target
)->parent
;
291 base
= xmlNodeGetBase(target
->doc
, target
);
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
);
301 URI
= xmlBuildURI(obj
->stringval
, base
);
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
));
311 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
314 xsltDocumentFunctionLoadDocument( ctxt
, URI
);
318 xmlXPathFreeObject(obj
);
320 xmlXPathFreeObject(obj2
);
325 * @ctxt: the XPath Parser context
326 * @nargs: the number of arguments
328 * Implement the key() XSLT function
329 * node-set key(string, object)
332 xsltKeyFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
333 xmlXPathObjectPtr obj1
, obj2
;
336 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
337 "key() : expects two arguments\n");
338 ctxt
->error
= XPATH_INVALID_ARITY
;
343 * Get the key's value.
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
);
357 * Get the key's name.
359 obj1
= valuePop(ctxt
);
361 if ((obj2
->type
== XPATH_NODESET
) || (obj2
->type
== XPATH_XSLT_TREE
)) {
363 xmlXPathObjectPtr newobj
, ret
;
365 ret
= xmlXPathNewNodeSet(NULL
);
367 if (obj2
->nodesetval
!= NULL
) {
368 for (i
= 0; i
< obj2
->nodesetval
->nodeNr
; i
++) {
369 valuePush(ctxt
, xmlXPathObjectCopy(obj1
));
371 xmlXPathNewNodeSet(obj2
->nodesetval
->nodeTab
[i
]));
372 xmlXPathStringFunction(ctxt
, 1);
373 xsltKeyFunction(ctxt
, 2);
374 newobj
= valuePop(ctxt
);
375 ret
->nodesetval
= xmlXPathNodeSetMerge(ret
->nodesetval
,
377 xmlXPathFreeObject(newobj
);
380 valuePush(ctxt
, ret
);
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
;
391 tctxt
= xsltXPathGetTransformContext(ctxt
);
393 oldDocInfo
= tctxt
->document
;
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
;
403 * Get the associated namespace URI if qualified name
405 qname
= obj1
->stringval
;
406 key
= xmlSplitQName2(qname
, &prefix
);
408 key
= xmlStrdup(obj1
->stringval
);
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
);
419 * TODO: Shouldn't we stop here?
429 * Force conversion of first arg to string
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
;
439 obj2
= valuePop(ctxt
);
440 value
= obj2
->stringval
;
443 * We need to ensure that ctxt->document is available for
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.
452 if (xpctxt
->node
->type
== XML_NAMESPACE_DECL
) {
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.
458 if ((((xmlNsPtr
) xpctxt
->node
)->next
!= NULL
) &&
459 (((xmlNsPtr
) xpctxt
->node
)->next
->type
== XML_ELEMENT_NODE
))
461 tmpNode
= (xmlNodePtr
) ((xmlNsPtr
) xpctxt
->node
)->next
;
464 tmpNode
= xpctxt
->node
;
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");
473 if ((tctxt
->document
== NULL
) ||
474 (tctxt
->document
->doc
!= tmpNode
->doc
))
476 if (tmpNode
->doc
->name
&& (tmpNode
->doc
->name
[0] == ' ')) {
478 * This is a Result Tree Fragment.
480 if (tmpNode
->doc
->_private
== NULL
) {
481 tmpNode
->doc
->_private
= xsltNewDocument(tctxt
, tmpNode
->doc
);
482 if (tmpNode
->doc
->_private
== NULL
)
485 tctxt
->document
= (xsltDocumentPtr
) tmpNode
->doc
->_private
;
488 * May be the initial source doc or a doc acquired via the
489 * document() function.
491 tctxt
->document
= xsltFindDocument(tctxt
, tmpNode
->doc
);
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
;
502 * Get/compute the key value.
504 nodelist
= xsltGetKey(tctxt
, key
, keyURI
, value
);
507 tctxt
->document
= oldDocInfo
;
508 valuePush(ctxt
, xmlXPathWrapNodeSet(
509 xmlXPathNodeSetMerge(NULL
, nodelist
)));
515 xmlXPathFreeObject(obj1
);
517 xmlXPathFreeObject(obj2
);
521 * xsltUnparsedEntityURIFunction:
522 * @ctxt: the XPath Parser context
523 * @nargs: the number of arguments
525 * Implement the unparsed-entity-uri() XSLT function
526 * string unparsed-entity-uri(string)
529 xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
530 xmlXPathObjectPtr obj
;
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
;
539 obj
= valuePop(ctxt
);
540 if (obj
->type
!= XPATH_STRING
) {
541 obj
= xmlXPathConvertString(obj
);
544 str
= obj
->stringval
;
546 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
550 entity
= xmlGetDocEntity(ctxt
->context
->doc
, str
);
551 if (entity
== NULL
) {
552 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
554 if (entity
->URI
!= NULL
)
555 valuePush(ctxt
, xmlXPathNewString(entity
->URI
));
557 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
560 xmlXPathFreeObject(obj
);
564 * xsltFormatNumberFunction:
565 * @ctxt: the XPath Parser context
566 * @nargs: the number of arguments
568 * Implement the format-number() XSLT function
569 * string format-number(number, string, string?)
572 xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
574 xmlXPathObjectPtr numberObj
= NULL
;
575 xmlXPathObjectPtr formatObj
= NULL
;
576 xmlXPathObjectPtr decimalObj
= NULL
;
577 xsltStylesheetPtr sheet
;
578 xsltDecimalFormatPtr formatValues
= NULL
;
580 const xmlChar
*ncname
;
581 const xmlChar
*prefix
= NULL
;
582 const xmlChar
*nsUri
= NULL
;
583 xsltTransformContextPtr tctxt
;
585 tctxt
= xsltXPathGetTransformContext(ctxt
);
586 if ((tctxt
== NULL
) || (tctxt
->inst
== NULL
))
588 sheet
= tctxt
->style
;
591 formatValues
= sheet
->decimalFormat
;
596 decimalObj
= valuePop(ctxt
);
597 ncname
= xsltSplitQName(sheet
->dict
, decimalObj
->stringval
, &prefix
);
598 if (prefix
!= NULL
) {
599 xmlNsPtr ns
= xmlSearchNs(tctxt
->inst
->doc
, tctxt
->inst
, prefix
);
601 xsltTransformError(tctxt
, NULL
, NULL
,
602 "format-number : No namespace found for QName '%s:%s'\n",
611 if (ncname
!= NULL
) {
612 formatValues
= xsltDecimalFormatGetByQName(sheet
, nsUri
, ncname
);
614 if (formatValues
== NULL
) {
615 xsltTransformError(tctxt
, NULL
, NULL
,
616 "format-number() : undeclared decimal format '%s'\n",
617 decimalObj
->stringval
);
619 /* Intentional fall-through */
622 formatObj
= valuePop(ctxt
);
624 numberObj
= valuePop(ctxt
);
627 XP_ERROR(XPATH_INVALID_ARITY
);
630 if (formatValues
!= NULL
) {
631 if (xsltFormatNumberConversion(formatValues
,
632 formatObj
->stringval
,
634 &result
) == XPATH_EXPRESSION_OK
) {
635 valuePush(ctxt
, xmlXPathNewString(result
));
640 xmlXPathFreeObject(numberObj
);
641 xmlXPathFreeObject(formatObj
);
642 xmlXPathFreeObject(decimalObj
);
646 * xsltGenerateIdFunction:
647 * @ctxt: the XPath Parser context
648 * @nargs: the number of arguments
650 * Implement the generate-id() XSLT function
651 * string generate-id(node-set?)
654 xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
655 static char base_address
;
656 xmlNodePtr cur
= NULL
;
657 xmlXPathObjectPtr obj
= NULL
;
662 cur
= ctxt
->context
->node
;
663 } else if (nargs
== 1) {
664 xmlNodeSetPtr nodelist
;
667 if ((ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_NODESET
)) {
668 ctxt
->error
= XPATH_INVALID_TYPE
;
669 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
670 "generate-id() : invalid arg expecting a node-set\n");
673 obj
= valuePop(ctxt
);
674 nodelist
= obj
->nodesetval
;
675 if ((nodelist
== NULL
) || (nodelist
->nodeNr
<= 0)) {
676 xmlXPathFreeObject(obj
);
677 valuePush(ctxt
, xmlXPathNewCString(""));
680 cur
= nodelist
->nodeTab
[0];
681 for (i
= 1;i
< nodelist
->nodeNr
;i
++) {
682 ret
= xmlXPathCmpNodes(cur
, nodelist
->nodeTab
[i
]);
684 cur
= nodelist
->nodeTab
[i
];
687 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
688 "generate-id() : invalid number of args %d\n", nargs
);
689 ctxt
->error
= XPATH_INVALID_ARITY
;
694 xmlXPathFreeObject(obj
);
696 val
= (long)((char *)cur
- (char *)&base_address
);
698 snprintf((char *)str
, sizeof(str
), "idp%ld", val
);
700 snprintf((char *)str
, sizeof(str
), "idm%ld", -val
);
702 valuePush(ctxt
, xmlXPathNewString(str
));
706 * xsltSystemPropertyFunction:
707 * @ctxt: the XPath Parser context
708 * @nargs: the number of arguments
710 * Implement the system-property() XSLT function
711 * object system-property(string)
714 xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
715 xmlXPathObjectPtr obj
;
716 xmlChar
*prefix
, *name
;
717 const xmlChar
*nsURI
= NULL
;
720 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
721 "system-property() : expects one string arg\n");
722 ctxt
->error
= XPATH_INVALID_ARITY
;
725 if ((ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_STRING
)) {
726 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
727 "system-property() : invalid arg expecting a string\n");
728 ctxt
->error
= XPATH_INVALID_TYPE
;
731 obj
= valuePop(ctxt
);
732 if (obj
->stringval
== NULL
) {
733 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
735 name
= xmlSplitQName2(obj
->stringval
, &prefix
);
737 name
= xmlStrdup(obj
->stringval
);
739 nsURI
= xmlXPathNsLookup(ctxt
->context
, prefix
);
741 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
742 "system-property() : prefix %s is not bound\n", prefix
);
746 if (xmlStrEqual(nsURI
, XSLT_NAMESPACE
)) {
747 #ifdef DOCBOOK_XSL_HACK
748 if (xmlStrEqual(name
, (const xmlChar
*)"vendor")) {
749 xsltStylesheetPtr sheet
;
750 xsltTransformContextPtr tctxt
;
752 tctxt
= xsltXPathGetTransformContext(ctxt
);
753 if ((tctxt
!= NULL
) && (tctxt
->inst
!= NULL
) &&
754 (xmlStrEqual(tctxt
->inst
->name
, BAD_CAST
"variable")) &&
755 (tctxt
->inst
->parent
!= NULL
) &&
756 (xmlStrEqual(tctxt
->inst
->parent
->name
,
757 BAD_CAST
"template")))
758 sheet
= tctxt
->style
;
761 if ((sheet
!= NULL
) && (sheet
->doc
!= NULL
) &&
762 (sheet
->doc
->URL
!= NULL
) &&
763 (xmlStrstr(sheet
->doc
->URL
,
764 (const xmlChar
*)"chunk") != NULL
)) {
765 valuePush(ctxt
, xmlXPathNewString(
766 (const xmlChar
*)"libxslt (SAXON 6.2 compatible)"));
769 valuePush(ctxt
, xmlXPathNewString(
770 (const xmlChar
*)XSLT_DEFAULT_VENDOR
));
774 if (xmlStrEqual(name
, (const xmlChar
*)"vendor")) {
775 valuePush(ctxt
, xmlXPathNewString(
776 (const xmlChar
*)XSLT_DEFAULT_VENDOR
));
779 if (xmlStrEqual(name
, (const xmlChar
*)"version")) {
780 valuePush(ctxt
, xmlXPathNewString(
781 (const xmlChar
*)XSLT_DEFAULT_VERSION
));
782 } else if (xmlStrEqual(name
, (const xmlChar
*)"vendor-url")) {
783 valuePush(ctxt
, xmlXPathNewString(
784 (const xmlChar
*)XSLT_DEFAULT_URL
));
786 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
789 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
796 xmlXPathFreeObject(obj
);
800 * xsltElementAvailableFunction:
801 * @ctxt: the XPath Parser context
802 * @nargs: the number of arguments
804 * Implement the element-available() XSLT function
805 * boolean element-available(string)
808 xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
809 xmlXPathObjectPtr obj
;
810 xmlChar
*prefix
, *name
;
811 const xmlChar
*nsURI
= NULL
;
812 xsltTransformContextPtr tctxt
;
815 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
816 "element-available() : expects one string arg\n");
817 ctxt
->error
= XPATH_INVALID_ARITY
;
820 xmlXPathStringFunction(ctxt
, 1);
821 if ((ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_STRING
)) {
822 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
823 "element-available() : invalid arg expecting a string\n");
824 ctxt
->error
= XPATH_INVALID_TYPE
;
827 obj
= valuePop(ctxt
);
828 tctxt
= xsltXPathGetTransformContext(ctxt
);
829 if ((tctxt
== NULL
) || (tctxt
->inst
== NULL
)) {
830 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
831 "element-available() : internal error tctxt == NULL\n");
832 xmlXPathFreeObject(obj
);
833 valuePush(ctxt
, xmlXPathNewBoolean(0));
838 name
= xmlSplitQName2(obj
->stringval
, &prefix
);
842 name
= xmlStrdup(obj
->stringval
);
843 ns
= xmlSearchNs(tctxt
->inst
->doc
, tctxt
->inst
, NULL
);
844 if (ns
!= NULL
) nsURI
= ns
->href
;
846 nsURI
= xmlXPathNsLookup(ctxt
->context
, prefix
);
848 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
849 "element-available() : prefix %s is not bound\n", prefix
);
853 if (xsltExtElementLookup(tctxt
, name
, nsURI
) != NULL
) {
854 valuePush(ctxt
, xmlXPathNewBoolean(1));
856 valuePush(ctxt
, xmlXPathNewBoolean(0));
859 xmlXPathFreeObject(obj
);
867 * xsltFunctionAvailableFunction:
868 * @ctxt: the XPath Parser context
869 * @nargs: the number of arguments
871 * Implement the function-available() XSLT function
872 * boolean function-available(string)
875 xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
876 xmlXPathObjectPtr obj
;
877 xmlChar
*prefix
, *name
;
878 const xmlChar
*nsURI
= NULL
;
881 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
882 "function-available() : expects one string arg\n");
883 ctxt
->error
= XPATH_INVALID_ARITY
;
886 xmlXPathStringFunction(ctxt
, 1);
887 if ((ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_STRING
)) {
888 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
889 "function-available() : invalid arg expecting a string\n");
890 ctxt
->error
= XPATH_INVALID_TYPE
;
893 obj
= valuePop(ctxt
);
895 name
= xmlSplitQName2(obj
->stringval
, &prefix
);
897 name
= xmlStrdup(obj
->stringval
);
899 nsURI
= xmlXPathNsLookup(ctxt
->context
, prefix
);
901 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
902 "function-available() : prefix %s is not bound\n", prefix
);
906 if (xmlXPathFunctionLookupNS(ctxt
->context
, name
, nsURI
) != NULL
) {
907 valuePush(ctxt
, xmlXPathNewBoolean(1));
909 valuePush(ctxt
, xmlXPathNewBoolean(0));
912 xmlXPathFreeObject(obj
);
920 * xsltCurrentFunction:
921 * @ctxt: the XPath Parser context
922 * @nargs: the number of arguments
924 * Implement the current() XSLT function
928 xsltCurrentFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
929 xsltTransformContextPtr tctxt
;
932 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
933 "current() : function uses no argument\n");
934 ctxt
->error
= XPATH_INVALID_ARITY
;
937 tctxt
= xsltXPathGetTransformContext(ctxt
);
939 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
940 "current() : internal error tctxt == NULL\n");
941 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
943 valuePush(ctxt
, xmlXPathNewNodeSet(tctxt
->node
)); /* current */
947 /************************************************************************
949 * Registration of XSLT and libxslt functions *
951 ************************************************************************/
954 * xsltRegisterAllFunctions:
955 * @ctxt: the XPath context
957 * Registers all default XSLT functions in this context
960 xsltRegisterAllFunctions(xmlXPathContextPtr ctxt
)
962 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "current",
963 xsltCurrentFunction
);
964 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "document",
965 xsltDocumentFunction
);
966 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "key", xsltKeyFunction
);
967 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "unparsed-entity-uri",
968 xsltUnparsedEntityURIFunction
);
969 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "format-number",
970 xsltFormatNumberFunction
);
971 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "generate-id",
972 xsltGenerateIdFunction
);
973 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "system-property",
974 xsltSystemPropertyFunction
);
975 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "element-available",
976 xsltElementAvailableFunction
);
977 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "function-available",
978 xsltFunctionAvailableFunction
);