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
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
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>
37 #include "xsltInternals.h"
38 #include "xsltutils.h"
39 #include "functions.h"
40 #include "extensions.h"
41 #include "numbersInternals.h"
43 #include "documents.h"
45 #ifdef WITH_XSLT_DEBUG
46 #define WITH_XSLT_DEBUG_FUNCTION
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/>
54 #define DOCBOOK_XSL_HACK
57 * xsltXPathFunctionLookup:
58 * @ctxt: a void * but the XSLT transformation context actually
59 * @name: the function name
60 * @ns_uri: the function namespace URI
62 * This is the entry point when a function is needed by the XPath
65 * Returns the callback function or NULL if not found
68 xsltXPathFunctionLookup (xmlXPathContextPtr ctxt
,
69 const xmlChar
*name
, const xmlChar
*ns_uri
) {
72 if ((ctxt
== NULL
) || (name
== NULL
) || (ns_uri
== NULL
))
75 #ifdef WITH_XSLT_DEBUG_FUNCTION
76 xsltGenericDebug(xsltGenericDebugContext
,
77 "Lookup function {%s}%s\n", ns_uri
, name
);
80 /* give priority to context-level functions */
82 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
84 XML_CAST_FPTR(ret
) = xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
87 ret
= xsltExtModuleFunctionLookup(name
, ns_uri
);
89 #ifdef WITH_XSLT_DEBUG_FUNCTION
91 xsltGenericDebug(xsltGenericDebugContext
,
92 "found function %s\n", name
);
98 /************************************************************************
100 * Module interfaces *
102 ************************************************************************/
105 xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt
, xmlChar
* URI
)
107 xsltTransformContextPtr tctxt
;
110 xsltDocumentPtr idoc
; /* document info */
112 xmlXPathContextPtr xptrctxt
= NULL
;
113 xmlXPathObjectPtr resObj
= NULL
;
115 tctxt
= xsltXPathGetTransformContext(ctxt
);
117 xsltTransformError(NULL
, NULL
, NULL
,
118 "document() : internal error tctxt == NULL\n");
119 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
123 uri
= xmlParseURI((const char *) URI
);
125 xsltTransformError(tctxt
, NULL
, NULL
,
126 "document() : failed to parse URI\n");
127 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
132 * check for and remove fragment identifier
134 fragment
= (xmlChar
*)uri
->fragment
;
135 if (fragment
!= NULL
) {
137 uri
->fragment
= NULL
;
138 newURI
= xmlSaveUri(uri
);
139 idoc
= xsltLoadDocument(tctxt
, newURI
);
142 idoc
= xsltLoadDocument(tctxt
, URI
);
148 ((tctxt
->style
->doc
!= NULL
) &&
149 (xmlStrEqual(tctxt
->style
->doc
->URL
, URI
))))
152 * This selects the stylesheet's doc itself.
154 doc
= tctxt
->style
->doc
;
156 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
158 if (fragment
!= NULL
)
166 if (fragment
== NULL
) {
167 valuePush(ctxt
, xmlXPathNewNodeSet((xmlNodePtr
) doc
));
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");
180 resObj
= xmlXPtrEval(fragment
, xptrctxt
);
181 xmlXPathFreeContext(xptrctxt
);
188 switch (resObj
->type
) {
191 case XPATH_UNDEFINED
:
197 case XPATH_XSLT_TREE
:
199 case XPATH_LOCATIONSET
:
200 xsltTransformError(tctxt
, NULL
, NULL
,
201 "document() : XPointer does not select a node set: #%s\n",
206 valuePush(ctxt
, resObj
);
210 xmlXPathFreeObject(resObj
);
213 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
217 * xsltDocumentFunction:
218 * @ctxt: the XPath Parser context
219 * @nargs: the number of arguments
221 * Implement the document() XSLT function
222 * node-set document(object, node-set?)
225 xsltDocumentFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
227 xmlXPathObjectPtr obj
, obj2
= NULL
;
228 xmlChar
*base
= NULL
, *URI
;
231 if ((nargs
< 1) || (nargs
> 2)) {
232 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
233 "document() : invalid number of args %d\n",
235 ctxt
->error
= XPATH_INVALID_ARITY
;
238 if (ctxt
->value
== NULL
) {
239 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
240 "document() : invalid arg value\n");
241 ctxt
->error
= XPATH_INVALID_TYPE
;
246 if (ctxt
->value
->type
!= XPATH_NODESET
) {
247 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
248 "document() : invalid arg expecting a nodeset\n");
249 ctxt
->error
= XPATH_INVALID_TYPE
;
253 obj2
= valuePop(ctxt
);
256 if (ctxt
->value
->type
== XPATH_NODESET
) {
258 xmlXPathObjectPtr newobj
, ret
;
260 obj
= valuePop(ctxt
);
261 ret
= xmlXPathNewNodeSet(NULL
);
263 if (obj
->nodesetval
) {
264 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
266 xmlXPathNewNodeSet(obj
->nodesetval
->nodeTab
[i
]));
267 xmlXPathStringFunction(ctxt
, 1);
269 valuePush(ctxt
, xmlXPathObjectCopy(obj2
));
272 xmlXPathNewNodeSet(obj
->nodesetval
->
275 xsltDocumentFunction(ctxt
, 2);
276 newobj
= valuePop(ctxt
);
277 ret
->nodesetval
= xmlXPathNodeSetMerge(ret
->nodesetval
,
279 xmlXPathFreeObject(newobj
);
283 xmlXPathFreeObject(obj
);
285 xmlXPathFreeObject(obj2
);
286 valuePush(ctxt
, ret
);
290 * Make sure it's converted to a string
292 xmlXPathStringFunction(ctxt
, 1);
293 if (ctxt
->value
->type
!= XPATH_STRING
) {
294 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
295 "document() : invalid arg expecting a string\n");
296 ctxt
->error
= XPATH_INVALID_TYPE
;
298 xmlXPathFreeObject(obj2
);
301 obj
= valuePop(ctxt
);
302 if (obj
->stringval
== NULL
) {
303 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
305 if ((obj2
!= NULL
) && (obj2
->nodesetval
!= NULL
) &&
306 (obj2
->nodesetval
->nodeNr
> 0) &&
307 IS_XSLT_REAL_NODE(obj2
->nodesetval
->nodeTab
[0])) {
310 target
= obj2
->nodesetval
->nodeTab
[0];
311 if ((target
->type
== XML_ATTRIBUTE_NODE
) ||
312 (target
->type
== XML_PI_NODE
)) {
313 target
= ((xmlAttrPtr
) target
)->parent
;
315 base
= xmlNodeGetBase(target
->doc
, target
);
317 xsltTransformContextPtr tctxt
;
319 tctxt
= xsltXPathGetTransformContext(ctxt
);
320 if ((tctxt
!= NULL
) && (tctxt
->inst
!= NULL
)) {
321 base
= xmlNodeGetBase(tctxt
->inst
->doc
, tctxt
->inst
);
322 } else if ((tctxt
!= NULL
) && (tctxt
->style
!= NULL
) &&
323 (tctxt
->style
->doc
!= NULL
)) {
324 base
= xmlNodeGetBase(tctxt
->style
->doc
,
325 (xmlNodePtr
) tctxt
->style
->doc
);
328 URI
= xmlBuildURI(obj
->stringval
, base
);
332 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
334 xsltDocumentFunctionLoadDocument( ctxt
, URI
);
338 xmlXPathFreeObject(obj
);
340 xmlXPathFreeObject(obj2
);
345 * @ctxt: the XPath Parser context
346 * @nargs: the number of arguments
348 * Implement the key() XSLT function
349 * node-set key(string, object)
352 xsltKeyFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
353 xmlXPathObjectPtr obj1
, obj2
;
356 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
357 "key() : expects two arguments\n");
358 ctxt
->error
= XPATH_INVALID_ARITY
;
363 * Get the key's value.
365 obj2
= valuePop(ctxt
);
366 xmlXPathStringFunction(ctxt
, 1);
367 if ((obj2
== NULL
) ||
368 (ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_STRING
)) {
369 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
370 "key() : invalid arg expecting a string\n");
371 ctxt
->error
= XPATH_INVALID_TYPE
;
372 xmlXPathFreeObject(obj2
);
377 * Get the key's name.
379 obj1
= valuePop(ctxt
);
381 if ((obj2
->type
== XPATH_NODESET
) || (obj2
->type
== XPATH_XSLT_TREE
)) {
383 xmlXPathObjectPtr newobj
, ret
;
385 ret
= xmlXPathNewNodeSet(NULL
);
387 if (obj2
->nodesetval
!= NULL
) {
388 for (i
= 0; i
< obj2
->nodesetval
->nodeNr
; i
++) {
389 valuePush(ctxt
, xmlXPathObjectCopy(obj1
));
391 xmlXPathNewNodeSet(obj2
->nodesetval
->nodeTab
[i
]));
392 xmlXPathStringFunction(ctxt
, 1);
393 xsltKeyFunction(ctxt
, 2);
394 newobj
= valuePop(ctxt
);
395 ret
->nodesetval
= xmlXPathNodeSetMerge(ret
->nodesetval
,
397 xmlXPathFreeObject(newobj
);
400 valuePush(ctxt
, ret
);
402 xmlNodeSetPtr nodelist
= NULL
;
403 xmlChar
*key
= NULL
, *value
;
404 const xmlChar
*keyURI
;
405 xsltTransformContextPtr tctxt
;
406 xmlChar
*qname
, *prefix
;
407 xmlXPathContextPtr xpctxt
= ctxt
->context
;
408 xmlNodePtr tmpNode
= NULL
;
409 xsltDocumentPtr oldDocInfo
;
411 tctxt
= xsltXPathGetTransformContext(ctxt
);
413 oldDocInfo
= tctxt
->document
;
415 if (xpctxt
->node
== NULL
) {
416 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
417 "Internal error in xsltKeyFunction(): "
418 "The context node is not set on the XPath context.\n");
419 tctxt
->state
= XSLT_STATE_STOPPED
;
423 * Get the associated namespace URI if qualified name
425 qname
= obj1
->stringval
;
426 key
= xmlSplitQName2(qname
, &prefix
);
428 key
= xmlStrdup(obj1
->stringval
);
433 if (prefix
!= NULL
) {
434 keyURI
= xmlXPathNsLookup(xpctxt
, prefix
);
435 if (keyURI
== NULL
) {
436 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
437 "key() : prefix %s is not bound\n", prefix
);
439 * TODO: Shouldn't we stop here?
449 * Force conversion of first arg to string
451 valuePush(ctxt
, obj2
);
452 xmlXPathStringFunction(ctxt
, 1);
453 if ((ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_STRING
)) {
454 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
455 "key() : invalid arg expecting a string\n");
456 ctxt
->error
= XPATH_INVALID_TYPE
;
459 obj2
= valuePop(ctxt
);
460 value
= obj2
->stringval
;
463 * We need to ensure that ctxt->document is available for
465 * First find the relevant doc, which is the context node's
466 * owner doc; using context->doc is not safe, since
467 * the doc could have been acquired via the document() function,
468 * or the doc might be a Result Tree Fragment.
469 * FUTURE INFO: In XSLT 2.0 the key() function takes an additional
470 * argument indicating the doc to use.
472 if (xpctxt
->node
->type
== XML_NAMESPACE_DECL
) {
474 * REVISIT: This is a libxml hack! Check xpath.c for details.
475 * The XPath module sets the owner element of a ns-node on
476 * the ns->next field.
478 if ((((xmlNsPtr
) xpctxt
->node
)->next
!= NULL
) &&
479 (((xmlNsPtr
) xpctxt
->node
)->next
->type
== XML_ELEMENT_NODE
))
481 tmpNode
= (xmlNodePtr
) ((xmlNsPtr
) xpctxt
->node
)->next
;
484 tmpNode
= xpctxt
->node
;
486 if ((tmpNode
== NULL
) || (tmpNode
->doc
== NULL
)) {
487 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
488 "Internal error in xsltKeyFunction(): "
489 "Couldn't get the doc of the XPath context node.\n");
493 if ((tctxt
->document
== NULL
) ||
494 (tctxt
->document
->doc
!= tmpNode
->doc
))
496 if (tmpNode
->doc
->name
&& (tmpNode
->doc
->name
[0] == ' ')) {
498 * This is a Result Tree Fragment.
500 if (tmpNode
->doc
->_private
== NULL
) {
501 tmpNode
->doc
->_private
= xsltNewDocument(tctxt
, tmpNode
->doc
);
502 if (tmpNode
->doc
->_private
== NULL
)
505 tctxt
->document
= (xsltDocumentPtr
) tmpNode
->doc
->_private
;
508 * May be the initial source doc or a doc acquired via the
509 * document() function.
511 tctxt
->document
= xsltFindDocument(tctxt
, tmpNode
->doc
);
513 if (tctxt
->document
== NULL
) {
514 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
515 "Internal error in xsltKeyFunction(): "
516 "Could not get the document info of a context doc.\n");
517 tctxt
->state
= XSLT_STATE_STOPPED
;
522 * Get/compute the key value.
524 nodelist
= xsltGetKey(tctxt
, key
, keyURI
, value
);
527 tctxt
->document
= oldDocInfo
;
528 valuePush(ctxt
, xmlXPathWrapNodeSet(
529 xmlXPathNodeSetMerge(NULL
, nodelist
)));
535 xmlXPathFreeObject(obj1
);
537 xmlXPathFreeObject(obj2
);
541 * xsltUnparsedEntityURIFunction:
542 * @ctxt: the XPath Parser context
543 * @nargs: the number of arguments
545 * Implement the unparsed-entity-uri() XSLT function
546 * string unparsed-entity-uri(string)
549 xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
550 xmlXPathObjectPtr obj
;
553 if ((nargs
!= 1) || (ctxt
->value
== NULL
)) {
554 xsltGenericError(xsltGenericErrorContext
,
555 "unparsed-entity-uri() : expects one string arg\n");
556 ctxt
->error
= XPATH_INVALID_ARITY
;
559 obj
= valuePop(ctxt
);
560 if (obj
->type
!= XPATH_STRING
) {
561 obj
= xmlXPathConvertString(obj
);
564 str
= obj
->stringval
;
566 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
570 entity
= xmlGetDocEntity(ctxt
->context
->doc
, str
);
571 if (entity
== NULL
) {
572 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
574 if (entity
->URI
!= NULL
)
575 valuePush(ctxt
, xmlXPathNewString(entity
->URI
));
577 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
580 xmlXPathFreeObject(obj
);
584 * xsltFormatNumberFunction:
585 * @ctxt: the XPath Parser context
586 * @nargs: the number of arguments
588 * Implement the format-number() XSLT function
589 * string format-number(number, string, string?)
592 xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
594 xmlXPathObjectPtr numberObj
= NULL
;
595 xmlXPathObjectPtr formatObj
= NULL
;
596 xmlXPathObjectPtr decimalObj
= NULL
;
597 xsltStylesheetPtr sheet
;
598 xsltDecimalFormatPtr formatValues
;
600 xsltTransformContextPtr tctxt
;
602 tctxt
= xsltXPathGetTransformContext(ctxt
);
605 sheet
= tctxt
->style
;
608 formatValues
= sheet
->decimalFormat
;
613 decimalObj
= valuePop(ctxt
);
614 formatValues
= xsltDecimalFormatGetByName(sheet
, decimalObj
->stringval
);
615 if (formatValues
== NULL
) {
616 xsltTransformError(tctxt
, NULL
, NULL
,
617 "format-number() : undeclared decimal format '%s'\n",
618 decimalObj
->stringval
);
620 /* Intentional fall-through */
623 formatObj
= valuePop(ctxt
);
625 numberObj
= valuePop(ctxt
);
628 XP_ERROR(XPATH_INVALID_ARITY
);
631 if (formatValues
!= NULL
) {
632 if (xsltFormatNumberConversion(formatValues
,
633 formatObj
->stringval
,
635 &result
) == XPATH_EXPRESSION_OK
) {
636 valuePush(ctxt
, xmlXPathNewString(result
));
641 xmlXPathFreeObject(numberObj
);
642 xmlXPathFreeObject(formatObj
);
643 xmlXPathFreeObject(decimalObj
);
647 * xsltGenerateIdFunction:
648 * @ctxt: the XPath Parser context
649 * @nargs: the number of arguments
651 * Implement the generate-id() XSLT function
652 * string generate-id(node-set?)
655 xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
656 xmlNodePtr cur
= NULL
;
661 cur
= ctxt
->context
->node
;
662 } else if (nargs
== 1) {
663 xmlXPathObjectPtr obj
;
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
];
686 xmlXPathFreeObject(obj
);
688 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
689 "generate-id() : invalid number of args %d\n", nargs
);
690 ctxt
->error
= XPATH_INVALID_ARITY
;
694 * Okay this is ugly but should work, use the NodePtr address
697 val
= (unsigned long)((char *)cur
- (char *)0);
698 val
/= sizeof(xmlNode
);
699 sprintf((char *)str
, "id%ld", val
);
700 valuePush(ctxt
, xmlXPathNewString(str
));
704 * xsltSystemPropertyFunction:
705 * @ctxt: the XPath Parser context
706 * @nargs: the number of arguments
708 * Implement the system-property() XSLT function
709 * object system-property(string)
712 xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
713 xmlXPathObjectPtr obj
;
714 xmlChar
*prefix
, *name
;
715 const xmlChar
*nsURI
= NULL
;
718 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
719 "system-property() : expects one string arg\n");
720 ctxt
->error
= XPATH_INVALID_ARITY
;
723 if ((ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_STRING
)) {
724 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
725 "system-property() : invalid arg expecting a string\n");
726 ctxt
->error
= XPATH_INVALID_TYPE
;
729 obj
= valuePop(ctxt
);
730 if (obj
->stringval
== NULL
) {
731 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
733 name
= xmlSplitQName2(obj
->stringval
, &prefix
);
735 name
= xmlStrdup(obj
->stringval
);
737 nsURI
= xmlXPathNsLookup(ctxt
->context
, prefix
);
739 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
740 "system-property() : prefix %s is not bound\n", prefix
);
744 if (xmlStrEqual(nsURI
, XSLT_NAMESPACE
)) {
745 #ifdef DOCBOOK_XSL_HACK
746 if (xmlStrEqual(name
, (const xmlChar
*)"vendor")) {
747 xsltStylesheetPtr sheet
;
748 xsltTransformContextPtr tctxt
;
750 tctxt
= xsltXPathGetTransformContext(ctxt
);
751 if ((tctxt
!= NULL
) && (tctxt
->inst
!= NULL
) &&
752 (xmlStrEqual(tctxt
->inst
->name
, BAD_CAST
"variable")) &&
753 (tctxt
->inst
->parent
!= NULL
) &&
754 (xmlStrEqual(tctxt
->inst
->parent
->name
,
755 BAD_CAST
"template")))
756 sheet
= tctxt
->style
;
759 if ((sheet
!= NULL
) && (sheet
->doc
!= NULL
) &&
760 (sheet
->doc
->URL
!= NULL
) &&
761 (xmlStrstr(sheet
->doc
->URL
,
762 (const xmlChar
*)"chunk") != NULL
)) {
763 valuePush(ctxt
, xmlXPathNewString(
764 (const xmlChar
*)"libxslt (SAXON 6.2 compatible)"));
767 valuePush(ctxt
, xmlXPathNewString(
768 (const xmlChar
*)XSLT_DEFAULT_VENDOR
));
772 if (xmlStrEqual(name
, (const xmlChar
*)"vendor")) {
773 valuePush(ctxt
, xmlXPathNewString(
774 (const xmlChar
*)XSLT_DEFAULT_VENDOR
));
777 if (xmlStrEqual(name
, (const xmlChar
*)"version")) {
778 valuePush(ctxt
, xmlXPathNewString(
779 (const xmlChar
*)XSLT_DEFAULT_VERSION
));
780 } else if (xmlStrEqual(name
, (const xmlChar
*)"vendor-url")) {
781 valuePush(ctxt
, xmlXPathNewString(
782 (const xmlChar
*)XSLT_DEFAULT_URL
));
784 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
792 xmlXPathFreeObject(obj
);
796 * xsltElementAvailableFunction:
797 * @ctxt: the XPath Parser context
798 * @nargs: the number of arguments
800 * Implement the element-available() XSLT function
801 * boolean element-available(string)
804 xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
805 xmlXPathObjectPtr obj
;
806 xmlChar
*prefix
, *name
;
807 const xmlChar
*nsURI
= NULL
;
808 xsltTransformContextPtr tctxt
;
811 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
812 "element-available() : expects one string arg\n");
813 ctxt
->error
= XPATH_INVALID_ARITY
;
816 xmlXPathStringFunction(ctxt
, 1);
817 if ((ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_STRING
)) {
818 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
819 "element-available() : invalid arg expecting a string\n");
820 ctxt
->error
= XPATH_INVALID_TYPE
;
823 obj
= valuePop(ctxt
);
824 tctxt
= xsltXPathGetTransformContext(ctxt
);
826 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
827 "element-available() : internal error tctxt == NULL\n");
828 xmlXPathFreeObject(obj
);
829 valuePush(ctxt
, xmlXPathNewBoolean(0));
834 name
= xmlSplitQName2(obj
->stringval
, &prefix
);
838 name
= xmlStrdup(obj
->stringval
);
839 ns
= xmlSearchNs(tctxt
->inst
->doc
, tctxt
->inst
, NULL
);
840 if (ns
!= NULL
) nsURI
= xmlStrdup(ns
->href
);
842 nsURI
= xmlXPathNsLookup(ctxt
->context
, prefix
);
844 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
845 "element-available() : prefix %s is not bound\n", prefix
);
849 if (xsltExtElementLookup(tctxt
, name
, nsURI
) != NULL
) {
850 valuePush(ctxt
, xmlXPathNewBoolean(1));
852 valuePush(ctxt
, xmlXPathNewBoolean(0));
855 xmlXPathFreeObject(obj
);
863 * xsltFunctionAvailableFunction:
864 * @ctxt: the XPath Parser context
865 * @nargs: the number of arguments
867 * Implement the function-available() XSLT function
868 * boolean function-available(string)
871 xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
872 xmlXPathObjectPtr obj
;
873 xmlChar
*prefix
, *name
;
874 const xmlChar
*nsURI
= NULL
;
877 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
878 "function-available() : expects one string arg\n");
879 ctxt
->error
= XPATH_INVALID_ARITY
;
882 xmlXPathStringFunction(ctxt
, 1);
883 if ((ctxt
->value
== NULL
) || (ctxt
->value
->type
!= XPATH_STRING
)) {
884 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
885 "function-available() : invalid arg expecting a string\n");
886 ctxt
->error
= XPATH_INVALID_TYPE
;
889 obj
= valuePop(ctxt
);
891 name
= xmlSplitQName2(obj
->stringval
, &prefix
);
893 name
= xmlStrdup(obj
->stringval
);
895 nsURI
= xmlXPathNsLookup(ctxt
->context
, prefix
);
897 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
898 "function-available() : prefix %s is not bound\n", prefix
);
902 if (xmlXPathFunctionLookupNS(ctxt
->context
, name
, nsURI
) != NULL
) {
903 valuePush(ctxt
, xmlXPathNewBoolean(1));
905 valuePush(ctxt
, xmlXPathNewBoolean(0));
908 xmlXPathFreeObject(obj
);
916 * xsltCurrentFunction:
917 * @ctxt: the XPath Parser context
918 * @nargs: the number of arguments
920 * Implement the current() XSLT function
924 xsltCurrentFunction(xmlXPathParserContextPtr ctxt
, int nargs
){
925 xsltTransformContextPtr tctxt
;
928 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
929 "current() : function uses no argument\n");
930 ctxt
->error
= XPATH_INVALID_ARITY
;
933 tctxt
= xsltXPathGetTransformContext(ctxt
);
935 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
936 "current() : internal error tctxt == NULL\n");
937 valuePush(ctxt
, xmlXPathNewNodeSet(NULL
));
939 valuePush(ctxt
, xmlXPathNewNodeSet(tctxt
->node
)); /* current */
943 /************************************************************************
945 * Registration of XSLT and libxslt functions *
947 ************************************************************************/
950 * xsltRegisterAllFunctions:
951 * @ctxt: the XPath context
953 * Registers all default XSLT functions in this context
956 xsltRegisterAllFunctions(xmlXPathContextPtr ctxt
)
958 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "current",
959 xsltCurrentFunction
);
960 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "document",
961 xsltDocumentFunction
);
962 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "key", xsltKeyFunction
);
963 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "unparsed-entity-uri",
964 xsltUnparsedEntityURIFunction
);
965 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "format-number",
966 xsltFormatNumberFunction
);
967 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "generate-id",
968 xsltGenerateIdFunction
);
969 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "system-property",
970 xsltSystemPropertyFunction
);
971 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "element-available",
972 xsltElementAvailableFunction
);
973 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*) "function-available",
974 xsltFunctionAvailableFunction
);