dmime: The soft synth doesn't supports sharing the channel groups.
[wine.git] / libs / xslt / libxslt / xsltutils.c
blob4717c0e8548a94ec52914ac5ef2cd884ba04474a
1 /*
2 * xsltutils.c: Utilities for the XSL Transformation 1.0 engine
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
9 * daniel@veillard.com
12 #define IN_LIBXSLT
13 #include "libxslt.h"
15 #ifndef XSLT_NEED_TRIO
16 #include <stdio.h>
17 #else
18 #include <trio.h>
19 #endif
21 #include <string.h>
22 #include <time.h>
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #include <stdarg.h>
34 #include <libxml/xmlmemory.h>
35 #include <libxml/tree.h>
36 #include <libxml/HTMLtree.h>
37 #include <libxml/xmlerror.h>
38 #include <libxml/xmlIO.h>
39 #include "xsltutils.h"
40 #include "templates.h"
41 #include "xsltInternals.h"
42 #include "imports.h"
43 #include "transform.h"
45 #if defined(_WIN32) && !defined(__CYGWIN__)
46 #define XSLT_WIN32_PERFORMANCE_COUNTER
47 #endif
49 /************************************************************************
50 * *
51 * Convenience function *
52 * *
53 ************************************************************************/
55 /**
56 * xsltGetCNsProp:
57 * @style: the stylesheet
58 * @node: the node
59 * @name: the attribute name
60 * @nameSpace: the URI of the namespace
62 * Similar to xmlGetNsProp() but with a slightly different semantic
64 * Search and get the value of an attribute associated to a node
65 * This attribute has to be anchored in the namespace specified,
66 * or has no namespace and the element is in that namespace.
68 * This does the entity substitution.
69 * This function looks in DTD attribute declaration for #FIXED or
70 * default declaration values unless DTD use has been turned off.
72 * Returns the attribute value or NULL if not found. The string is allocated
73 * in the stylesheet dictionary.
75 const xmlChar *
76 xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,
77 const xmlChar *name, const xmlChar *nameSpace) {
78 xmlAttrPtr prop;
79 xmlDocPtr doc;
80 xmlNsPtr ns;
81 xmlChar *tmp;
82 const xmlChar *ret;
84 if ((node == NULL) || (style == NULL) || (style->dict == NULL))
85 return(NULL);
87 if (nameSpace == NULL)
88 return xmlGetProp(node, name);
90 if (node->type == XML_NAMESPACE_DECL)
91 return(NULL);
92 if (node->type == XML_ELEMENT_NODE)
93 prop = node->properties;
94 else
95 prop = NULL;
96 while (prop != NULL) {
98 * One need to have
99 * - same attribute names
100 * - and the attribute carrying that namespace
102 if ((xmlStrEqual(prop->name, name)) &&
103 (((prop->ns == NULL) && (node->ns != NULL) &&
104 (xmlStrEqual(node->ns->href, nameSpace))) ||
105 ((prop->ns != NULL) &&
106 (xmlStrEqual(prop->ns->href, nameSpace))))) {
108 tmp = xmlNodeListGetString(node->doc, prop->children, 1);
109 if (tmp == NULL)
110 ret = xmlDictLookup(style->dict, BAD_CAST "", 0);
111 else {
112 ret = xmlDictLookup(style->dict, tmp, -1);
113 xmlFree(tmp);
115 return ret;
117 prop = prop->next;
119 tmp = NULL;
121 * Check if there is a default declaration in the internal
122 * or external subsets
124 doc = node->doc;
125 if (doc != NULL) {
126 if (doc->intSubset != NULL) {
127 xmlAttributePtr attrDecl;
129 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
130 if ((attrDecl == NULL) && (doc->extSubset != NULL))
131 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
133 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
135 * The DTD declaration only allows a prefix search
137 ns = xmlSearchNs(doc, node, attrDecl->prefix);
138 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
139 return(xmlDictLookup(style->dict,
140 attrDecl->defaultValue, -1));
144 return(NULL);
147 * xsltGetNsProp:
148 * @node: the node
149 * @name: the attribute name
150 * @nameSpace: the URI of the namespace
152 * Similar to xmlGetNsProp() but with a slightly different semantic
154 * Search and get the value of an attribute associated to a node
155 * This attribute has to be anchored in the namespace specified,
156 * or has no namespace and the element is in that namespace.
158 * This does the entity substitution.
159 * This function looks in DTD attribute declaration for #FIXED or
160 * default declaration values unless DTD use has been turned off.
162 * Returns the attribute value or NULL if not found.
163 * It's up to the caller to free the memory.
165 xmlChar *
166 xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
167 xmlAttrPtr prop;
168 xmlDocPtr doc;
169 xmlNsPtr ns;
171 if (node == NULL)
172 return(NULL);
174 if (nameSpace == NULL)
175 return xmlGetProp(node, name);
177 if (node->type == XML_NAMESPACE_DECL)
178 return(NULL);
179 if (node->type == XML_ELEMENT_NODE)
180 prop = node->properties;
181 else
182 prop = NULL;
184 * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former
185 * is not namespace-aware and will return an attribute with equal
186 * name regardless of its namespace.
187 * Example:
188 * <xsl:element foo:name="myName"/>
189 * So this would return "myName" even if an attribute @name
190 * in the XSLT was requested.
192 while (prop != NULL) {
194 * One need to have
195 * - same attribute names
196 * - and the attribute carrying that namespace
198 if ((xmlStrEqual(prop->name, name)) &&
199 (((prop->ns == NULL) && (node->ns != NULL) &&
200 (xmlStrEqual(node->ns->href, nameSpace))) ||
201 ((prop->ns != NULL) &&
202 (xmlStrEqual(prop->ns->href, nameSpace))))) {
203 xmlChar *ret;
205 ret = xmlNodeListGetString(node->doc, prop->children, 1);
206 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
207 return(ret);
209 prop = prop->next;
213 * Check if there is a default declaration in the internal
214 * or external subsets
216 doc = node->doc;
217 if (doc != NULL) {
218 if (doc->intSubset != NULL) {
219 xmlAttributePtr attrDecl;
221 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
222 if ((attrDecl == NULL) && (doc->extSubset != NULL))
223 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
225 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
227 * The DTD declaration only allows a prefix search
229 ns = xmlSearchNs(doc, node, attrDecl->prefix);
230 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
231 return(xmlStrdup(attrDecl->defaultValue));
235 return(NULL);
239 * xsltGetUTF8Char:
240 * @utf: a sequence of UTF-8 encoded bytes
241 * @len: a pointer to @bytes len
243 * Read one UTF8 Char from @utf
244 * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately
245 * and use the original API
247 * Returns the char value or -1 in case of error and update @len with the
248 * number of bytes used
251 xsltGetUTF8Char(const unsigned char *utf, int *len) {
252 unsigned int c;
254 if (utf == NULL)
255 goto error;
256 if (len == NULL)
257 goto error;
258 if (*len < 1)
259 goto error;
261 c = utf[0];
262 if (c & 0x80) {
263 if (*len < 2)
264 goto error;
265 if ((utf[1] & 0xc0) != 0x80)
266 goto error;
267 if ((c & 0xe0) == 0xe0) {
268 if (*len < 3)
269 goto error;
270 if ((utf[2] & 0xc0) != 0x80)
271 goto error;
272 if ((c & 0xf0) == 0xf0) {
273 if (*len < 4)
274 goto error;
275 if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
276 goto error;
277 *len = 4;
278 /* 4-byte code */
279 c = (utf[0] & 0x7) << 18;
280 c |= (utf[1] & 0x3f) << 12;
281 c |= (utf[2] & 0x3f) << 6;
282 c |= utf[3] & 0x3f;
283 } else {
284 /* 3-byte code */
285 *len = 3;
286 c = (utf[0] & 0xf) << 12;
287 c |= (utf[1] & 0x3f) << 6;
288 c |= utf[2] & 0x3f;
290 } else {
291 /* 2-byte code */
292 *len = 2;
293 c = (utf[0] & 0x1f) << 6;
294 c |= utf[1] & 0x3f;
296 } else {
297 /* 1-byte code */
298 *len = 1;
300 return(c);
302 error:
303 if (len != NULL)
304 *len = 0;
305 return(-1);
308 #ifdef XSLT_REFACTORED
311 * xsltPointerListAddSize:
312 * @list: the pointer list structure
313 * @item: the item to be stored
314 * @initialSize: the initial size of the list
316 * Adds an item to the list.
318 * Returns the position of the added item in the list or
319 * -1 in case of an error.
322 xsltPointerListAddSize(xsltPointerListPtr list,
323 void *item,
324 int initialSize)
326 if (list->items == NULL) {
327 if (initialSize <= 0)
328 initialSize = 1;
329 list->items = (void **) xmlMalloc(
330 initialSize * sizeof(void *));
331 if (list->items == NULL) {
332 xsltGenericError(xsltGenericErrorContext,
333 "xsltPointerListAddSize: memory allocation failure.\n");
334 return(-1);
336 list->number = 0;
337 list->size = initialSize;
338 } else if (list->size <= list->number) {
339 list->size *= 2;
340 list->items = (void **) xmlRealloc(list->items,
341 list->size * sizeof(void *));
342 if (list->items == NULL) {
343 xsltGenericError(xsltGenericErrorContext,
344 "xsltPointerListAddSize: memory re-allocation failure.\n");
345 list->size = 0;
346 return(-1);
349 list->items[list->number++] = item;
350 return(0);
354 * xsltPointerListCreate:
355 * @initialSize: the initial size for the list
357 * Creates an xsltPointerList structure.
359 * Returns a xsltPointerList structure or NULL in case of an error.
361 xsltPointerListPtr
362 xsltPointerListCreate(int initialSize)
364 xsltPointerListPtr ret;
366 ret = xmlMalloc(sizeof(xsltPointerList));
367 if (ret == NULL) {
368 xsltGenericError(xsltGenericErrorContext,
369 "xsltPointerListCreate: memory allocation failure.\n");
370 return (NULL);
372 memset(ret, 0, sizeof(xsltPointerList));
373 if (initialSize > 0) {
374 xsltPointerListAddSize(ret, NULL, initialSize);
375 ret->number = 0;
377 return (ret);
381 * xsltPointerListFree:
382 * @list: pointer to the list to be freed
384 * Frees the xsltPointerList structure. This does not free
385 * the content of the list.
387 void
388 xsltPointerListFree(xsltPointerListPtr list)
390 if (list == NULL)
391 return;
392 if (list->items != NULL)
393 xmlFree(list->items);
394 xmlFree(list);
398 * xsltPointerListClear:
399 * @list: pointer to the list to be cleared
401 * Resets the list, but does not free the allocated array
402 * and does not free the content of the list.
404 void
405 xsltPointerListClear(xsltPointerListPtr list)
407 if (list->items != NULL) {
408 xmlFree(list->items);
409 list->items = NULL;
411 list->number = 0;
412 list->size = 0;
415 #endif /* XSLT_REFACTORED */
417 /************************************************************************
419 * Handling of XSLT stylesheets messages *
421 ************************************************************************/
424 * xsltMessage:
425 * @ctxt: an XSLT processing context
426 * @node: The current node
427 * @inst: The node containing the message instruction
429 * Process and xsl:message construct
431 void
432 xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
433 xmlGenericErrorFunc error = xsltGenericError;
434 void *errctx = xsltGenericErrorContext;
435 xmlChar *prop, *message;
436 int terminate = 0;
438 if ((ctxt == NULL) || (inst == NULL))
439 return;
441 if (ctxt->error != NULL) {
442 error = ctxt->error;
443 errctx = ctxt->errctx;
446 prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);
447 if (prop != NULL) {
448 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
449 terminate = 1;
450 } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
451 terminate = 0;
452 } else {
453 xsltTransformError(ctxt, NULL, inst,
454 "xsl:message : terminate expecting 'yes' or 'no'\n");
456 xmlFree(prop);
458 message = xsltEvalTemplateString(ctxt, node, inst);
459 if (message != NULL) {
460 int len = xmlStrlen(message);
462 error(errctx, "%s", (const char *)message);
463 if ((len > 0) && (message[len - 1] != '\n'))
464 error(errctx, "\n");
465 xmlFree(message);
467 if (terminate)
468 ctxt->state = XSLT_STATE_STOPPED;
471 /************************************************************************
473 * Handling of out of context errors *
475 ************************************************************************/
477 #define XSLT_GET_VAR_STR(msg, str) { \
478 int size; \
479 int chars; \
480 char *larger; \
481 va_list ap; \
483 str = (char *) xmlMalloc(150); \
484 if (str == NULL) \
485 return; \
487 size = 150; \
489 while (size < 64000) { \
490 va_start(ap, msg); \
491 chars = vsnprintf(str, size, msg, ap); \
492 va_end(ap); \
493 if ((chars > -1) && (chars < size)) \
494 break; \
495 if (chars > -1) \
496 size += chars + 1; \
497 else \
498 size += 100; \
499 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
500 xmlFree(str); \
501 return; \
503 str = larger; \
507 * xsltGenericErrorDefaultFunc:
508 * @ctx: an error context
509 * @msg: the message to display/transmit
510 * @...: extra parameters for the message display
512 * Default handler for out of context error messages.
514 static void WINAPIV LIBXSLT_ATTR_FORMAT(2,3)
515 xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
516 va_list args;
518 if (xsltGenericErrorContext == NULL)
519 xsltGenericErrorContext = (void *) stderr;
521 va_start(args, msg);
522 vfprintf((FILE *)xsltGenericErrorContext, msg, args);
523 va_end(args);
526 xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
527 void *xsltGenericErrorContext = NULL;
531 * xsltSetGenericErrorFunc:
532 * @ctx: the new error handling context
533 * @handler: the new handler function
535 * Function to reset the handler and the error context for out of
536 * context error messages.
537 * This simply means that @handler will be called for subsequent
538 * error messages while not parsing nor validating. And @ctx will
539 * be passed as first argument to @handler
540 * One can simply force messages to be emitted to another FILE * than
541 * stderr by setting @ctx to this file handle and @handler to NULL.
543 void
544 xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
545 xsltGenericErrorContext = ctx;
546 if (handler != NULL)
547 xsltGenericError = handler;
548 else
549 xsltGenericError = xsltGenericErrorDefaultFunc;
553 * xsltGenericDebugDefaultFunc:
554 * @ctx: an error context
555 * @msg: the message to display/transmit
556 * @...: extra parameters for the message display
558 * Default handler for out of context error messages.
560 static void WINAPIV LIBXSLT_ATTR_FORMAT(2,3)
561 xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
562 va_list args;
564 if (xsltGenericDebugContext == NULL)
565 return;
567 va_start(args, msg);
568 vfprintf((FILE *)xsltGenericDebugContext, msg, args);
569 va_end(args);
572 xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
573 void *xsltGenericDebugContext = NULL;
577 * xsltSetGenericDebugFunc:
578 * @ctx: the new error handling context
579 * @handler: the new handler function
581 * Function to reset the handler and the error context for out of
582 * context error messages.
583 * This simply means that @handler will be called for subsequent
584 * error messages while not parsing or validating. And @ctx will
585 * be passed as first argument to @handler
586 * One can simply force messages to be emitted to another FILE * than
587 * stderr by setting @ctx to this file handle and @handler to NULL.
589 void
590 xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
591 xsltGenericDebugContext = ctx;
592 if (handler != NULL)
593 xsltGenericDebug = handler;
594 else
595 xsltGenericDebug = xsltGenericDebugDefaultFunc;
599 * xsltPrintErrorContext:
600 * @ctxt: the transformation context
601 * @style: the stylesheet
602 * @node: the current node being processed
604 * Display the context of an error.
606 void
607 xsltPrintErrorContext(xsltTransformContextPtr ctxt,
608 xsltStylesheetPtr style, xmlNodePtr node) {
609 int line = 0;
610 const xmlChar *file = NULL;
611 const xmlChar *name = NULL;
612 const char *type = "error";
613 xmlGenericErrorFunc error = xsltGenericError;
614 void *errctx = xsltGenericErrorContext;
616 if (ctxt != NULL) {
617 if (ctxt->state == XSLT_STATE_OK)
618 ctxt->state = XSLT_STATE_ERROR;
619 if (ctxt->error != NULL) {
620 error = ctxt->error;
621 errctx = ctxt->errctx;
624 if ((node == NULL) && (ctxt != NULL))
625 node = ctxt->inst;
627 if (node != NULL) {
628 if ((node->type == XML_DOCUMENT_NODE) ||
629 (node->type == XML_HTML_DOCUMENT_NODE)) {
630 xmlDocPtr doc = (xmlDocPtr) node;
632 file = doc->URL;
633 } else {
634 line = xmlGetLineNo(node);
635 if ((node->doc != NULL) && (node->doc->URL != NULL))
636 file = node->doc->URL;
637 if (node->name != NULL)
638 name = node->name;
642 if (ctxt != NULL)
643 type = "runtime error";
644 else if (style != NULL) {
645 #ifdef XSLT_REFACTORED
646 if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)
647 type = "compilation warning";
648 else
649 type = "compilation error";
650 #else
651 type = "compilation error";
652 #endif
655 if ((file != NULL) && (line != 0) && (name != NULL))
656 error(errctx, "%s: file %s line %d element %s\n",
657 type, file, line, name);
658 else if ((file != NULL) && (name != NULL))
659 error(errctx, "%s: file %s element %s\n", type, file, name);
660 else if ((file != NULL) && (line != 0))
661 error(errctx, "%s: file %s line %d\n", type, file, line);
662 else if (file != NULL)
663 error(errctx, "%s: file %s\n", type, file);
664 else if (name != NULL)
665 error(errctx, "%s: element %s\n", type, name);
666 else
667 error(errctx, "%s\n", type);
671 * xsltSetTransformErrorFunc:
672 * @ctxt: the XSLT transformation context
673 * @ctx: the new error handling context
674 * @handler: the new handler function
676 * Function to reset the handler and the error context for out of
677 * context error messages specific to a given XSLT transromation.
679 * This simply means that @handler will be called for subsequent
680 * error messages while running the transformation.
682 void
683 xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,
684 void *ctx, xmlGenericErrorFunc handler)
686 ctxt->error = handler;
687 ctxt->errctx = ctx;
691 * xsltTransformError:
692 * @ctxt: an XSLT transformation context
693 * @style: the XSLT stylesheet used
694 * @node: the current node in the stylesheet
695 * @msg: the message to display/transmit
696 * @...: extra parameters for the message display
698 * Display and format an error messages, gives file, line, position and
699 * extra parameters, will use the specific transformation context if available
701 void WINAPIV
702 xsltTransformError(xsltTransformContextPtr ctxt,
703 xsltStylesheetPtr style,
704 xmlNodePtr node,
705 const char *msg, ...) {
706 xmlGenericErrorFunc error = xsltGenericError;
707 void *errctx = xsltGenericErrorContext;
708 char * str;
710 if (ctxt != NULL) {
711 if (ctxt->state == XSLT_STATE_OK)
712 ctxt->state = XSLT_STATE_ERROR;
713 if (ctxt->error != NULL) {
714 error = ctxt->error;
715 errctx = ctxt->errctx;
718 if ((node == NULL) && (ctxt != NULL))
719 node = ctxt->inst;
720 xsltPrintErrorContext(ctxt, style, node);
721 XSLT_GET_VAR_STR(msg, str);
722 error(errctx, "%s", str);
723 if (str != NULL)
724 xmlFree(str);
727 /************************************************************************
729 * QNames *
731 ************************************************************************/
734 * xsltSplitQName:
735 * @dict: a dictionary
736 * @name: the full QName
737 * @prefix: the return value
739 * Split QNames into prefix and local names, both allocated from a dictionary.
741 * Returns: the localname or NULL in case of error.
743 const xmlChar *
744 xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {
745 int len = 0;
746 const xmlChar *ret = NULL;
748 *prefix = NULL;
749 if ((name == NULL) || (dict == NULL)) return(NULL);
750 if (name[0] == ':')
751 return(xmlDictLookup(dict, name, -1));
752 while ((name[len] != 0) && (name[len] != ':')) len++;
753 if (name[len] == 0) return(xmlDictLookup(dict, name, -1));
754 *prefix = xmlDictLookup(dict, name, len);
755 ret = xmlDictLookup(dict, &name[len + 1], -1);
756 return(ret);
760 * xsltGetQNameURI:
761 * @node: the node holding the QName
762 * @name: pointer to the initial QName value
764 * This function analyzes @name, if the name contains a prefix,
765 * the function seaches the associated namespace in scope for it.
766 * It will also replace @name value with the NCName, the old value being
767 * freed.
768 * Errors in the prefix lookup are signalled by setting @name to NULL.
770 * NOTE: the namespace returned is a pointer to the place where it is
771 * defined and hence has the same lifespan as the document holding it.
773 * Returns the namespace URI if there is a prefix, or NULL if @name is
774 * not prefixed.
776 const xmlChar *
777 xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)
779 int len = 0;
780 xmlChar *qname;
781 xmlNsPtr ns;
783 if (name == NULL)
784 return(NULL);
785 qname = *name;
786 if ((qname == NULL) || (*qname == 0))
787 return(NULL);
788 if (node == NULL) {
789 xsltGenericError(xsltGenericErrorContext,
790 "QName: no element for namespace lookup %s\n",
791 qname);
792 xmlFree(qname);
793 *name = NULL;
794 return(NULL);
797 /* nasty but valid */
798 if (qname[0] == ':')
799 return(NULL);
802 * we are not trying to validate but just to cut, and yes it will
803 * work even if this is a set of UTF-8 encoded chars
805 while ((qname[len] != 0) && (qname[len] != ':'))
806 len++;
808 if (qname[len] == 0)
809 return(NULL);
812 * handle xml: separately, this one is magical
814 if ((qname[0] == 'x') && (qname[1] == 'm') &&
815 (qname[2] == 'l') && (qname[3] == ':')) {
816 if (qname[4] == 0)
817 return(NULL);
818 *name = xmlStrdup(&qname[4]);
819 xmlFree(qname);
820 return(XML_XML_NAMESPACE);
823 qname[len] = 0;
824 ns = xmlSearchNs(node->doc, node, qname);
825 if (ns == NULL) {
826 xsltGenericError(xsltGenericErrorContext,
827 "%s:%s : no namespace bound to prefix %s\n",
828 qname, &qname[len + 1], qname);
829 *name = NULL;
830 xmlFree(qname);
831 return(NULL);
833 *name = xmlStrdup(&qname[len + 1]);
834 xmlFree(qname);
835 return(ns->href);
839 * xsltGetQNameURI2:
840 * @style: stylesheet pointer
841 * @node: the node holding the QName
842 * @name: pointer to the initial QName value
844 * This function is similar to xsltGetQNameURI, but is used when
845 * @name is a dictionary entry.
847 * Returns the namespace URI if there is a prefix, or NULL if @name is
848 * not prefixed.
850 const xmlChar *
851 xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
852 const xmlChar **name) {
853 int len = 0;
854 xmlChar *qname;
855 xmlNsPtr ns;
857 if (name == NULL)
858 return(NULL);
859 qname = (xmlChar *)*name;
860 if ((qname == NULL) || (*qname == 0))
861 return(NULL);
862 if (node == NULL) {
863 xsltGenericError(xsltGenericErrorContext,
864 "QName: no element for namespace lookup %s\n",
865 qname);
866 *name = NULL;
867 return(NULL);
871 * we are not trying to validate but just to cut, and yes it will
872 * work even if this is a set of UTF-8 encoded chars
874 while ((qname[len] != 0) && (qname[len] != ':'))
875 len++;
877 if (qname[len] == 0)
878 return(NULL);
881 * handle xml: separately, this one is magical
883 if ((qname[0] == 'x') && (qname[1] == 'm') &&
884 (qname[2] == 'l') && (qname[3] == ':')) {
885 if (qname[4] == 0)
886 return(NULL);
887 *name = xmlDictLookup(style->dict, &qname[4], -1);
888 return(XML_XML_NAMESPACE);
891 qname = xmlStrndup(*name, len);
892 ns = xmlSearchNs(node->doc, node, qname);
893 if (ns == NULL) {
894 if (style) {
895 xsltTransformError(NULL, style, node,
896 "No namespace bound to prefix '%s'.\n",
897 qname);
898 style->errors++;
899 } else {
900 xsltGenericError(xsltGenericErrorContext,
901 "%s : no namespace bound to prefix %s\n",
902 *name, qname);
904 *name = NULL;
905 xmlFree(qname);
906 return(NULL);
908 *name = xmlDictLookup(style->dict, (*name)+len+1, -1);
909 xmlFree(qname);
910 return(ns->href);
913 /************************************************************************
915 * Sorting *
917 ************************************************************************/
920 * xsltDocumentSortFunction:
921 * @list: the node set
923 * reorder the current node list @list accordingly to the document order
924 * This function is slow, obsolete and should not be used anymore.
926 void
927 xsltDocumentSortFunction(xmlNodeSetPtr list) {
928 int i, j;
929 int len, tst;
930 xmlNodePtr node;
932 if (list == NULL)
933 return;
934 len = list->nodeNr;
935 if (len <= 1)
936 return;
937 /* TODO: sort is really not optimized, does it needs to ? */
938 for (i = 0;i < len -1;i++) {
939 for (j = i + 1; j < len; j++) {
940 tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
941 if (tst == -1) {
942 node = list->nodeTab[i];
943 list->nodeTab[i] = list->nodeTab[j];
944 list->nodeTab[j] = node;
951 * xsltComputeSortResult:
952 * @ctxt: a XSLT process context
953 * @sort: node list
955 * reorder the current node list accordingly to the set of sorting
956 * requirement provided by the array of nodes.
958 * Returns a ordered XPath nodeset or NULL in case of error.
960 xmlXPathObjectPtr *
961 xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
962 #ifdef XSLT_REFACTORED
963 xsltStyleItemSortPtr comp;
964 #else
965 xsltStylePreCompPtr comp;
966 #endif
967 xmlXPathObjectPtr *results = NULL;
968 xmlNodeSetPtr list = NULL;
969 xmlXPathObjectPtr res;
970 int len = 0;
971 int i;
972 xmlNodePtr oldNode;
973 xmlNodePtr oldInst;
974 int oldPos, oldSize ;
975 int oldNsNr;
976 xmlNsPtr *oldNamespaces;
978 comp = sort->psvi;
979 if (comp == NULL) {
980 xsltGenericError(xsltGenericErrorContext,
981 "xsl:sort : compilation failed\n");
982 return(NULL);
985 if ((comp->select == NULL) || (comp->comp == NULL))
986 return(NULL);
988 list = ctxt->nodeList;
989 if ((list == NULL) || (list->nodeNr <= 1))
990 return(NULL);
992 len = list->nodeNr;
994 /* TODO: xsl:sort lang attribute */
995 /* TODO: xsl:sort case-order attribute */
998 results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
999 if (results == NULL) {
1000 xsltGenericError(xsltGenericErrorContext,
1001 "xsltComputeSortResult: memory allocation failure\n");
1002 return(NULL);
1005 oldNode = ctxt->node;
1006 oldInst = ctxt->inst;
1007 oldPos = ctxt->xpathCtxt->proximityPosition;
1008 oldSize = ctxt->xpathCtxt->contextSize;
1009 oldNsNr = ctxt->xpathCtxt->nsNr;
1010 oldNamespaces = ctxt->xpathCtxt->namespaces;
1011 for (i = 0;i < len;i++) {
1012 ctxt->inst = sort;
1013 ctxt->xpathCtxt->contextSize = len;
1014 ctxt->xpathCtxt->proximityPosition = i + 1;
1015 ctxt->node = list->nodeTab[i];
1016 ctxt->xpathCtxt->node = ctxt->node;
1017 #ifdef XSLT_REFACTORED
1018 if (comp->inScopeNs != NULL) {
1019 ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
1020 ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
1021 } else {
1022 ctxt->xpathCtxt->namespaces = NULL;
1023 ctxt->xpathCtxt->nsNr = 0;
1025 #else
1026 ctxt->xpathCtxt->namespaces = comp->nsList;
1027 ctxt->xpathCtxt->nsNr = comp->nsNr;
1028 #endif
1029 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
1030 if (res != NULL) {
1031 if (res->type != XPATH_STRING)
1032 res = xmlXPathConvertString(res);
1033 if (comp->number)
1034 res = xmlXPathConvertNumber(res);
1035 res->index = i; /* Save original pos for dupl resolv */
1036 if (comp->number) {
1037 if (res->type == XPATH_NUMBER) {
1038 results[i] = res;
1039 } else {
1040 #ifdef WITH_XSLT_DEBUG_PROCESS
1041 xsltGenericDebug(xsltGenericDebugContext,
1042 "xsltComputeSortResult: select didn't evaluate to a number\n");
1043 #endif
1044 results[i] = NULL;
1046 } else {
1047 if (res->type == XPATH_STRING) {
1048 if (comp->locale != (xsltLocale)0) {
1049 xmlChar *str = res->stringval;
1050 res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, str);
1051 xmlFree(str);
1054 results[i] = res;
1055 } else {
1056 #ifdef WITH_XSLT_DEBUG_PROCESS
1057 xsltGenericDebug(xsltGenericDebugContext,
1058 "xsltComputeSortResult: select didn't evaluate to a string\n");
1059 #endif
1060 results[i] = NULL;
1063 } else {
1064 ctxt->state = XSLT_STATE_STOPPED;
1065 results[i] = NULL;
1068 ctxt->node = oldNode;
1069 ctxt->inst = oldInst;
1070 ctxt->xpathCtxt->contextSize = oldSize;
1071 ctxt->xpathCtxt->proximityPosition = oldPos;
1072 ctxt->xpathCtxt->nsNr = oldNsNr;
1073 ctxt->xpathCtxt->namespaces = oldNamespaces;
1075 return(results);
1079 * xsltDefaultSortFunction:
1080 * @ctxt: a XSLT process context
1081 * @sorts: array of sort nodes
1082 * @nbsorts: the number of sorts in the array
1084 * reorder the current node list accordingly to the set of sorting
1085 * requirement provided by the arry of nodes.
1087 void
1088 xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
1089 int nbsorts) {
1090 #ifdef XSLT_REFACTORED
1091 xsltStyleItemSortPtr comp;
1092 #else
1093 xsltStylePreCompPtr comp;
1094 #endif
1095 xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
1096 xmlXPathObjectPtr *results = NULL, *res;
1097 xmlNodeSetPtr list = NULL;
1098 int descending, number, desc, numb;
1099 int len = 0;
1100 int i, j, incr;
1101 int tst;
1102 int depth;
1103 xmlNodePtr node;
1104 xmlXPathObjectPtr tmp;
1105 int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
1107 if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
1108 (nbsorts >= XSLT_MAX_SORT))
1109 return;
1110 if (sorts[0] == NULL)
1111 return;
1112 comp = sorts[0]->psvi;
1113 if (comp == NULL)
1114 return;
1116 list = ctxt->nodeList;
1117 if ((list == NULL) || (list->nodeNr <= 1))
1118 return; /* nothing to do */
1120 for (j = 0; j < nbsorts; j++) {
1121 comp = sorts[j]->psvi;
1122 tempstype[j] = 0;
1123 if ((comp->stype == NULL) && (comp->has_stype != 0)) {
1124 comp->stype =
1125 xsltEvalAttrValueTemplate(ctxt, sorts[j],
1126 (const xmlChar *) "data-type",
1127 XSLT_NAMESPACE);
1128 if (comp->stype != NULL) {
1129 tempstype[j] = 1;
1130 if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
1131 comp->number = 0;
1132 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
1133 comp->number = 1;
1134 else {
1135 xsltTransformError(ctxt, NULL, sorts[j],
1136 "xsltDoSortFunction: no support for data-type = %s\n",
1137 comp->stype);
1138 comp->number = 0; /* use default */
1142 temporder[j] = 0;
1143 if ((comp->order == NULL) && (comp->has_order != 0)) {
1144 comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
1145 (const xmlChar *) "order",
1146 XSLT_NAMESPACE);
1147 if (comp->order != NULL) {
1148 temporder[j] = 1;
1149 if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
1150 comp->descending = 0;
1151 else if (xmlStrEqual(comp->order,
1152 (const xmlChar *) "descending"))
1153 comp->descending = 1;
1154 else {
1155 xsltTransformError(ctxt, NULL, sorts[j],
1156 "xsltDoSortFunction: invalid value %s for order\n",
1157 comp->order);
1158 comp->descending = 0; /* use default */
1164 len = list->nodeNr;
1166 resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
1167 for (i = 1;i < XSLT_MAX_SORT;i++)
1168 resultsTab[i] = NULL;
1170 results = resultsTab[0];
1172 comp = sorts[0]->psvi;
1173 descending = comp->descending;
1174 number = comp->number;
1175 if (results == NULL)
1176 return;
1178 /* Shell's sort of node-set */
1179 for (incr = len / 2; incr > 0; incr /= 2) {
1180 for (i = incr; i < len; i++) {
1181 j = i - incr;
1182 if (results[i] == NULL)
1183 continue;
1185 while (j >= 0) {
1186 if (results[j] == NULL)
1187 tst = 1;
1188 else {
1189 if (number) {
1190 /* We make NaN smaller than number in accordance
1191 with XSLT spec */
1192 if (xmlXPathIsNaN(results[j]->floatval)) {
1193 if (xmlXPathIsNaN(results[j + incr]->floatval))
1194 tst = 0;
1195 else
1196 tst = -1;
1197 } else if (xmlXPathIsNaN(results[j + incr]->floatval))
1198 tst = 1;
1199 else if (results[j]->floatval ==
1200 results[j + incr]->floatval)
1201 tst = 0;
1202 else if (results[j]->floatval >
1203 results[j + incr]->floatval)
1204 tst = 1;
1205 else tst = -1;
1206 } else if(comp->locale != (xsltLocale)0) {
1207 tst = xsltLocaleStrcmp(
1208 comp->locale,
1209 (xsltLocaleChar *) results[j]->stringval,
1210 (xsltLocaleChar *) results[j + incr]->stringval);
1211 } else {
1212 tst = xmlStrcmp(results[j]->stringval,
1213 results[j + incr]->stringval);
1215 if (descending)
1216 tst = -tst;
1218 if (tst == 0) {
1220 * Okay we need to use multi level sorts
1222 depth = 1;
1223 while (depth < nbsorts) {
1224 if (sorts[depth] == NULL)
1225 break;
1226 comp = sorts[depth]->psvi;
1227 if (comp == NULL)
1228 break;
1229 desc = comp->descending;
1230 numb = comp->number;
1233 * Compute the result of the next level for the
1234 * full set, this might be optimized ... or not
1236 if (resultsTab[depth] == NULL)
1237 resultsTab[depth] = xsltComputeSortResult(ctxt,
1238 sorts[depth]);
1239 res = resultsTab[depth];
1240 if (res == NULL)
1241 break;
1242 if (res[j] == NULL) {
1243 if (res[j+incr] != NULL)
1244 tst = 1;
1245 } else if (res[j+incr] == NULL) {
1246 tst = -1;
1247 } else {
1248 if (numb) {
1249 /* We make NaN smaller than number in
1250 accordance with XSLT spec */
1251 if (xmlXPathIsNaN(res[j]->floatval)) {
1252 if (xmlXPathIsNaN(res[j +
1253 incr]->floatval))
1254 tst = 0;
1255 else
1256 tst = -1;
1257 } else if (xmlXPathIsNaN(res[j + incr]->
1258 floatval))
1259 tst = 1;
1260 else if (res[j]->floatval == res[j + incr]->
1261 floatval)
1262 tst = 0;
1263 else if (res[j]->floatval >
1264 res[j + incr]->floatval)
1265 tst = 1;
1266 else tst = -1;
1267 } else if(comp->locale != (xsltLocale)0) {
1268 tst = xsltLocaleStrcmp(
1269 comp->locale,
1270 (xsltLocaleChar *) res[j]->stringval,
1271 (xsltLocaleChar *) res[j + incr]->stringval);
1272 } else {
1273 tst = xmlStrcmp(res[j]->stringval,
1274 res[j + incr]->stringval);
1276 if (desc)
1277 tst = -tst;
1281 * if we still can't differenciate at this level
1282 * try one level deeper.
1284 if (tst != 0)
1285 break;
1286 depth++;
1289 if (tst == 0) {
1290 tst = results[j]->index > results[j + incr]->index;
1292 if (tst > 0) {
1293 tmp = results[j];
1294 results[j] = results[j + incr];
1295 results[j + incr] = tmp;
1296 node = list->nodeTab[j];
1297 list->nodeTab[j] = list->nodeTab[j + incr];
1298 list->nodeTab[j + incr] = node;
1299 depth = 1;
1300 while (depth < nbsorts) {
1301 if (sorts[depth] == NULL)
1302 break;
1303 if (resultsTab[depth] == NULL)
1304 break;
1305 res = resultsTab[depth];
1306 tmp = res[j];
1307 res[j] = res[j + incr];
1308 res[j + incr] = tmp;
1309 depth++;
1311 j -= incr;
1312 } else
1313 break;
1318 for (j = 0; j < nbsorts; j++) {
1319 comp = sorts[j]->psvi;
1320 if (tempstype[j] == 1) {
1321 /* The data-type needs to be recomputed each time */
1322 xmlFree((void *)(comp->stype));
1323 comp->stype = NULL;
1325 if (temporder[j] == 1) {
1326 /* The order needs to be recomputed each time */
1327 xmlFree((void *)(comp->order));
1328 comp->order = NULL;
1330 if (resultsTab[j] != NULL) {
1331 for (i = 0;i < len;i++)
1332 xmlXPathFreeObject(resultsTab[j][i]);
1333 xmlFree(resultsTab[j]);
1339 static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
1342 * xsltDoSortFunction:
1343 * @ctxt: a XSLT process context
1344 * @sorts: array of sort nodes
1345 * @nbsorts: the number of sorts in the array
1347 * reorder the current node list accordingly to the set of sorting
1348 * requirement provided by the arry of nodes.
1349 * This is a wrapper function, the actual function used is specified
1350 * using xsltSetCtxtSortFunc() to set the context specific sort function,
1351 * or xsltSetSortFunc() to set the global sort function.
1352 * If a sort function is set on the context, this will get called.
1353 * Otherwise the global sort function is called.
1355 void
1356 xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
1357 int nbsorts)
1359 if (ctxt->sortfunc != NULL)
1360 (ctxt->sortfunc)(ctxt, sorts, nbsorts);
1361 else if (xsltSortFunction != NULL)
1362 xsltSortFunction(ctxt, sorts, nbsorts);
1366 * xsltSetSortFunc:
1367 * @handler: the new handler function
1369 * Function to reset the global handler for XSLT sorting.
1370 * If the handler is NULL, the default sort function will be used.
1372 void
1373 xsltSetSortFunc(xsltSortFunc handler) {
1374 if (handler != NULL)
1375 xsltSortFunction = handler;
1376 else
1377 xsltSortFunction = xsltDefaultSortFunction;
1381 * xsltSetCtxtSortFunc:
1382 * @ctxt: a XSLT process context
1383 * @handler: the new handler function
1385 * Function to set the handler for XSLT sorting
1386 * for the specified context.
1387 * If the handler is NULL, then the global
1388 * sort function will be called
1390 void
1391 xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
1392 ctxt->sortfunc = handler;
1395 /************************************************************************
1397 * Parsing options *
1399 ************************************************************************/
1402 * xsltSetCtxtParseOptions:
1403 * @ctxt: a XSLT process context
1404 * @options: a combination of libxml2 xmlParserOption
1406 * Change the default parser option passed by the XSLT engine to the
1407 * parser when using document() loading.
1409 * Returns the previous options or -1 in case of error
1412 xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
1414 int oldopts;
1416 if (ctxt == NULL)
1417 return(-1);
1418 oldopts = ctxt->parserOptions;
1419 if (ctxt->xinclude)
1420 oldopts |= XML_PARSE_XINCLUDE;
1421 ctxt->parserOptions = options;
1422 if (options & XML_PARSE_XINCLUDE)
1423 ctxt->xinclude = 1;
1424 else
1425 ctxt->xinclude = 0;
1426 return(oldopts);
1429 /************************************************************************
1431 * Output *
1433 ************************************************************************/
1436 * xsltSaveResultTo:
1437 * @buf: an output buffer
1438 * @result: the result xmlDocPtr
1439 * @style: the stylesheet
1441 * Save the result @result obtained by applying the @style stylesheet
1442 * to an I/O output channel @buf
1444 * Returns the number of byte written or -1 in case of failure.
1447 xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
1448 xsltStylesheetPtr style) {
1449 const xmlChar *encoding;
1450 int base;
1451 const xmlChar *method;
1452 int indent;
1454 if ((buf == NULL) || (result == NULL) || (style == NULL))
1455 return(-1);
1456 if ((result->children == NULL) ||
1457 ((result->children->type == XML_DTD_NODE) &&
1458 (result->children->next == NULL)))
1459 return(0);
1461 if ((style->methodURI != NULL) &&
1462 ((style->method == NULL) ||
1463 (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
1464 xsltGenericError(xsltGenericErrorContext,
1465 "xsltSaveResultTo : unknown output method\n");
1466 return(-1);
1469 base = buf->written;
1471 XSLT_GET_IMPORT_PTR(method, style, method)
1472 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1473 XSLT_GET_IMPORT_INT(indent, style, indent);
1475 if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
1476 method = (const xmlChar *) "html";
1478 if ((method != NULL) &&
1479 (xmlStrEqual(method, (const xmlChar *) "html"))) {
1480 if (encoding != NULL) {
1481 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1482 } else {
1483 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1485 if (indent == -1)
1486 indent = 1;
1487 htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
1488 indent);
1489 xmlOutputBufferFlush(buf);
1490 } else if ((method != NULL) &&
1491 (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
1492 if (encoding != NULL) {
1493 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1494 } else {
1495 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1497 htmlDocContentDumpOutput(buf, result, (const char *) encoding);
1498 xmlOutputBufferFlush(buf);
1499 } else if ((method != NULL) &&
1500 (xmlStrEqual(method, (const xmlChar *) "text"))) {
1501 xmlNodePtr cur;
1503 cur = result->children;
1504 while (cur != NULL) {
1505 if (cur->type == XML_TEXT_NODE)
1506 xmlOutputBufferWriteString(buf, (const char *) cur->content);
1509 * Skip to next node
1511 if (cur->children != NULL) {
1512 if ((cur->children->type != XML_ENTITY_DECL) &&
1513 (cur->children->type != XML_ENTITY_REF_NODE) &&
1514 (cur->children->type != XML_ENTITY_NODE)) {
1515 cur = cur->children;
1516 continue;
1519 if (cur->next != NULL) {
1520 cur = cur->next;
1521 continue;
1524 do {
1525 cur = cur->parent;
1526 if (cur == NULL)
1527 break;
1528 if (cur == (xmlNodePtr) style->doc) {
1529 cur = NULL;
1530 break;
1532 if (cur->next != NULL) {
1533 cur = cur->next;
1534 break;
1536 } while (cur != NULL);
1538 xmlOutputBufferFlush(buf);
1539 } else {
1540 int omitXmlDecl;
1541 int standalone;
1543 XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
1544 XSLT_GET_IMPORT_INT(standalone, style, standalone);
1546 if (omitXmlDecl != 1) {
1547 xmlOutputBufferWriteString(buf, "<?xml version=");
1548 if (result->version != NULL) {
1549 xmlOutputBufferWriteString(buf, "\"");
1550 xmlOutputBufferWriteString(buf, (const char *)result->version);
1551 xmlOutputBufferWriteString(buf, "\"");
1552 } else
1553 xmlOutputBufferWriteString(buf, "\"1.0\"");
1554 if (encoding == NULL) {
1555 if (result->encoding != NULL)
1556 encoding = result->encoding;
1557 else if (result->charset != XML_CHAR_ENCODING_UTF8)
1558 encoding = (const xmlChar *)
1559 xmlGetCharEncodingName((xmlCharEncoding)
1560 result->charset);
1562 if (encoding != NULL) {
1563 xmlOutputBufferWriteString(buf, " encoding=");
1564 xmlOutputBufferWriteString(buf, "\"");
1565 xmlOutputBufferWriteString(buf, (const char *) encoding);
1566 xmlOutputBufferWriteString(buf, "\"");
1568 switch (standalone) {
1569 case 0:
1570 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
1571 break;
1572 case 1:
1573 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
1574 break;
1575 default:
1576 break;
1578 xmlOutputBufferWriteString(buf, "?>\n");
1580 if (result->children != NULL) {
1581 xmlNodePtr children = result->children;
1582 xmlNodePtr child = children;
1585 * Hack to avoid quadratic behavior when scanning
1586 * result->children in xmlGetIntSubset called by
1587 * xmlNodeDumpOutput.
1589 result->children = NULL;
1591 while (child != NULL) {
1592 xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
1593 (const char *) encoding);
1594 if (indent && ((child->type == XML_DTD_NODE) ||
1595 ((child->type == XML_COMMENT_NODE) &&
1596 (child->next != NULL))))
1597 xmlOutputBufferWriteString(buf, "\n");
1598 child = child->next;
1600 if (indent)
1601 xmlOutputBufferWriteString(buf, "\n");
1603 result->children = children;
1605 xmlOutputBufferFlush(buf);
1607 return(buf->written - base);
1611 * xsltSaveResultToFilename:
1612 * @URL: a filename or URL
1613 * @result: the result xmlDocPtr
1614 * @style: the stylesheet
1615 * @compression: the compression factor (0 - 9 included)
1617 * Save the result @result obtained by applying the @style stylesheet
1618 * to a file or @URL
1620 * Returns the number of byte written or -1 in case of failure.
1623 xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
1624 xsltStylesheetPtr style, int compression) {
1625 xmlOutputBufferPtr buf;
1626 const xmlChar *encoding;
1627 int ret;
1629 if ((URL == NULL) || (result == NULL) || (style == NULL))
1630 return(-1);
1631 if (result->children == NULL)
1632 return(0);
1634 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1635 if (encoding != NULL) {
1636 xmlCharEncodingHandlerPtr encoder;
1638 encoder = xmlFindCharEncodingHandler((char *)encoding);
1639 if ((encoder != NULL) &&
1640 (xmlStrEqual((const xmlChar *)encoder->name,
1641 (const xmlChar *) "UTF-8")))
1642 encoder = NULL;
1643 buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
1644 } else {
1645 buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
1647 if (buf == NULL)
1648 return(-1);
1649 xsltSaveResultTo(buf, result, style);
1650 ret = xmlOutputBufferClose(buf);
1651 return(ret);
1655 * xsltSaveResultToFile:
1656 * @file: a FILE * I/O
1657 * @result: the result xmlDocPtr
1658 * @style: the stylesheet
1660 * Save the result @result obtained by applying the @style stylesheet
1661 * to an open FILE * I/O.
1662 * This does not close the FILE @file
1664 * Returns the number of bytes written or -1 in case of failure.
1667 xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
1668 xmlOutputBufferPtr buf;
1669 const xmlChar *encoding;
1670 int ret;
1672 if ((file == NULL) || (result == NULL) || (style == NULL))
1673 return(-1);
1674 if (result->children == NULL)
1675 return(0);
1677 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1678 if (encoding != NULL) {
1679 xmlCharEncodingHandlerPtr encoder;
1681 encoder = xmlFindCharEncodingHandler((char *)encoding);
1682 if ((encoder != NULL) &&
1683 (xmlStrEqual((const xmlChar *)encoder->name,
1684 (const xmlChar *) "UTF-8")))
1685 encoder = NULL;
1686 buf = xmlOutputBufferCreateFile(file, encoder);
1687 } else {
1688 buf = xmlOutputBufferCreateFile(file, NULL);
1691 if (buf == NULL)
1692 return(-1);
1693 xsltSaveResultTo(buf, result, style);
1694 ret = xmlOutputBufferClose(buf);
1695 return(ret);
1699 * xsltSaveResultToFd:
1700 * @fd: a file descriptor
1701 * @result: the result xmlDocPtr
1702 * @style: the stylesheet
1704 * Save the result @result obtained by applying the @style stylesheet
1705 * to an open file descriptor
1706 * This does not close the descriptor.
1708 * Returns the number of bytes written or -1 in case of failure.
1711 xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
1712 xmlOutputBufferPtr buf;
1713 const xmlChar *encoding;
1714 int ret;
1716 if ((fd < 0) || (result == NULL) || (style == NULL))
1717 return(-1);
1718 if (result->children == NULL)
1719 return(0);
1721 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1722 if (encoding != NULL) {
1723 xmlCharEncodingHandlerPtr encoder;
1725 encoder = xmlFindCharEncodingHandler((char *)encoding);
1726 if ((encoder != NULL) &&
1727 (xmlStrEqual((const xmlChar *)encoder->name,
1728 (const xmlChar *) "UTF-8")))
1729 encoder = NULL;
1730 buf = xmlOutputBufferCreateFd(fd, encoder);
1731 } else {
1732 buf = xmlOutputBufferCreateFd(fd, NULL);
1734 if (buf == NULL)
1735 return(-1);
1736 xsltSaveResultTo(buf, result, style);
1737 ret = xmlOutputBufferClose(buf);
1738 return(ret);
1742 * xsltSaveResultToString:
1743 * @doc_txt_ptr: Memory pointer for allocated XML text
1744 * @doc_txt_len: Length of the generated XML text
1745 * @result: the result xmlDocPtr
1746 * @style: the stylesheet
1748 * Save the result @result obtained by applying the @style stylesheet
1749 * to a new allocated string.
1751 * Returns 0 in case of success and -1 in case of error
1754 xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len,
1755 xmlDocPtr result, xsltStylesheetPtr style) {
1756 xmlOutputBufferPtr buf;
1757 const xmlChar *encoding;
1759 *doc_txt_ptr = NULL;
1760 *doc_txt_len = 0;
1761 if (result->children == NULL)
1762 return(0);
1764 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1765 if (encoding != NULL) {
1766 xmlCharEncodingHandlerPtr encoder;
1768 encoder = xmlFindCharEncodingHandler((char *)encoding);
1769 if ((encoder != NULL) &&
1770 (xmlStrEqual((const xmlChar *)encoder->name,
1771 (const xmlChar *) "UTF-8")))
1772 encoder = NULL;
1773 buf = xmlAllocOutputBuffer(encoder);
1774 } else {
1775 buf = xmlAllocOutputBuffer(NULL);
1777 if (buf == NULL)
1778 return(-1);
1779 xsltSaveResultTo(buf, result, style);
1780 #ifdef LIBXML2_NEW_BUFFER
1781 if (buf->conv != NULL) {
1782 *doc_txt_len = xmlBufUse(buf->conv);
1783 *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->conv), *doc_txt_len);
1784 } else {
1785 *doc_txt_len = xmlBufUse(buf->buffer);
1786 *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), *doc_txt_len);
1788 #else
1789 if (buf->conv != NULL) {
1790 *doc_txt_len = buf->conv->use;
1791 *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
1792 } else {
1793 *doc_txt_len = buf->buffer->use;
1794 *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
1796 #endif
1797 (void)xmlOutputBufferClose(buf);
1798 return 0;
1801 #ifdef WITH_PROFILER
1803 /************************************************************************
1805 * Generating profiling information *
1807 ************************************************************************/
1809 static long calibration = -1;
1812 * xsltCalibrateTimestamps:
1814 * Used for to calibrate the xsltTimestamp() function
1815 * Should work if launched at startup and we don't loose our quantum :-)
1817 * Returns the number of milliseconds used by xsltTimestamp()
1819 #if !defined(XSLT_WIN32_PERFORMANCE_COUNTER) && \
1820 (defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY))
1821 static long
1822 xsltCalibrateTimestamps(void) {
1823 register int i;
1825 for (i = 0;i < 999;i++)
1826 xsltTimestamp();
1827 return(xsltTimestamp() / 1000);
1829 #endif
1832 * xsltCalibrateAdjust:
1833 * @delta: a negative dealy value found
1835 * Used for to correct the calibration for xsltTimestamp()
1837 void
1838 xsltCalibrateAdjust(long delta) {
1839 calibration += delta;
1843 * xsltTimestamp:
1845 * Used for gathering profiling data
1847 * Returns the number of tenth of milliseconds since the beginning of the
1848 * profiling
1850 long
1851 xsltTimestamp(void)
1853 #ifdef XSLT_WIN32_PERFORMANCE_COUNTER
1854 BOOL ok;
1855 LARGE_INTEGER performanceCount;
1856 LARGE_INTEGER performanceFrequency;
1857 LONGLONG quadCount;
1858 double seconds;
1859 static LONGLONG startupQuadCount = 0;
1860 static LONGLONG startupQuadFreq = 0;
1862 ok = QueryPerformanceCounter(&performanceCount);
1863 if (!ok)
1864 return 0;
1865 quadCount = performanceCount.QuadPart;
1866 if (calibration < 0) {
1867 calibration = 0;
1868 ok = QueryPerformanceFrequency(&performanceFrequency);
1869 if (!ok)
1870 return 0;
1871 startupQuadFreq = performanceFrequency.QuadPart;
1872 startupQuadCount = quadCount;
1873 return (0);
1875 if (startupQuadFreq == 0)
1876 return 0;
1877 seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
1878 return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
1880 #else /* XSLT_WIN32_PERFORMANCE_COUNTER */
1881 #ifdef HAVE_CLOCK_GETTIME
1882 # if defined(CLOCK_MONOTONIC)
1883 # define XSLT_CLOCK CLOCK_MONOTONIC
1884 # elif defined(CLOCK_HIGHRES)
1885 # define XSLT_CLOCK CLOCK_HIGHRES
1886 # else
1887 # define XSLT_CLOCK CLOCK_REALTIME
1888 # endif
1889 static struct timespec startup;
1890 struct timespec cur;
1891 long tics;
1893 if (calibration < 0) {
1894 clock_gettime(XSLT_CLOCK, &startup);
1895 calibration = 0;
1896 calibration = xsltCalibrateTimestamps();
1897 clock_gettime(XSLT_CLOCK, &startup);
1898 return (0);
1901 clock_gettime(XSLT_CLOCK, &cur);
1902 tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1903 tics += (cur.tv_nsec - startup.tv_nsec) /
1904 (1000000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1906 tics -= calibration;
1907 return(tics);
1909 #elif HAVE_GETTIMEOFDAY
1910 static struct timeval startup;
1911 struct timeval cur;
1912 long tics;
1914 if (calibration < 0) {
1915 gettimeofday(&startup, NULL);
1916 calibration = 0;
1917 calibration = xsltCalibrateTimestamps();
1918 gettimeofday(&startup, NULL);
1919 return (0);
1922 gettimeofday(&cur, NULL);
1923 tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1924 tics += (cur.tv_usec - startup.tv_usec) /
1925 (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1927 tics -= calibration;
1928 return(tics);
1929 #else
1931 /* Neither gettimeofday() nor Win32 performance counter available */
1933 return (0);
1935 #endif /* HAVE_GETTIMEOFDAY */
1936 #endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
1939 static char *
1940 pretty_templ_match(xsltTemplatePtr templ) {
1941 static char dst[1001];
1942 char *src = (char *)templ->match;
1943 int i=0,j;
1945 /* strip white spaces */
1946 for (j=0; i<1000 && src[j]; i++,j++) {
1947 for(;src[j]==' ';j++);
1948 dst[i]=src[j];
1950 if(i<998 && templ->mode) {
1951 /* append [mode] */
1952 dst[i++]='[';
1953 src=(char *)templ->mode;
1954 for (j=0; i<999 && src[j]; i++,j++) {
1955 dst[i]=src[j];
1957 dst[i++]=']';
1959 dst[i]='\0';
1960 return dst;
1963 #define MAX_TEMPLATES 10000
1966 * xsltSaveProfiling:
1967 * @ctxt: an XSLT context
1968 * @output: a FILE * for saving the information
1970 * Save the profiling information on @output
1972 void
1973 xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
1974 int nb, i,j,k,l;
1975 int max;
1976 int total;
1977 unsigned long totalt;
1978 xsltTemplatePtr *templates;
1979 xsltStylesheetPtr style;
1980 xsltTemplatePtr templ1,templ2;
1981 int *childt;
1983 if ((output == NULL) || (ctxt == NULL))
1984 return;
1985 if (ctxt->profile == 0)
1986 return;
1988 nb = 0;
1989 max = MAX_TEMPLATES;
1990 templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
1991 if (templates == NULL)
1992 return;
1994 style = ctxt->style;
1995 while (style != NULL) {
1996 templ1 = style->templates;
1997 while (templ1 != NULL) {
1998 if (nb >= max)
1999 break;
2001 if (templ1->nbCalls > 0)
2002 templates[nb++] = templ1;
2003 templ1 = templ1->next;
2006 style = xsltNextImport(style);
2009 for (i = 0;i < nb -1;i++) {
2010 for (j = i + 1; j < nb; j++) {
2011 if ((templates[i]->time <= templates[j]->time) ||
2012 ((templates[i]->time == templates[j]->time) &&
2013 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2014 templ1 = templates[j];
2015 templates[j] = templates[i];
2016 templates[i] = templ1;
2022 /* print flat profile */
2024 fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n",
2025 "number", "match", "name", "mode");
2026 total = 0;
2027 totalt = 0;
2028 for (i = 0;i < nb;i++) {
2029 templ1 = templates[i];
2030 fprintf(output, "%5d ", i);
2031 if (templ1->match != NULL) {
2032 if (xmlStrlen(templ1->match) > 20)
2033 fprintf(output, "%s\n%26s", templ1->match, "");
2034 else
2035 fprintf(output, "%20s", templ1->match);
2036 } else {
2037 fprintf(output, "%20s", "");
2039 if (templ1->name != NULL) {
2040 if (xmlStrlen(templ1->name) > 20)
2041 fprintf(output, "%s\n%46s", templ1->name, "");
2042 else
2043 fprintf(output, "%20s", templ1->name);
2044 } else {
2045 fprintf(output, "%20s", "");
2047 if (templ1->mode != NULL) {
2048 if (xmlStrlen(templ1->mode) > 10)
2049 fprintf(output, "%s\n%56s", templ1->mode, "");
2050 else
2051 fprintf(output, "%10s", templ1->mode);
2052 } else {
2053 fprintf(output, "%10s", "");
2055 fprintf(output, " %6d", templ1->nbCalls);
2056 fprintf(output, " %6ld %6ld\n", templ1->time,
2057 templ1->time / templ1->nbCalls);
2058 total += templ1->nbCalls;
2059 totalt += templ1->time;
2061 fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
2064 /* print call graph */
2066 childt = xmlMalloc((nb + 1) * sizeof(int));
2067 if (childt == NULL)
2068 return;
2070 /* precalculate children times */
2071 for (i = 0; i < nb; i++) {
2072 templ1 = templates[i];
2074 childt[i] = 0;
2075 for (k = 0; k < nb; k++) {
2076 templ2 = templates[k];
2077 for (l = 0; l < templ2->templNr; l++) {
2078 if (templ2->templCalledTab[l] == templ1) {
2079 childt[i] +=templ2->time;
2084 childt[i] = 0;
2086 fprintf(output, "\nindex %% time self children called name\n");
2088 for (i = 0; i < nb; i++) {
2089 char ix_str[20], timep_str[20], times_str[20], timec_str[20], called_str[20];
2090 unsigned long t;
2092 templ1 = templates[i];
2093 /* callers */
2094 for (j = 0; j < templ1->templNr; j++) {
2095 templ2 = templ1->templCalledTab[j];
2096 for (k = 0; k < nb; k++) {
2097 if (templates[k] == templ2)
2098 break;
2100 t=templ2?templ2->time:totalt;
2101 snprintf(times_str,sizeof(times_str),"%8.3f",(float)t/XSLT_TIMESTAMP_TICS_PER_SEC);
2102 snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC);
2103 snprintf(called_str,sizeof(called_str),"%6d/%d",
2104 templ1->templCountTab[j], /* number of times caller calls 'this' */
2105 templ1->nbCalls); /* total number of calls to 'this' */
2107 fprintf(output, " %-8s %-8s %-12s %s [%d]\n",
2108 times_str,timec_str,called_str,
2109 (templ2?(templ2->name?(char *)templ2->name:pretty_templ_match(templ2)):"-"),k);
2111 /* this */
2112 snprintf(ix_str,sizeof(ix_str),"[%d]",i);
2113 snprintf(timep_str,sizeof(timep_str),"%6.2f",(float)templ1->time*100.0/totalt);
2114 snprintf(times_str,sizeof(times_str),"%8.3f",(float)templ1->time/XSLT_TIMESTAMP_TICS_PER_SEC);
2115 snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[i]/XSLT_TIMESTAMP_TICS_PER_SEC);
2116 fprintf(output, "%-5s %-6s %-8s %-8s %6d %s [%d]\n",
2117 ix_str, timep_str,times_str,timec_str,
2118 templ1->nbCalls,
2119 templ1->name?(char *)templ1->name:pretty_templ_match(templ1),i);
2120 /* callees
2121 * - go over templates[0..nb] and their templCalledTab[]
2122 * - print those where we in the the call-stack
2124 total = 0;
2125 for (k = 0; k < nb; k++) {
2126 templ2 = templates[k];
2127 for (l = 0; l < templ2->templNr; l++) {
2128 if (templ2->templCalledTab[l] == templ1) {
2129 total+=templ2->templCountTab[l];
2133 for (k = 0; k < nb; k++) {
2134 templ2 = templates[k];
2135 for (l = 0; l < templ2->templNr; l++) {
2136 if (templ2->templCalledTab[l] == templ1) {
2137 snprintf(times_str,sizeof(times_str),"%8.3f",(float)templ2->time/XSLT_TIMESTAMP_TICS_PER_SEC);
2138 snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC);
2139 snprintf(called_str,sizeof(called_str),"%6d/%d",
2140 templ2->templCountTab[l], /* number of times 'this' calls callee */
2141 total); /* total number of calls from 'this' */
2142 fprintf(output, " %-8s %-8s %-12s %s [%d]\n",
2143 times_str,timec_str,called_str,
2144 templ2->name?(char *)templ2->name:pretty_templ_match(templ2),k);
2148 fprintf(output, "-----------------------------------------------\n");
2151 fprintf(output, "\f\nIndex by function name\n");
2152 for (i = 0; i < nb; i++) {
2153 templ1 = templates[i];
2154 fprintf(output, "[%d] %s (%s:%d)\n",
2155 i, templ1->name?(char *)templ1->name:pretty_templ_match(templ1),
2156 templ1->style->doc->URL,templ1->elem->line);
2159 fprintf(output, "\f\n");
2160 xmlFree(childt);
2162 xmlFree(templates);
2165 /************************************************************************
2167 * Fetching profiling information *
2169 ************************************************************************/
2172 * xsltGetProfileInformation:
2173 * @ctxt: a transformation context
2175 * This function should be called after the transformation completed
2176 * to extract template processing profiling information if available.
2177 * The information is returned as an XML document tree like
2178 * <?xml version="1.0"?>
2179 * <profile>
2180 * <template rank="1" match="*" name=""
2181 * mode="" calls="6" time="48" average="8"/>
2182 * <template rank="2" match="item2|item3" name=""
2183 * mode="" calls="10" time="30" average="3"/>
2184 * <template rank="3" match="item1" name=""
2185 * mode="" calls="5" time="17" average="3"/>
2186 * </profile>
2187 * The caller will need to free up the returned tree with xmlFreeDoc()
2189 * Returns the xmlDocPtr corresponding to the result or NULL if not available.
2192 xmlDocPtr
2193 xsltGetProfileInformation(xsltTransformContextPtr ctxt)
2195 xmlDocPtr ret = NULL;
2196 xmlNodePtr root, child;
2197 char buf[100];
2199 xsltStylesheetPtr style;
2200 xsltTemplatePtr *templates;
2201 xsltTemplatePtr templ;
2202 int nb = 0, max = 0, i, j;
2204 if (!ctxt)
2205 return NULL;
2207 if (!ctxt->profile)
2208 return NULL;
2210 nb = 0;
2211 max = 10000;
2212 templates =
2213 (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
2214 if (templates == NULL)
2215 return NULL;
2218 * collect all the templates in an array
2220 style = ctxt->style;
2221 while (style != NULL) {
2222 templ = style->templates;
2223 while (templ != NULL) {
2224 if (nb >= max)
2225 break;
2227 if (templ->nbCalls > 0)
2228 templates[nb++] = templ;
2229 templ = templ->next;
2232 style = (xsltStylesheetPtr) xsltNextImport(style);
2236 * Sort the array by time spent
2238 for (i = 0; i < nb - 1; i++) {
2239 for (j = i + 1; j < nb; j++) {
2240 if ((templates[i]->time <= templates[j]->time) ||
2241 ((templates[i]->time == templates[j]->time) &&
2242 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2243 templ = templates[j];
2244 templates[j] = templates[i];
2245 templates[i] = templ;
2251 * Generate a document corresponding to the results.
2253 ret = xmlNewDoc(BAD_CAST "1.0");
2254 root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
2255 xmlDocSetRootElement(ret, root);
2257 for (i = 0; i < nb; i++) {
2258 child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
2259 snprintf(buf, sizeof(buf), "%d", i + 1);
2260 xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
2261 xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
2262 xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
2263 xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
2265 snprintf(buf, sizeof(buf), "%d", templates[i]->nbCalls);
2266 xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
2268 snprintf(buf, sizeof(buf), "%ld", templates[i]->time);
2269 xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
2271 snprintf(buf, sizeof(buf), "%ld", templates[i]->time / templates[i]->nbCalls);
2272 xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
2275 xmlFree(templates);
2277 return ret;
2280 #endif /* WITH_PROFILER */
2282 /************************************************************************
2284 * Hooks for libxml2 XPath *
2286 ************************************************************************/
2289 * xsltXPathCompileFlags:
2290 * @style: the stylesheet
2291 * @str: the XPath expression
2292 * @flags: extra compilation flags to pass down to libxml2 XPath
2294 * Compile an XPath expression
2296 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2297 * the caller has to free the object.
2299 xmlXPathCompExprPtr
2300 xsltXPathCompileFlags(xsltStylesheetPtr style, const xmlChar *str, int flags) {
2301 xmlXPathContextPtr xpathCtxt;
2302 xmlXPathCompExprPtr ret;
2304 if (style != NULL) {
2305 xpathCtxt = style->principal->xpathCtxt;
2306 if (xpathCtxt == NULL)
2307 return NULL;
2308 xpathCtxt->dict = style->dict;
2309 } else {
2310 xpathCtxt = xmlXPathNewContext(NULL);
2311 if (xpathCtxt == NULL)
2312 return NULL;
2314 xpathCtxt->flags = flags;
2317 * Compile the expression.
2319 ret = xmlXPathCtxtCompile(xpathCtxt, str);
2321 if (style == NULL) {
2322 xmlXPathFreeContext(xpathCtxt);
2325 * TODO: there is a lot of optimizations which should be possible
2326 * like variable slot precomputations, function precomputations, etc.
2329 return(ret);
2333 * xsltXPathCompile:
2334 * @style: the stylesheet
2335 * @str: the XPath expression
2337 * Compile an XPath expression
2339 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2340 * the caller has to free the object.
2342 xmlXPathCompExprPtr
2343 xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
2344 return(xsltXPathCompileFlags(style, str, 0));
2347 /************************************************************************
2349 * Hooks for the debugger *
2351 ************************************************************************/
2353 int xslDebugStatus;
2356 * xsltGetDebuggerStatus:
2358 * Get xslDebugStatus.
2360 * Returns the value of xslDebugStatus.
2363 xsltGetDebuggerStatus(void)
2365 return(xslDebugStatus);
2368 #ifdef WITH_DEBUGGER
2371 * There is currently only 3 debugging callback defined
2372 * Debugger callbacks are disabled by default
2374 #define XSLT_CALLBACK_NUMBER 3
2376 typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
2377 typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
2378 struct _xsltDebuggerCallbacks {
2379 xsltHandleDebuggerCallback handler;
2380 xsltAddCallCallback add;
2381 xsltDropCallCallback drop;
2384 static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
2385 NULL, /* handler */
2386 NULL, /* add */
2387 NULL /* drop */
2391 * xsltSetDebuggerStatus:
2392 * @value : the value to be set
2394 * This function sets the value of xslDebugStatus.
2396 void
2397 xsltSetDebuggerStatus(int value)
2399 xslDebugStatus = value;
2403 * xsltSetDebuggerCallbacks:
2404 * @no : number of callbacks
2405 * @block : the block of callbacks
2407 * This function allow to plug a debugger into the XSLT library
2408 * @block points to a block of memory containing the address of @no
2409 * callback routines.
2411 * Returns 0 in case of success and -1 in case of error
2414 xsltSetDebuggerCallbacks(int no, void *block)
2416 xsltDebuggerCallbacksPtr callbacks;
2418 if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
2419 return(-1);
2421 callbacks = (xsltDebuggerCallbacksPtr) block;
2422 xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
2423 xsltDebuggerCurrentCallbacks.add = callbacks->add;
2424 xsltDebuggerCurrentCallbacks.drop = callbacks->drop;
2425 return(0);
2429 * xslHandleDebugger:
2430 * @cur : source node being executed
2431 * @node : data node being processed
2432 * @templ : temlate that applies to node
2433 * @ctxt : the xslt transform context
2435 * If either cur or node are a breakpoint, or xslDebugStatus in state
2436 * where debugging must occcur at this time then transfer control
2437 * to the xslDebugBreak function
2439 void
2440 xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
2441 xsltTransformContextPtr ctxt)
2443 if (xsltDebuggerCurrentCallbacks.handler != NULL)
2444 xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
2448 * xslAddCall:
2449 * @templ : current template being applied
2450 * @source : the source node being processed
2452 * Add template "call" to call stack
2453 * Returns : 1 on sucess 0 otherwise an error may be printed if
2454 * WITH_XSLT_DEBUG_BREAKPOINTS is defined
2457 xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
2459 if (xsltDebuggerCurrentCallbacks.add != NULL)
2460 return(xsltDebuggerCurrentCallbacks.add(templ, source));
2461 return(0);
2465 * xslDropCall:
2467 * Drop the topmost item off the call stack
2469 void
2470 xslDropCall(void)
2472 if (xsltDebuggerCurrentCallbacks.drop != NULL)
2473 xsltDebuggerCurrentCallbacks.drop();
2476 #endif /* WITH_DEBUGGER */