cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / third_party / libxslt / libxslt / xsltutils.c
blobab981a4237274e6ea44604250f047b9c6c844ead
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 /* gettimeofday on Windows ??? */
46 #if defined(WIN32) && !defined(__CYGWIN__)
47 #ifdef _MSC_VER
48 #include <winsock2.h>
49 #pragma comment(lib, "ws2_32.lib")
50 #define gettimeofday(p1,p2)
51 #define HAVE_GETTIMEOFDAY
52 #define XSLT_WIN32_PERFORMANCE_COUNTER
53 #endif /* _MS_VER */
54 #endif /* WIN32 */
56 /************************************************************************
57 * *
58 * Convenience function *
59 * *
60 ************************************************************************/
62 /**
63 * xsltGetCNsProp:
64 * @style: the stylesheet
65 * @node: the node
66 * @name: the attribute name
67 * @nameSpace: the URI of the namespace
69 * Similar to xmlGetNsProp() but with a slightly different semantic
71 * Search and get the value of an attribute associated to a node
72 * This attribute has to be anchored in the namespace specified,
73 * or has no namespace and the element is in that namespace.
75 * This does the entity substitution.
76 * This function looks in DTD attribute declaration for #FIXED or
77 * default declaration values unless DTD use has been turned off.
79 * Returns the attribute value or NULL if not found. The string is allocated
80 * in the stylesheet dictionary.
82 const xmlChar *
83 xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,
84 const xmlChar *name, const xmlChar *nameSpace) {
85 xmlAttrPtr prop;
86 xmlDocPtr doc;
87 xmlNsPtr ns;
88 xmlChar *tmp;
89 const xmlChar *ret;
91 if ((node == NULL) || (style == NULL) || (style->dict == NULL))
92 return(NULL);
94 if (nameSpace == NULL)
95 return xmlGetProp(node, name);
97 if (node->type == XML_NAMESPACE_DECL)
98 return(NULL);
99 if (node->type == XML_ELEMENT_NODE)
100 prop = node->properties;
101 else
102 prop = NULL;
103 while (prop != NULL) {
105 * One need to have
106 * - same attribute names
107 * - and the attribute carrying that namespace
109 if ((xmlStrEqual(prop->name, name)) &&
110 (((prop->ns == NULL) && (node->ns != NULL) &&
111 (xmlStrEqual(node->ns->href, nameSpace))) ||
112 ((prop->ns != NULL) &&
113 (xmlStrEqual(prop->ns->href, nameSpace))))) {
115 tmp = xmlNodeListGetString(node->doc, prop->children, 1);
116 if (tmp == NULL)
117 ret = xmlDictLookup(style->dict, BAD_CAST "", 0);
118 else {
119 ret = xmlDictLookup(style->dict, tmp, -1);
120 xmlFree(tmp);
122 return ret;
124 prop = prop->next;
126 tmp = NULL;
128 * Check if there is a default declaration in the internal
129 * or external subsets
131 doc = node->doc;
132 if (doc != NULL) {
133 if (doc->intSubset != NULL) {
134 xmlAttributePtr attrDecl;
136 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
137 if ((attrDecl == NULL) && (doc->extSubset != NULL))
138 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
140 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
142 * The DTD declaration only allows a prefix search
144 ns = xmlSearchNs(doc, node, attrDecl->prefix);
145 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
146 return(xmlDictLookup(style->dict,
147 attrDecl->defaultValue, -1));
151 return(NULL);
154 * xsltGetNsProp:
155 * @node: the node
156 * @name: the attribute name
157 * @nameSpace: the URI of the namespace
159 * Similar to xmlGetNsProp() but with a slightly different semantic
161 * Search and get the value of an attribute associated to a node
162 * This attribute has to be anchored in the namespace specified,
163 * or has no namespace and the element is in that namespace.
165 * This does the entity substitution.
166 * This function looks in DTD attribute declaration for #FIXED or
167 * default declaration values unless DTD use has been turned off.
169 * Returns the attribute value or NULL if not found.
170 * It's up to the caller to free the memory.
172 xmlChar *
173 xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
174 xmlAttrPtr prop;
175 xmlDocPtr doc;
176 xmlNsPtr ns;
178 if (node == NULL)
179 return(NULL);
181 if (nameSpace == NULL)
182 return xmlGetProp(node, name);
184 if (node->type == XML_NAMESPACE_DECL)
185 return(NULL);
186 if (node->type == XML_ELEMENT_NODE)
187 prop = node->properties;
188 else
189 prop = NULL;
191 * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former
192 * is not namespace-aware and will return an attribute with equal
193 * name regardless of its namespace.
194 * Example:
195 * <xsl:element foo:name="myName"/>
196 * So this would return "myName" even if an attribute @name
197 * in the XSLT was requested.
199 while (prop != NULL) {
201 * One need to have
202 * - same attribute names
203 * - and the attribute carrying that namespace
205 if ((xmlStrEqual(prop->name, name)) &&
206 (((prop->ns == NULL) && (node->ns != NULL) &&
207 (xmlStrEqual(node->ns->href, nameSpace))) ||
208 ((prop->ns != NULL) &&
209 (xmlStrEqual(prop->ns->href, nameSpace))))) {
210 xmlChar *ret;
212 ret = xmlNodeListGetString(node->doc, prop->children, 1);
213 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
214 return(ret);
216 prop = prop->next;
220 * Check if there is a default declaration in the internal
221 * or external subsets
223 doc = node->doc;
224 if (doc != NULL) {
225 if (doc->intSubset != NULL) {
226 xmlAttributePtr attrDecl;
228 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
229 if ((attrDecl == NULL) && (doc->extSubset != NULL))
230 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
232 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
234 * The DTD declaration only allows a prefix search
236 ns = xmlSearchNs(doc, node, attrDecl->prefix);
237 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
238 return(xmlStrdup(attrDecl->defaultValue));
242 return(NULL);
246 * xsltGetUTF8Char:
247 * @utf: a sequence of UTF-8 encoded bytes
248 * @len: a pointer to @bytes len
250 * Read one UTF8 Char from @utf
251 * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately
252 * and use the original API
254 * Returns the char value or -1 in case of error and update @len with the
255 * number of bytes used
258 xsltGetUTF8Char(const unsigned char *utf, int *len) {
259 unsigned int c;
261 if (utf == NULL)
262 goto error;
263 if (len == NULL)
264 goto error;
265 if (*len < 1)
266 goto error;
268 c = utf[0];
269 if (c & 0x80) {
270 if (*len < 2)
271 goto error;
272 if ((utf[1] & 0xc0) != 0x80)
273 goto error;
274 if ((c & 0xe0) == 0xe0) {
275 if (*len < 3)
276 goto error;
277 if ((utf[2] & 0xc0) != 0x80)
278 goto error;
279 if ((c & 0xf0) == 0xf0) {
280 if (*len < 4)
281 goto error;
282 if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
283 goto error;
284 *len = 4;
285 /* 4-byte code */
286 c = (utf[0] & 0x7) << 18;
287 c |= (utf[1] & 0x3f) << 12;
288 c |= (utf[2] & 0x3f) << 6;
289 c |= utf[3] & 0x3f;
290 } else {
291 /* 3-byte code */
292 *len = 3;
293 c = (utf[0] & 0xf) << 12;
294 c |= (utf[1] & 0x3f) << 6;
295 c |= utf[2] & 0x3f;
297 } else {
298 /* 2-byte code */
299 *len = 2;
300 c = (utf[0] & 0x1f) << 6;
301 c |= utf[1] & 0x3f;
303 } else {
304 /* 1-byte code */
305 *len = 1;
307 return(c);
309 error:
310 if (len != NULL)
311 *len = 0;
312 return(-1);
315 #ifdef XSLT_REFACTORED
318 * xsltPointerListAddSize:
319 * @list: the pointer list structure
320 * @item: the item to be stored
321 * @initialSize: the initial size of the list
323 * Adds an item to the list.
325 * Returns the position of the added item in the list or
326 * -1 in case of an error.
329 xsltPointerListAddSize(xsltPointerListPtr list,
330 void *item,
331 int initialSize)
333 if (list->items == NULL) {
334 if (initialSize <= 0)
335 initialSize = 1;
336 list->items = (void **) xmlMalloc(
337 initialSize * sizeof(void *));
338 if (list->items == NULL) {
339 xsltGenericError(xsltGenericErrorContext,
340 "xsltPointerListAddSize: memory allocation failure.\n");
341 return(-1);
343 list->number = 0;
344 list->size = initialSize;
345 } else if (list->size <= list->number) {
346 list->size *= 2;
347 list->items = (void **) xmlRealloc(list->items,
348 list->size * sizeof(void *));
349 if (list->items == NULL) {
350 xsltGenericError(xsltGenericErrorContext,
351 "xsltPointerListAddSize: memory re-allocation failure.\n");
352 list->size = 0;
353 return(-1);
356 list->items[list->number++] = item;
357 return(0);
361 * xsltPointerListCreate:
362 * @initialSize: the initial size for the list
364 * Creates an xsltPointerList structure.
366 * Returns a xsltPointerList structure or NULL in case of an error.
368 xsltPointerListPtr
369 xsltPointerListCreate(int initialSize)
371 xsltPointerListPtr ret;
373 ret = xmlMalloc(sizeof(xsltPointerList));
374 if (ret == NULL) {
375 xsltGenericError(xsltGenericErrorContext,
376 "xsltPointerListCreate: memory allocation failure.\n");
377 return (NULL);
379 memset(ret, 0, sizeof(xsltPointerList));
380 if (initialSize > 0) {
381 xsltPointerListAddSize(ret, NULL, initialSize);
382 ret->number = 0;
384 return (ret);
388 * xsltPointerListFree:
389 * @list: pointer to the list to be freed
391 * Frees the xsltPointerList structure. This does not free
392 * the content of the list.
394 void
395 xsltPointerListFree(xsltPointerListPtr list)
397 if (list == NULL)
398 return;
399 if (list->items != NULL)
400 xmlFree(list->items);
401 xmlFree(list);
405 * xsltPointerListClear:
406 * @list: pointer to the list to be cleared
408 * Resets the list, but does not free the allocated array
409 * and does not free the content of the list.
411 void
412 xsltPointerListClear(xsltPointerListPtr list)
414 if (list->items != NULL) {
415 xmlFree(list->items);
416 list->items = NULL;
418 list->number = 0;
419 list->size = 0;
422 #endif /* XSLT_REFACTORED */
424 /************************************************************************
426 * Handling of XSLT stylesheets messages *
428 ************************************************************************/
431 * xsltMessage:
432 * @ctxt: an XSLT processing context
433 * @node: The current node
434 * @inst: The node containing the message instruction
436 * Process and xsl:message construct
438 void
439 xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
440 xmlGenericErrorFunc error = xsltGenericError;
441 void *errctx = xsltGenericErrorContext;
442 xmlChar *prop, *message;
443 int terminate = 0;
445 if ((ctxt == NULL) || (inst == NULL))
446 return;
448 if (ctxt->error != NULL) {
449 error = ctxt->error;
450 errctx = ctxt->errctx;
453 prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);
454 if (prop != NULL) {
455 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
456 terminate = 1;
457 } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
458 terminate = 0;
459 } else {
460 error(errctx,
461 "xsl:message : terminate expecting 'yes' or 'no'\n");
462 ctxt->state = XSLT_STATE_ERROR;
464 xmlFree(prop);
466 message = xsltEvalTemplateString(ctxt, node, inst);
467 if (message != NULL) {
468 int len = xmlStrlen(message);
470 error(errctx, "%s", (const char *)message);
471 if ((len > 0) && (message[len - 1] != '\n'))
472 error(errctx, "\n");
473 xmlFree(message);
475 if (terminate)
476 ctxt->state = XSLT_STATE_STOPPED;
479 /************************************************************************
481 * Handling of out of context errors *
483 ************************************************************************/
485 #define XSLT_GET_VAR_STR(msg, str) { \
486 int size; \
487 int chars; \
488 char *larger; \
489 va_list ap; \
491 str = (char *) xmlMalloc(150); \
492 if (str == NULL) \
493 return; \
495 size = 150; \
497 while (size < 64000) { \
498 va_start(ap, msg); \
499 chars = vsnprintf(str, size, msg, ap); \
500 va_end(ap); \
501 if ((chars > -1) && (chars < size)) \
502 break; \
503 if (chars > -1) \
504 size += chars + 1; \
505 else \
506 size += 100; \
507 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
508 xmlFree(str); \
509 return; \
511 str = larger; \
515 * xsltGenericErrorDefaultFunc:
516 * @ctx: an error context
517 * @msg: the message to display/transmit
518 * @...: extra parameters for the message display
520 * Default handler for out of context error messages.
522 static void
523 xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
524 va_list args;
526 if (xsltGenericErrorContext == NULL)
527 xsltGenericErrorContext = (void *) stderr;
529 va_start(args, msg);
530 vfprintf((FILE *)xsltGenericErrorContext, msg, args);
531 va_end(args);
534 xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
535 void *xsltGenericErrorContext = NULL;
539 * xsltSetGenericErrorFunc:
540 * @ctx: the new error handling context
541 * @handler: the new handler function
543 * Function to reset the handler and the error context for out of
544 * context error messages.
545 * This simply means that @handler will be called for subsequent
546 * error messages while not parsing nor validating. And @ctx will
547 * be passed as first argument to @handler
548 * One can simply force messages to be emitted to another FILE * than
549 * stderr by setting @ctx to this file handle and @handler to NULL.
551 void
552 xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
553 xsltGenericErrorContext = ctx;
554 if (handler != NULL)
555 xsltGenericError = handler;
556 else
557 xsltGenericError = xsltGenericErrorDefaultFunc;
561 * xsltGenericDebugDefaultFunc:
562 * @ctx: an error context
563 * @msg: the message to display/transmit
564 * @...: extra parameters for the message display
566 * Default handler for out of context error messages.
568 static void
569 xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
570 va_list args;
572 if (xsltGenericDebugContext == NULL)
573 return;
575 va_start(args, msg);
576 vfprintf((FILE *)xsltGenericDebugContext, msg, args);
577 va_end(args);
580 xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
581 void *xsltGenericDebugContext = NULL;
585 * xsltSetGenericDebugFunc:
586 * @ctx: the new error handling context
587 * @handler: the new handler function
589 * Function to reset the handler and the error context for out of
590 * context error messages.
591 * This simply means that @handler will be called for subsequent
592 * error messages while not parsing or validating. And @ctx will
593 * be passed as first argument to @handler
594 * One can simply force messages to be emitted to another FILE * than
595 * stderr by setting @ctx to this file handle and @handler to NULL.
597 void
598 xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
599 xsltGenericDebugContext = ctx;
600 if (handler != NULL)
601 xsltGenericDebug = handler;
602 else
603 xsltGenericDebug = xsltGenericDebugDefaultFunc;
607 * xsltPrintErrorContext:
608 * @ctxt: the transformation context
609 * @style: the stylesheet
610 * @node: the current node being processed
612 * Display the context of an error.
614 void
615 xsltPrintErrorContext(xsltTransformContextPtr ctxt,
616 xsltStylesheetPtr style, xmlNodePtr node) {
617 int line = 0;
618 const xmlChar *file = NULL;
619 const xmlChar *name = NULL;
620 const char *type = "error";
621 xmlGenericErrorFunc error = xsltGenericError;
622 void *errctx = xsltGenericErrorContext;
624 if (ctxt != NULL) {
625 ctxt->state = XSLT_STATE_ERROR;
626 if (ctxt->error != NULL) {
627 error = ctxt->error;
628 errctx = ctxt->errctx;
631 if ((node == NULL) && (ctxt != NULL))
632 node = ctxt->inst;
634 if (node != NULL) {
635 if ((node->type == XML_DOCUMENT_NODE) ||
636 (node->type == XML_HTML_DOCUMENT_NODE)) {
637 xmlDocPtr doc = (xmlDocPtr) node;
639 file = doc->URL;
640 } else {
641 line = xmlGetLineNo(node);
642 if ((node->doc != NULL) && (node->doc->URL != NULL))
643 file = node->doc->URL;
644 if (node->name != NULL)
645 name = node->name;
649 if (ctxt != NULL)
650 type = "runtime error";
651 else if (style != NULL) {
652 #ifdef XSLT_REFACTORED
653 if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)
654 type = "compilation warning";
655 else
656 type = "compilation error";
657 #else
658 type = "compilation error";
659 #endif
662 if ((file != NULL) && (line != 0) && (name != NULL))
663 error(errctx, "%s: file %s line %d element %s\n",
664 type, file, line, name);
665 else if ((file != NULL) && (name != NULL))
666 error(errctx, "%s: file %s element %s\n", type, file, name);
667 else if ((file != NULL) && (line != 0))
668 error(errctx, "%s: file %s line %d\n", type, file, line);
669 else if (file != NULL)
670 error(errctx, "%s: file %s\n", type, file);
671 else if (name != NULL)
672 error(errctx, "%s: element %s\n", type, name);
673 else
674 error(errctx, "%s\n", type);
678 * xsltSetTransformErrorFunc:
679 * @ctxt: the XSLT transformation context
680 * @ctx: the new error handling context
681 * @handler: the new handler function
683 * Function to reset the handler and the error context for out of
684 * context error messages specific to a given XSLT transromation.
686 * This simply means that @handler will be called for subsequent
687 * error messages while running the transformation.
689 void
690 xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,
691 void *ctx, xmlGenericErrorFunc handler)
693 ctxt->error = handler;
694 ctxt->errctx = ctx;
698 * xsltTransformError:
699 * @ctxt: an XSLT transformation context
700 * @style: the XSLT stylesheet used
701 * @node: the current node in the stylesheet
702 * @msg: the message to display/transmit
703 * @...: extra parameters for the message display
705 * Display and format an error messages, gives file, line, position and
706 * extra parameters, will use the specific transformation context if available
708 void
709 xsltTransformError(xsltTransformContextPtr ctxt,
710 xsltStylesheetPtr style,
711 xmlNodePtr node,
712 const char *msg, ...) {
713 xmlGenericErrorFunc error = xsltGenericError;
714 void *errctx = xsltGenericErrorContext;
715 char * str;
717 if (ctxt != NULL) {
718 ctxt->state = XSLT_STATE_ERROR;
719 if (ctxt->error != NULL) {
720 error = ctxt->error;
721 errctx = ctxt->errctx;
724 if ((node == NULL) && (ctxt != NULL))
725 node = ctxt->inst;
726 xsltPrintErrorContext(ctxt, style, node);
727 XSLT_GET_VAR_STR(msg, str);
728 error(errctx, "%s", str);
729 if (str != NULL)
730 xmlFree(str);
733 /************************************************************************
735 * QNames *
737 ************************************************************************/
740 * xsltSplitQName:
741 * @dict: a dictionary
742 * @name: the full QName
743 * @prefix: the return value
745 * Split QNames into prefix and local names, both allocated from a dictionary.
747 * Returns: the localname or NULL in case of error.
749 const xmlChar *
750 xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {
751 int len = 0;
752 const xmlChar *ret = NULL;
754 *prefix = NULL;
755 if ((name == NULL) || (dict == NULL)) return(NULL);
756 if (name[0] == ':')
757 return(xmlDictLookup(dict, name, -1));
758 while ((name[len] != 0) && (name[len] != ':')) len++;
759 if (name[len] == 0) return(xmlDictLookup(dict, name, -1));
760 *prefix = xmlDictLookup(dict, name, len);
761 ret = xmlDictLookup(dict, &name[len + 1], -1);
762 return(ret);
766 * xsltGetQNameURI:
767 * @node: the node holding the QName
768 * @name: pointer to the initial QName value
770 * This function analyzes @name, if the name contains a prefix,
771 * the function seaches the associated namespace in scope for it.
772 * It will also replace @name value with the NCName, the old value being
773 * freed.
774 * Errors in the prefix lookup are signalled by setting @name to NULL.
776 * NOTE: the namespace returned is a pointer to the place where it is
777 * defined and hence has the same lifespan as the document holding it.
779 * Returns the namespace URI if there is a prefix, or NULL if @name is
780 * not prefixed.
782 const xmlChar *
783 xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)
785 int len = 0;
786 xmlChar *qname;
787 xmlNsPtr ns;
789 if (name == NULL)
790 return(NULL);
791 qname = *name;
792 if ((qname == NULL) || (*qname == 0))
793 return(NULL);
794 if (node == NULL) {
795 xsltGenericError(xsltGenericErrorContext,
796 "QName: no element for namespace lookup %s\n",
797 qname);
798 xmlFree(qname);
799 *name = NULL;
800 return(NULL);
803 /* nasty but valid */
804 if (qname[0] == ':')
805 return(NULL);
808 * we are not trying to validate but just to cut, and yes it will
809 * work even if this is a set of UTF-8 encoded chars
811 while ((qname[len] != 0) && (qname[len] != ':'))
812 len++;
814 if (qname[len] == 0)
815 return(NULL);
818 * handle xml: separately, this one is magical
820 if ((qname[0] == 'x') && (qname[1] == 'm') &&
821 (qname[2] == 'l') && (qname[3] == ':')) {
822 if (qname[4] == 0)
823 return(NULL);
824 *name = xmlStrdup(&qname[4]);
825 xmlFree(qname);
826 return(XML_XML_NAMESPACE);
829 qname[len] = 0;
830 ns = xmlSearchNs(node->doc, node, qname);
831 if (ns == NULL) {
832 xsltGenericError(xsltGenericErrorContext,
833 "%s:%s : no namespace bound to prefix %s\n",
834 qname, &qname[len + 1], qname);
835 *name = NULL;
836 xmlFree(qname);
837 return(NULL);
839 *name = xmlStrdup(&qname[len + 1]);
840 xmlFree(qname);
841 return(ns->href);
845 * xsltGetQNameURI2:
846 * @style: stylesheet pointer
847 * @node: the node holding the QName
848 * @name: pointer to the initial QName value
850 * This function is similar to xsltGetQNameURI, but is used when
851 * @name is a dictionary entry.
853 * Returns the namespace URI if there is a prefix, or NULL if @name is
854 * not prefixed.
856 const xmlChar *
857 xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
858 const xmlChar **name) {
859 int len = 0;
860 xmlChar *qname;
861 xmlNsPtr ns;
863 if (name == NULL)
864 return(NULL);
865 qname = (xmlChar *)*name;
866 if ((qname == NULL) || (*qname == 0))
867 return(NULL);
868 if (node == NULL) {
869 xsltGenericError(xsltGenericErrorContext,
870 "QName: no element for namespace lookup %s\n",
871 qname);
872 *name = NULL;
873 return(NULL);
877 * we are not trying to validate but just to cut, and yes it will
878 * work even if this is a set of UTF-8 encoded chars
880 while ((qname[len] != 0) && (qname[len] != ':'))
881 len++;
883 if (qname[len] == 0)
884 return(NULL);
887 * handle xml: separately, this one is magical
889 if ((qname[0] == 'x') && (qname[1] == 'm') &&
890 (qname[2] == 'l') && (qname[3] == ':')) {
891 if (qname[4] == 0)
892 return(NULL);
893 *name = xmlDictLookup(style->dict, &qname[4], -1);
894 return(XML_XML_NAMESPACE);
897 qname = xmlStrndup(*name, len);
898 ns = xmlSearchNs(node->doc, node, qname);
899 if (ns == NULL) {
900 if (style) {
901 xsltTransformError(NULL, style, node,
902 "No namespace bound to prefix '%s'.\n",
903 qname);
904 style->errors++;
905 } else {
906 xsltGenericError(xsltGenericErrorContext,
907 "%s : no namespace bound to prefix %s\n",
908 *name, qname);
910 *name = NULL;
911 xmlFree(qname);
912 return(NULL);
914 *name = xmlDictLookup(style->dict, (*name)+len+1, -1);
915 xmlFree(qname);
916 return(ns->href);
919 /************************************************************************
921 * Sorting *
923 ************************************************************************/
926 * xsltDocumentSortFunction:
927 * @list: the node set
929 * reorder the current node list @list accordingly to the document order
930 * This function is slow, obsolete and should not be used anymore.
932 void
933 xsltDocumentSortFunction(xmlNodeSetPtr list) {
934 int i, j;
935 int len, tst;
936 xmlNodePtr node;
938 if (list == NULL)
939 return;
940 len = list->nodeNr;
941 if (len <= 1)
942 return;
943 /* TODO: sort is really not optimized, does it needs to ? */
944 for (i = 0;i < len -1;i++) {
945 for (j = i + 1; j < len; j++) {
946 tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
947 if (tst == -1) {
948 node = list->nodeTab[i];
949 list->nodeTab[i] = list->nodeTab[j];
950 list->nodeTab[j] = node;
957 * xsltComputeSortResult:
958 * @ctxt: a XSLT process context
959 * @sort: node list
961 * reorder the current node list accordingly to the set of sorting
962 * requirement provided by the array of nodes.
964 * Returns a ordered XPath nodeset or NULL in case of error.
966 xmlXPathObjectPtr *
967 xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
968 #ifdef XSLT_REFACTORED
969 xsltStyleItemSortPtr comp;
970 #else
971 xsltStylePreCompPtr comp;
972 #endif
973 xmlXPathObjectPtr *results = NULL;
974 xmlNodeSetPtr list = NULL;
975 xmlXPathObjectPtr res;
976 int len = 0;
977 int i;
978 xmlNodePtr oldNode;
979 xmlNodePtr oldInst;
980 int oldPos, oldSize ;
981 int oldNsNr;
982 xmlNsPtr *oldNamespaces;
984 comp = sort->psvi;
985 if (comp == NULL) {
986 xsltGenericError(xsltGenericErrorContext,
987 "xsl:sort : compilation failed\n");
988 return(NULL);
991 if ((comp->select == NULL) || (comp->comp == NULL))
992 return(NULL);
994 list = ctxt->nodeList;
995 if ((list == NULL) || (list->nodeNr <= 1))
996 return(NULL);
998 len = list->nodeNr;
1000 /* TODO: xsl:sort lang attribute */
1001 /* TODO: xsl:sort case-order attribute */
1004 results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
1005 if (results == NULL) {
1006 xsltGenericError(xsltGenericErrorContext,
1007 "xsltComputeSortResult: memory allocation failure\n");
1008 return(NULL);
1011 oldNode = ctxt->node;
1012 oldInst = ctxt->inst;
1013 oldPos = ctxt->xpathCtxt->proximityPosition;
1014 oldSize = ctxt->xpathCtxt->contextSize;
1015 oldNsNr = ctxt->xpathCtxt->nsNr;
1016 oldNamespaces = ctxt->xpathCtxt->namespaces;
1017 for (i = 0;i < len;i++) {
1018 ctxt->inst = sort;
1019 ctxt->xpathCtxt->contextSize = len;
1020 ctxt->xpathCtxt->proximityPosition = i + 1;
1021 ctxt->node = list->nodeTab[i];
1022 ctxt->xpathCtxt->node = ctxt->node;
1023 #ifdef XSLT_REFACTORED
1024 if (comp->inScopeNs != NULL) {
1025 ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
1026 ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
1027 } else {
1028 ctxt->xpathCtxt->namespaces = NULL;
1029 ctxt->xpathCtxt->nsNr = 0;
1031 #else
1032 ctxt->xpathCtxt->namespaces = comp->nsList;
1033 ctxt->xpathCtxt->nsNr = comp->nsNr;
1034 #endif
1035 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
1036 if (res != NULL) {
1037 if (res->type != XPATH_STRING)
1038 res = xmlXPathConvertString(res);
1039 if (comp->number)
1040 res = xmlXPathConvertNumber(res);
1041 res->index = i; /* Save original pos for dupl resolv */
1042 if (comp->number) {
1043 if (res->type == XPATH_NUMBER) {
1044 results[i] = res;
1045 } else {
1046 #ifdef WITH_XSLT_DEBUG_PROCESS
1047 xsltGenericDebug(xsltGenericDebugContext,
1048 "xsltComputeSortResult: select didn't evaluate to a number\n");
1049 #endif
1050 results[i] = NULL;
1052 } else {
1053 if (res->type == XPATH_STRING) {
1054 if (comp->locale != (xsltLocale)0) {
1055 xmlChar *str = res->stringval;
1056 res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, str);
1057 xmlFree(str);
1060 results[i] = res;
1061 } else {
1062 #ifdef WITH_XSLT_DEBUG_PROCESS
1063 xsltGenericDebug(xsltGenericDebugContext,
1064 "xsltComputeSortResult: select didn't evaluate to a string\n");
1065 #endif
1066 results[i] = NULL;
1069 } else {
1070 ctxt->state = XSLT_STATE_STOPPED;
1071 results[i] = NULL;
1074 ctxt->node = oldNode;
1075 ctxt->inst = oldInst;
1076 ctxt->xpathCtxt->contextSize = oldSize;
1077 ctxt->xpathCtxt->proximityPosition = oldPos;
1078 ctxt->xpathCtxt->nsNr = oldNsNr;
1079 ctxt->xpathCtxt->namespaces = oldNamespaces;
1081 return(results);
1085 * xsltDefaultSortFunction:
1086 * @ctxt: a XSLT process context
1087 * @sorts: array of sort nodes
1088 * @nbsorts: the number of sorts in the array
1090 * reorder the current node list accordingly to the set of sorting
1091 * requirement provided by the arry of nodes.
1093 void
1094 xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
1095 int nbsorts) {
1096 #ifdef XSLT_REFACTORED
1097 xsltStyleItemSortPtr comp;
1098 #else
1099 xsltStylePreCompPtr comp;
1100 #endif
1101 xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
1102 xmlXPathObjectPtr *results = NULL, *res;
1103 xmlNodeSetPtr list = NULL;
1104 int descending, number, desc, numb;
1105 int len = 0;
1106 int i, j, incr;
1107 int tst;
1108 int depth;
1109 xmlNodePtr node;
1110 xmlXPathObjectPtr tmp;
1111 int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
1113 if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
1114 (nbsorts >= XSLT_MAX_SORT))
1115 return;
1116 if (sorts[0] == NULL)
1117 return;
1118 comp = sorts[0]->psvi;
1119 if (comp == NULL)
1120 return;
1122 list = ctxt->nodeList;
1123 if ((list == NULL) || (list->nodeNr <= 1))
1124 return; /* nothing to do */
1126 for (j = 0; j < nbsorts; j++) {
1127 comp = sorts[j]->psvi;
1128 tempstype[j] = 0;
1129 if ((comp->stype == NULL) && (comp->has_stype != 0)) {
1130 comp->stype =
1131 xsltEvalAttrValueTemplate(ctxt, sorts[j],
1132 (const xmlChar *) "data-type",
1133 XSLT_NAMESPACE);
1134 if (comp->stype != NULL) {
1135 tempstype[j] = 1;
1136 if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
1137 comp->number = 0;
1138 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
1139 comp->number = 1;
1140 else {
1141 xsltTransformError(ctxt, NULL, sorts[j],
1142 "xsltDoSortFunction: no support for data-type = %s\n",
1143 comp->stype);
1144 comp->number = 0; /* use default */
1148 temporder[j] = 0;
1149 if ((comp->order == NULL) && (comp->has_order != 0)) {
1150 comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
1151 (const xmlChar *) "order",
1152 XSLT_NAMESPACE);
1153 if (comp->order != NULL) {
1154 temporder[j] = 1;
1155 if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
1156 comp->descending = 0;
1157 else if (xmlStrEqual(comp->order,
1158 (const xmlChar *) "descending"))
1159 comp->descending = 1;
1160 else {
1161 xsltTransformError(ctxt, NULL, sorts[j],
1162 "xsltDoSortFunction: invalid value %s for order\n",
1163 comp->order);
1164 comp->descending = 0; /* use default */
1170 len = list->nodeNr;
1172 resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
1173 for (i = 1;i < XSLT_MAX_SORT;i++)
1174 resultsTab[i] = NULL;
1176 results = resultsTab[0];
1178 comp = sorts[0]->psvi;
1179 descending = comp->descending;
1180 number = comp->number;
1181 if (results == NULL)
1182 return;
1184 /* Shell's sort of node-set */
1185 for (incr = len / 2; incr > 0; incr /= 2) {
1186 for (i = incr; i < len; i++) {
1187 j = i - incr;
1188 if (results[i] == NULL)
1189 continue;
1191 while (j >= 0) {
1192 if (results[j] == NULL)
1193 tst = 1;
1194 else {
1195 if (number) {
1196 /* We make NaN smaller than number in accordance
1197 with XSLT spec */
1198 if (xmlXPathIsNaN(results[j]->floatval)) {
1199 if (xmlXPathIsNaN(results[j + incr]->floatval))
1200 tst = 0;
1201 else
1202 tst = -1;
1203 } else if (xmlXPathIsNaN(results[j + incr]->floatval))
1204 tst = 1;
1205 else if (results[j]->floatval ==
1206 results[j + incr]->floatval)
1207 tst = 0;
1208 else if (results[j]->floatval >
1209 results[j + incr]->floatval)
1210 tst = 1;
1211 else tst = -1;
1212 } else if(comp->locale != (xsltLocale)0) {
1213 tst = xsltLocaleStrcmp(
1214 comp->locale,
1215 (xsltLocaleChar *) results[j]->stringval,
1216 (xsltLocaleChar *) results[j + incr]->stringval);
1217 } else {
1218 tst = xmlStrcmp(results[j]->stringval,
1219 results[j + incr]->stringval);
1221 if (descending)
1222 tst = -tst;
1224 if (tst == 0) {
1226 * Okay we need to use multi level sorts
1228 depth = 1;
1229 while (depth < nbsorts) {
1230 if (sorts[depth] == NULL)
1231 break;
1232 comp = sorts[depth]->psvi;
1233 if (comp == NULL)
1234 break;
1235 desc = comp->descending;
1236 numb = comp->number;
1239 * Compute the result of the next level for the
1240 * full set, this might be optimized ... or not
1242 if (resultsTab[depth] == NULL)
1243 resultsTab[depth] = xsltComputeSortResult(ctxt,
1244 sorts[depth]);
1245 res = resultsTab[depth];
1246 if (res == NULL)
1247 break;
1248 if (res[j] == NULL) {
1249 if (res[j+incr] != NULL)
1250 tst = 1;
1251 } else {
1252 if (numb) {
1253 /* We make NaN smaller than number in
1254 accordance with XSLT spec */
1255 if (xmlXPathIsNaN(res[j]->floatval)) {
1256 if (xmlXPathIsNaN(res[j +
1257 incr]->floatval))
1258 tst = 0;
1259 else
1260 tst = -1;
1261 } else if (xmlXPathIsNaN(res[j + incr]->
1262 floatval))
1263 tst = 1;
1264 else if (res[j]->floatval == res[j + incr]->
1265 floatval)
1266 tst = 0;
1267 else if (res[j]->floatval >
1268 res[j + incr]->floatval)
1269 tst = 1;
1270 else tst = -1;
1271 } else if(comp->locale != (xsltLocale)0) {
1272 tst = xsltLocaleStrcmp(
1273 comp->locale,
1274 (xsltLocaleChar *) res[j]->stringval,
1275 (xsltLocaleChar *) res[j + incr]->stringval);
1276 } else {
1277 tst = xmlStrcmp(res[j]->stringval,
1278 res[j + incr]->stringval);
1280 if (desc)
1281 tst = -tst;
1285 * if we still can't differenciate at this level
1286 * try one level deeper.
1288 if (tst != 0)
1289 break;
1290 depth++;
1293 if (tst == 0) {
1294 tst = results[j]->index > results[j + incr]->index;
1296 if (tst > 0) {
1297 tmp = results[j];
1298 results[j] = results[j + incr];
1299 results[j + incr] = tmp;
1300 node = list->nodeTab[j];
1301 list->nodeTab[j] = list->nodeTab[j + incr];
1302 list->nodeTab[j + incr] = node;
1303 depth = 1;
1304 while (depth < nbsorts) {
1305 if (sorts[depth] == NULL)
1306 break;
1307 if (resultsTab[depth] == NULL)
1308 break;
1309 res = resultsTab[depth];
1310 tmp = res[j];
1311 res[j] = res[j + incr];
1312 res[j + incr] = tmp;
1313 depth++;
1315 j -= incr;
1316 } else
1317 break;
1322 for (j = 0; j < nbsorts; j++) {
1323 comp = sorts[j]->psvi;
1324 if (tempstype[j] == 1) {
1325 /* The data-type needs to be recomputed each time */
1326 xmlFree((void *)(comp->stype));
1327 comp->stype = NULL;
1329 if (temporder[j] == 1) {
1330 /* The order needs to be recomputed each time */
1331 xmlFree((void *)(comp->order));
1332 comp->order = NULL;
1334 if (resultsTab[j] != NULL) {
1335 for (i = 0;i < len;i++)
1336 xmlXPathFreeObject(resultsTab[j][i]);
1337 xmlFree(resultsTab[j]);
1343 static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
1346 * xsltDoSortFunction:
1347 * @ctxt: a XSLT process context
1348 * @sorts: array of sort nodes
1349 * @nbsorts: the number of sorts in the array
1351 * reorder the current node list accordingly to the set of sorting
1352 * requirement provided by the arry of nodes.
1353 * This is a wrapper function, the actual function used is specified
1354 * using xsltSetCtxtSortFunc() to set the context specific sort function,
1355 * or xsltSetSortFunc() to set the global sort function.
1356 * If a sort function is set on the context, this will get called.
1357 * Otherwise the global sort function is called.
1359 void
1360 xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
1361 int nbsorts)
1363 if (ctxt->sortfunc != NULL)
1364 (ctxt->sortfunc)(ctxt, sorts, nbsorts);
1365 else if (xsltSortFunction != NULL)
1366 xsltSortFunction(ctxt, sorts, nbsorts);
1370 * xsltSetSortFunc:
1371 * @handler: the new handler function
1373 * Function to reset the global handler for XSLT sorting.
1374 * If the handler is NULL, the default sort function will be used.
1376 void
1377 xsltSetSortFunc(xsltSortFunc handler) {
1378 if (handler != NULL)
1379 xsltSortFunction = handler;
1380 else
1381 xsltSortFunction = xsltDefaultSortFunction;
1385 * xsltSetCtxtSortFunc:
1386 * @ctxt: a XSLT process context
1387 * @handler: the new handler function
1389 * Function to set the handler for XSLT sorting
1390 * for the specified context.
1391 * If the handler is NULL, then the global
1392 * sort function will be called
1394 void
1395 xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
1396 ctxt->sortfunc = handler;
1399 /************************************************************************
1401 * Parsing options *
1403 ************************************************************************/
1406 * xsltSetCtxtParseOptions:
1407 * @ctxt: a XSLT process context
1408 * @options: a combination of libxml2 xmlParserOption
1410 * Change the default parser option passed by the XSLT engine to the
1411 * parser when using document() loading.
1413 * Returns the previous options or -1 in case of error
1416 xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
1418 int oldopts;
1420 if (ctxt == NULL)
1421 return(-1);
1422 oldopts = ctxt->parserOptions;
1423 if (ctxt->xinclude)
1424 oldopts |= XML_PARSE_XINCLUDE;
1425 ctxt->parserOptions = options;
1426 if (options & XML_PARSE_XINCLUDE)
1427 ctxt->xinclude = 1;
1428 else
1429 ctxt->xinclude = 0;
1430 return(oldopts);
1433 /************************************************************************
1435 * Output *
1437 ************************************************************************/
1440 * xsltSaveResultTo:
1441 * @buf: an output buffer
1442 * @result: the result xmlDocPtr
1443 * @style: the stylesheet
1445 * Save the result @result obtained by applying the @style stylesheet
1446 * to an I/O output channel @buf
1448 * Returns the number of byte written or -1 in case of failure.
1451 xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
1452 xsltStylesheetPtr style) {
1453 const xmlChar *encoding;
1454 int base;
1455 const xmlChar *method;
1456 int indent;
1458 if ((buf == NULL) || (result == NULL) || (style == NULL))
1459 return(-1);
1460 if ((result->children == NULL) ||
1461 ((result->children->type == XML_DTD_NODE) &&
1462 (result->children->next == NULL)))
1463 return(0);
1465 if ((style->methodURI != NULL) &&
1466 ((style->method == NULL) ||
1467 (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
1468 xsltGenericError(xsltGenericErrorContext,
1469 "xsltSaveResultTo : unknown ouput method\n");
1470 return(-1);
1473 base = buf->written;
1475 XSLT_GET_IMPORT_PTR(method, style, method)
1476 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1477 XSLT_GET_IMPORT_INT(indent, style, indent);
1479 if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
1480 method = (const xmlChar *) "html";
1482 if ((method != NULL) &&
1483 (xmlStrEqual(method, (const xmlChar *) "html"))) {
1484 if (encoding != NULL) {
1485 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1486 } else {
1487 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1489 if (indent == -1)
1490 indent = 1;
1491 htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
1492 indent);
1493 xmlOutputBufferFlush(buf);
1494 } else if ((method != NULL) &&
1495 (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
1496 if (encoding != NULL) {
1497 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1498 } else {
1499 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1501 htmlDocContentDumpOutput(buf, result, (const char *) encoding);
1502 xmlOutputBufferFlush(buf);
1503 } else if ((method != NULL) &&
1504 (xmlStrEqual(method, (const xmlChar *) "text"))) {
1505 xmlNodePtr cur;
1507 cur = result->children;
1508 while (cur != NULL) {
1509 if (cur->type == XML_TEXT_NODE)
1510 xmlOutputBufferWriteString(buf, (const char *) cur->content);
1513 * Skip to next node
1515 if (cur->children != NULL) {
1516 if ((cur->children->type != XML_ENTITY_DECL) &&
1517 (cur->children->type != XML_ENTITY_REF_NODE) &&
1518 (cur->children->type != XML_ENTITY_NODE)) {
1519 cur = cur->children;
1520 continue;
1523 if (cur->next != NULL) {
1524 cur = cur->next;
1525 continue;
1528 do {
1529 cur = cur->parent;
1530 if (cur == NULL)
1531 break;
1532 if (cur == (xmlNodePtr) style->doc) {
1533 cur = NULL;
1534 break;
1536 if (cur->next != NULL) {
1537 cur = cur->next;
1538 break;
1540 } while (cur != NULL);
1542 xmlOutputBufferFlush(buf);
1543 } else {
1544 int omitXmlDecl;
1545 int standalone;
1547 XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
1548 XSLT_GET_IMPORT_INT(standalone, style, standalone);
1550 if (omitXmlDecl != 1) {
1551 xmlOutputBufferWriteString(buf, "<?xml version=");
1552 if (result->version != NULL) {
1553 xmlOutputBufferWriteString(buf, "\"");
1554 xmlOutputBufferWriteString(buf, (const char *)result->version);
1555 xmlOutputBufferWriteString(buf, "\"");
1556 } else
1557 xmlOutputBufferWriteString(buf, "\"1.0\"");
1558 if (encoding == NULL) {
1559 if (result->encoding != NULL)
1560 encoding = result->encoding;
1561 else if (result->charset != XML_CHAR_ENCODING_UTF8)
1562 encoding = (const xmlChar *)
1563 xmlGetCharEncodingName((xmlCharEncoding)
1564 result->charset);
1566 if (encoding != NULL) {
1567 xmlOutputBufferWriteString(buf, " encoding=");
1568 xmlOutputBufferWriteString(buf, "\"");
1569 xmlOutputBufferWriteString(buf, (const char *) encoding);
1570 xmlOutputBufferWriteString(buf, "\"");
1572 switch (standalone) {
1573 case 0:
1574 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
1575 break;
1576 case 1:
1577 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
1578 break;
1579 default:
1580 break;
1582 xmlOutputBufferWriteString(buf, "?>\n");
1584 if (result->children != NULL) {
1585 xmlNodePtr child = result->children;
1587 while (child != NULL) {
1588 xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
1589 (const char *) encoding);
1590 if (indent && ((child->type == XML_DTD_NODE) ||
1591 ((child->type == XML_COMMENT_NODE) &&
1592 (child->next != NULL))))
1593 xmlOutputBufferWriteString(buf, "\n");
1594 child = child->next;
1596 if (indent)
1597 xmlOutputBufferWriteString(buf, "\n");
1599 xmlOutputBufferFlush(buf);
1601 return(buf->written - base);
1605 * xsltSaveResultToFilename:
1606 * @URL: a filename or URL
1607 * @result: the result xmlDocPtr
1608 * @style: the stylesheet
1609 * @compression: the compression factor (0 - 9 included)
1611 * Save the result @result obtained by applying the @style stylesheet
1612 * to a file or @URL
1614 * Returns the number of byte written or -1 in case of failure.
1617 xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
1618 xsltStylesheetPtr style, int compression) {
1619 xmlOutputBufferPtr buf;
1620 const xmlChar *encoding;
1621 int ret;
1623 if ((URL == NULL) || (result == NULL) || (style == NULL))
1624 return(-1);
1625 if (result->children == NULL)
1626 return(0);
1628 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1629 if (encoding != NULL) {
1630 xmlCharEncodingHandlerPtr encoder;
1632 encoder = xmlFindCharEncodingHandler((char *)encoding);
1633 if ((encoder != NULL) &&
1634 (xmlStrEqual((const xmlChar *)encoder->name,
1635 (const xmlChar *) "UTF-8")))
1636 encoder = NULL;
1637 buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
1638 } else {
1639 buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
1641 if (buf == NULL)
1642 return(-1);
1643 xsltSaveResultTo(buf, result, style);
1644 ret = xmlOutputBufferClose(buf);
1645 return(ret);
1649 * xsltSaveResultToFile:
1650 * @file: a FILE * I/O
1651 * @result: the result xmlDocPtr
1652 * @style: the stylesheet
1654 * Save the result @result obtained by applying the @style stylesheet
1655 * to an open FILE * I/O.
1656 * This does not close the FILE @file
1658 * Returns the number of bytes written or -1 in case of failure.
1661 xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
1662 xmlOutputBufferPtr buf;
1663 const xmlChar *encoding;
1664 int ret;
1666 if ((file == NULL) || (result == NULL) || (style == NULL))
1667 return(-1);
1668 if (result->children == NULL)
1669 return(0);
1671 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1672 if (encoding != NULL) {
1673 xmlCharEncodingHandlerPtr encoder;
1675 encoder = xmlFindCharEncodingHandler((char *)encoding);
1676 if ((encoder != NULL) &&
1677 (xmlStrEqual((const xmlChar *)encoder->name,
1678 (const xmlChar *) "UTF-8")))
1679 encoder = NULL;
1680 buf = xmlOutputBufferCreateFile(file, encoder);
1681 } else {
1682 buf = xmlOutputBufferCreateFile(file, NULL);
1685 if (buf == NULL)
1686 return(-1);
1687 xsltSaveResultTo(buf, result, style);
1688 ret = xmlOutputBufferClose(buf);
1689 return(ret);
1693 * xsltSaveResultToFd:
1694 * @fd: a file descriptor
1695 * @result: the result xmlDocPtr
1696 * @style: the stylesheet
1698 * Save the result @result obtained by applying the @style stylesheet
1699 * to an open file descriptor
1700 * This does not close the descriptor.
1702 * Returns the number of bytes written or -1 in case of failure.
1705 xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
1706 xmlOutputBufferPtr buf;
1707 const xmlChar *encoding;
1708 int ret;
1710 if ((fd < 0) || (result == NULL) || (style == NULL))
1711 return(-1);
1712 if (result->children == NULL)
1713 return(0);
1715 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1716 if (encoding != NULL) {
1717 xmlCharEncodingHandlerPtr encoder;
1719 encoder = xmlFindCharEncodingHandler((char *)encoding);
1720 if ((encoder != NULL) &&
1721 (xmlStrEqual((const xmlChar *)encoder->name,
1722 (const xmlChar *) "UTF-8")))
1723 encoder = NULL;
1724 buf = xmlOutputBufferCreateFd(fd, encoder);
1725 } else {
1726 buf = xmlOutputBufferCreateFd(fd, NULL);
1728 if (buf == NULL)
1729 return(-1);
1730 xsltSaveResultTo(buf, result, style);
1731 ret = xmlOutputBufferClose(buf);
1732 return(ret);
1736 * xsltSaveResultToString:
1737 * @doc_txt_ptr: Memory pointer for allocated XML text
1738 * @doc_txt_len: Length of the generated XML text
1739 * @result: the result xmlDocPtr
1740 * @style: the stylesheet
1742 * Save the result @result obtained by applying the @style stylesheet
1743 * to a new allocated string.
1745 * Returns 0 in case of success and -1 in case of error
1748 xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len,
1749 xmlDocPtr result, xsltStylesheetPtr style) {
1750 xmlOutputBufferPtr buf;
1751 const xmlChar *encoding;
1753 *doc_txt_ptr = NULL;
1754 *doc_txt_len = 0;
1755 if (result->children == NULL)
1756 return(0);
1758 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1759 if (encoding != NULL) {
1760 xmlCharEncodingHandlerPtr encoder;
1762 encoder = xmlFindCharEncodingHandler((char *)encoding);
1763 if ((encoder != NULL) &&
1764 (xmlStrEqual((const xmlChar *)encoder->name,
1765 (const xmlChar *) "UTF-8")))
1766 encoder = NULL;
1767 buf = xmlAllocOutputBuffer(encoder);
1768 } else {
1769 buf = xmlAllocOutputBuffer(NULL);
1771 if (buf == NULL)
1772 return(-1);
1773 xsltSaveResultTo(buf, result, style);
1774 #ifdef LIBXML2_NEW_BUFFER
1775 if (buf->conv != NULL) {
1776 *doc_txt_len = xmlBufUse(buf->conv);
1777 *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->conv), *doc_txt_len);
1778 } else {
1779 *doc_txt_len = xmlBufUse(buf->buffer);
1780 *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), *doc_txt_len);
1782 #else
1783 if (buf->conv != NULL) {
1784 *doc_txt_len = buf->conv->use;
1785 *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
1786 } else {
1787 *doc_txt_len = buf->buffer->use;
1788 *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
1790 #endif
1791 (void)xmlOutputBufferClose(buf);
1792 return 0;
1795 /************************************************************************
1797 * Generating profiling informations *
1799 ************************************************************************/
1801 static long calibration = -1;
1804 * xsltCalibrateTimestamps:
1806 * Used for to calibrate the xsltTimestamp() function
1807 * Should work if launched at startup and we don't loose our quantum :-)
1809 * Returns the number of milliseconds used by xsltTimestamp()
1811 static long
1812 xsltCalibrateTimestamps(void) {
1813 register int i;
1815 for (i = 0;i < 999;i++)
1816 xsltTimestamp();
1817 return(xsltTimestamp() / 1000);
1821 * xsltCalibrateAdjust:
1822 * @delta: a negative dealy value found
1824 * Used for to correct the calibration for xsltTimestamp()
1826 void
1827 xsltCalibrateAdjust(long delta) {
1828 calibration += delta;
1832 * xsltTimestamp:
1834 * Used for gathering profiling data
1836 * Returns the number of tenth of milliseconds since the beginning of the
1837 * profiling
1839 long
1840 xsltTimestamp(void)
1842 #ifdef XSLT_WIN32_PERFORMANCE_COUNTER
1843 BOOL ok;
1844 LARGE_INTEGER performanceCount;
1845 LARGE_INTEGER performanceFrequency;
1846 LONGLONG quadCount;
1847 double seconds;
1848 static LONGLONG startupQuadCount = 0;
1849 static LONGLONG startupQuadFreq = 0;
1851 ok = QueryPerformanceCounter(&performanceCount);
1852 if (!ok)
1853 return 0;
1854 quadCount = performanceCount.QuadPart;
1855 if (calibration < 0) {
1856 calibration = 0;
1857 ok = QueryPerformanceFrequency(&performanceFrequency);
1858 if (!ok)
1859 return 0;
1860 startupQuadFreq = performanceFrequency.QuadPart;
1861 startupQuadCount = quadCount;
1862 return (0);
1864 if (startupQuadFreq == 0)
1865 return 0;
1866 seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
1867 return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
1869 #else /* XSLT_WIN32_PERFORMANCE_COUNTER */
1870 #ifdef HAVE_CLOCK_GETTIME
1871 # if defined(CLOCK_MONOTONIC)
1872 # define XSLT_CLOCK CLOCK_MONOTONIC
1873 # elif defined(CLOCK_HIGHRES)
1874 # define XSLT_CLOCK CLOCK_HIGHRES
1875 # else
1876 # define XSLT_CLOCK CLOCK_REALTIME
1877 # endif
1878 static struct timespec startup;
1879 struct timespec cur;
1880 long tics;
1882 if (calibration < 0) {
1883 clock_gettime(XSLT_CLOCK, &startup);
1884 calibration = 0;
1885 calibration = xsltCalibrateTimestamps();
1886 clock_gettime(XSLT_CLOCK, &startup);
1887 return (0);
1890 clock_gettime(XSLT_CLOCK, &cur);
1891 tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1892 tics += (cur.tv_nsec - startup.tv_nsec) /
1893 (1000000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1895 tics -= calibration;
1896 return(tics);
1898 #elif HAVE_GETTIMEOFDAY
1899 static struct timeval startup;
1900 struct timeval cur;
1901 long tics;
1903 if (calibration < 0) {
1904 gettimeofday(&startup, NULL);
1905 calibration = 0;
1906 calibration = xsltCalibrateTimestamps();
1907 gettimeofday(&startup, NULL);
1908 return (0);
1911 gettimeofday(&cur, NULL);
1912 tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1913 tics += (cur.tv_usec - startup.tv_usec) /
1914 (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1916 tics -= calibration;
1917 return(tics);
1918 #else
1920 /* Neither gettimeofday() nor Win32 performance counter available */
1922 return (0);
1924 #endif /* HAVE_GETTIMEOFDAY */
1925 #endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
1928 static char *
1929 pretty_templ_match(xsltTemplatePtr templ) {
1930 static char dst[1001];
1931 char *src = (char *)templ->match;
1932 int i=0,j;
1934 /* strip white spaces */
1935 for (j=0; i<1000 && src[j]; i++,j++) {
1936 for(;src[j]==' ';j++);
1937 dst[i]=src[j];
1939 if(i<998 && templ->mode) {
1940 /* append [mode] */
1941 dst[i++]='[';
1942 src=(char *)templ->mode;
1943 for (j=0; i<999 && src[j]; i++,j++) {
1944 dst[i]=src[j];
1946 dst[i++]=']';
1948 dst[i]='\0';
1949 return dst;
1952 #define MAX_TEMPLATES 10000
1955 * xsltSaveProfiling:
1956 * @ctxt: an XSLT context
1957 * @output: a FILE * for saving the informations
1959 * Save the profiling informations on @output
1961 void
1962 xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
1963 int nb, i,j,k,l;
1964 int max;
1965 int total;
1966 long totalt;
1967 xsltTemplatePtr *templates;
1968 xsltStylesheetPtr style;
1969 xsltTemplatePtr templ1,templ2;
1970 int *childt;
1972 if ((output == NULL) || (ctxt == NULL))
1973 return;
1974 if (ctxt->profile == 0)
1975 return;
1977 nb = 0;
1978 max = MAX_TEMPLATES;
1979 templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
1980 if (templates == NULL)
1981 return;
1983 style = ctxt->style;
1984 while (style != NULL) {
1985 templ1 = style->templates;
1986 while (templ1 != NULL) {
1987 if (nb >= max)
1988 break;
1990 if (templ1->nbCalls > 0)
1991 templates[nb++] = templ1;
1992 templ1 = templ1->next;
1995 style = xsltNextImport(style);
1998 for (i = 0;i < nb -1;i++) {
1999 for (j = i + 1; j < nb; j++) {
2000 if ((templates[i]->time <= templates[j]->time) ||
2001 ((templates[i]->time == templates[j]->time) &&
2002 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2003 templ1 = templates[j];
2004 templates[j] = templates[i];
2005 templates[i] = templ1;
2011 /* print flat profile */
2013 fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n",
2014 "number", "match", "name", "mode");
2015 total = 0;
2016 totalt = 0;
2017 for (i = 0;i < nb;i++) {
2018 templ1 = templates[i];
2019 fprintf(output, "%5d ", i);
2020 if (templ1->match != NULL) {
2021 if (xmlStrlen(templ1->match) > 20)
2022 fprintf(output, "%s\n%26s", templ1->match, "");
2023 else
2024 fprintf(output, "%20s", templ1->match);
2025 } else {
2026 fprintf(output, "%20s", "");
2028 if (templ1->name != NULL) {
2029 if (xmlStrlen(templ1->name) > 20)
2030 fprintf(output, "%s\n%46s", templ1->name, "");
2031 else
2032 fprintf(output, "%20s", templ1->name);
2033 } else {
2034 fprintf(output, "%20s", "");
2036 if (templ1->mode != NULL) {
2037 if (xmlStrlen(templ1->mode) > 10)
2038 fprintf(output, "%s\n%56s", templ1->mode, "");
2039 else
2040 fprintf(output, "%10s", templ1->mode);
2041 } else {
2042 fprintf(output, "%10s", "");
2044 fprintf(output, " %6d", templ1->nbCalls);
2045 fprintf(output, " %6ld %6ld\n", templ1->time,
2046 templ1->time / templ1->nbCalls);
2047 total += templ1->nbCalls;
2048 totalt += templ1->time;
2050 fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
2053 /* print call graph */
2055 childt = xmlMalloc((nb + 1) * sizeof(int));
2056 if (childt == NULL)
2057 return;
2059 /* precalculate children times */
2060 for (i = 0; i < nb; i++) {
2061 templ1 = templates[i];
2063 childt[i] = 0;
2064 for (k = 0; k < nb; k++) {
2065 templ2 = templates[k];
2066 for (l = 0; l < templ2->templNr; l++) {
2067 if (templ2->templCalledTab[l] == templ1) {
2068 childt[i] +=templ2->time;
2073 childt[i] = 0;
2075 fprintf(output, "\nindex %% time self children called name\n");
2077 for (i = 0; i < nb; i++) {
2078 char ix_str[20], timep_str[20], times_str[20], timec_str[20], called_str[20];
2079 int t;
2081 templ1 = templates[i];
2082 /* callers */
2083 for (j = 0; j < templ1->templNr; j++) {
2084 templ2 = templ1->templCalledTab[j];
2085 for (k = 0; k < nb; k++) {
2086 if (templates[k] == templ2)
2087 break;
2089 t=templ2?templ2->time:totalt;
2090 sprintf(times_str,"%8.3f",(float)t/XSLT_TIMESTAMP_TICS_PER_SEC);
2091 sprintf(timec_str,"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC);
2092 sprintf(called_str,"%6d/%d",
2093 templ1->templCountTab[j], /* number of times caller calls 'this' */
2094 templ1->nbCalls); /* total number of calls to 'this' */
2096 fprintf(output, " %-8s %-8s %-12s %s [%d]\n",
2097 times_str,timec_str,called_str,
2098 (templ2?(templ2->name?(char *)templ2->name:pretty_templ_match(templ2)):"-"),k);
2100 /* this */
2101 sprintf(ix_str,"[%d]",i);
2102 sprintf(timep_str,"%6.2f",(float)templ1->time*100.0/totalt);
2103 sprintf(times_str,"%8.3f",(float)templ1->time/XSLT_TIMESTAMP_TICS_PER_SEC);
2104 sprintf(timec_str,"%8.3f",(float)childt[i]/XSLT_TIMESTAMP_TICS_PER_SEC);
2105 fprintf(output, "%-5s %-6s %-8s %-8s %6d %s [%d]\n",
2106 ix_str, timep_str,times_str,timec_str,
2107 templ1->nbCalls,
2108 templ1->name?(char *)templ1->name:pretty_templ_match(templ1),i);
2109 /* callees
2110 * - go over templates[0..nb] and their templCalledTab[]
2111 * - print those where we in the the call-stack
2113 total = 0;
2114 for (k = 0; k < nb; k++) {
2115 templ2 = templates[k];
2116 for (l = 0; l < templ2->templNr; l++) {
2117 if (templ2->templCalledTab[l] == templ1) {
2118 total+=templ2->templCountTab[l];
2122 for (k = 0; k < nb; k++) {
2123 templ2 = templates[k];
2124 for (l = 0; l < templ2->templNr; l++) {
2125 if (templ2->templCalledTab[l] == templ1) {
2126 sprintf(times_str,"%8.3f",(float)templ2->time/XSLT_TIMESTAMP_TICS_PER_SEC);
2127 sprintf(timec_str,"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC);
2128 sprintf(called_str,"%6d/%d",
2129 templ2->templCountTab[l], /* number of times 'this' calls callee */
2130 total); /* total number of calls from 'this' */
2131 fprintf(output, " %-8s %-8s %-12s %s [%d]\n",
2132 times_str,timec_str,called_str,
2133 templ2->name?(char *)templ2->name:pretty_templ_match(templ2),k);
2137 fprintf(output, "-----------------------------------------------\n");
2140 fprintf(output, "\f\nIndex by function name\n");
2141 for (i = 0; i < nb; i++) {
2142 templ1 = templates[i];
2143 fprintf(output, "[%d] %s (%s:%d)\n",
2144 i, templ1->name?(char *)templ1->name:pretty_templ_match(templ1),
2145 templ1->style->doc->URL,templ1->elem->line);
2148 fprintf(output, "\f\n");
2149 xmlFree(childt);
2151 xmlFree(templates);
2154 /************************************************************************
2156 * Fetching profiling informations *
2158 ************************************************************************/
2161 * xsltGetProfileInformation:
2162 * @ctxt: a transformation context
2164 * This function should be called after the transformation completed
2165 * to extract template processing profiling informations if availble.
2166 * The informations are returned as an XML document tree like
2167 * <?xml version="1.0"?>
2168 * <profile>
2169 * <template rank="1" match="*" name=""
2170 * mode="" calls="6" time="48" average="8"/>
2171 * <template rank="2" match="item2|item3" name=""
2172 * mode="" calls="10" time="30" average="3"/>
2173 * <template rank="3" match="item1" name=""
2174 * mode="" calls="5" time="17" average="3"/>
2175 * </profile>
2176 * The caller will need to free up the returned tree with xmlFreeDoc()
2178 * Returns the xmlDocPtr corresponding to the result or NULL if not available.
2181 xmlDocPtr
2182 xsltGetProfileInformation(xsltTransformContextPtr ctxt)
2184 xmlDocPtr ret = NULL;
2185 xmlNodePtr root, child;
2186 char buf[100];
2188 xsltStylesheetPtr style;
2189 xsltTemplatePtr *templates;
2190 xsltTemplatePtr templ;
2191 int nb = 0, max = 0, i, j;
2193 if (!ctxt)
2194 return NULL;
2196 if (!ctxt->profile)
2197 return NULL;
2199 nb = 0;
2200 max = 10000;
2201 templates =
2202 (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
2203 if (templates == NULL)
2204 return NULL;
2207 * collect all the templates in an array
2209 style = ctxt->style;
2210 while (style != NULL) {
2211 templ = style->templates;
2212 while (templ != NULL) {
2213 if (nb >= max)
2214 break;
2216 if (templ->nbCalls > 0)
2217 templates[nb++] = templ;
2218 templ = templ->next;
2221 style = (xsltStylesheetPtr) xsltNextImport(style);
2225 * Sort the array by time spent
2227 for (i = 0; i < nb - 1; i++) {
2228 for (j = i + 1; j < nb; j++) {
2229 if ((templates[i]->time <= templates[j]->time) ||
2230 ((templates[i]->time == templates[j]->time) &&
2231 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2232 templ = templates[j];
2233 templates[j] = templates[i];
2234 templates[i] = templ;
2240 * Generate a document corresponding to the results.
2242 ret = xmlNewDoc(BAD_CAST "1.0");
2243 root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
2244 xmlDocSetRootElement(ret, root);
2246 for (i = 0; i < nb; i++) {
2247 child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
2248 sprintf(buf, "%d", i + 1);
2249 xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
2250 xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
2251 xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
2252 xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
2254 sprintf(buf, "%d", templates[i]->nbCalls);
2255 xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
2257 sprintf(buf, "%ld", templates[i]->time);
2258 xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
2260 sprintf(buf, "%ld", templates[i]->time / templates[i]->nbCalls);
2261 xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
2264 xmlFree(templates);
2266 return ret;
2269 /************************************************************************
2271 * Hooks for libxml2 XPath *
2273 ************************************************************************/
2276 * xsltXPathCompileFlags:
2277 * @style: the stylesheet
2278 * @str: the XPath expression
2279 * @flags: extra compilation flags to pass down to libxml2 XPath
2281 * Compile an XPath expression
2283 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2284 * the caller has to free the object.
2286 xmlXPathCompExprPtr
2287 xsltXPathCompileFlags(xsltStylesheetPtr style, const xmlChar *str, int flags) {
2288 xmlXPathContextPtr xpathCtxt;
2289 xmlXPathCompExprPtr ret;
2291 if (style != NULL) {
2292 #ifdef XSLT_REFACTORED_XPATHCOMP
2293 if (XSLT_CCTXT(style)) {
2295 * Proposed by Jerome Pesenti
2296 * --------------------------
2297 * For better efficiency we'll reuse the compilation
2298 * context's XPath context. For the common stylesheet using
2299 * XPath expressions this will reduce compilation time to
2300 * about 50%.
2302 * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
2304 xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
2305 xpathCtxt->doc = style->doc;
2306 } else
2307 xpathCtxt = xmlXPathNewContext(style->doc);
2308 #else
2309 xpathCtxt = xmlXPathNewContext(style->doc);
2310 #endif
2311 if (xpathCtxt == NULL)
2312 return NULL;
2313 xpathCtxt->dict = style->dict;
2314 } else {
2315 xpathCtxt = xmlXPathNewContext(NULL);
2316 if (xpathCtxt == NULL)
2317 return NULL;
2319 xpathCtxt->flags = flags;
2322 * Compile the expression.
2324 ret = xmlXPathCtxtCompile(xpathCtxt, str);
2326 #ifdef XSLT_REFACTORED_XPATHCOMP
2327 if ((style == NULL) || (! XSLT_CCTXT(style))) {
2328 xmlXPathFreeContext(xpathCtxt);
2330 #else
2331 xmlXPathFreeContext(xpathCtxt);
2332 #endif
2334 * TODO: there is a lot of optimizations which should be possible
2335 * like variable slot precomputations, function precomputations, etc.
2338 return(ret);
2342 * xsltXPathCompile:
2343 * @style: the stylesheet
2344 * @str: the XPath expression
2346 * Compile an XPath expression
2348 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2349 * the caller has to free the object.
2351 xmlXPathCompExprPtr
2352 xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
2353 return(xsltXPathCompileFlags(style, str, 0));
2356 /************************************************************************
2358 * Hooks for the debugger *
2360 ************************************************************************/
2363 * There is currently only 3 debugging callback defined
2364 * Debugger callbacks are disabled by default
2366 #define XSLT_CALLBACK_NUMBER 3
2368 typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
2369 typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
2370 struct _xsltDebuggerCallbacks {
2371 xsltHandleDebuggerCallback handler;
2372 xsltAddCallCallback add;
2373 xsltDropCallCallback drop;
2376 static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
2377 NULL, /* handler */
2378 NULL, /* add */
2379 NULL /* drop */
2382 int xslDebugStatus;
2385 * xsltSetDebuggerStatus:
2386 * @value : the value to be set
2388 * This function sets the value of xslDebugStatus.
2390 void
2391 xsltSetDebuggerStatus(int value)
2393 xslDebugStatus = value;
2397 * xsltGetDebuggerStatus:
2399 * Get xslDebugStatus.
2401 * Returns the value of xslDebugStatus.
2404 xsltGetDebuggerStatus(void)
2406 return(xslDebugStatus);
2410 * xsltSetDebuggerCallbacks:
2411 * @no : number of callbacks
2412 * @block : the block of callbacks
2414 * This function allow to plug a debugger into the XSLT library
2415 * @block points to a block of memory containing the address of @no
2416 * callback routines.
2418 * Returns 0 in case of success and -1 in case of error
2421 xsltSetDebuggerCallbacks(int no, void *block)
2423 xsltDebuggerCallbacksPtr callbacks;
2425 if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
2426 return(-1);
2428 callbacks = (xsltDebuggerCallbacksPtr) block;
2429 xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
2430 xsltDebuggerCurrentCallbacks.add = callbacks->add;
2431 xsltDebuggerCurrentCallbacks.drop = callbacks->drop;
2432 return(0);
2436 * xslHandleDebugger:
2437 * @cur : source node being executed
2438 * @node : data node being processed
2439 * @templ : temlate that applies to node
2440 * @ctxt : the xslt transform context
2442 * If either cur or node are a breakpoint, or xslDebugStatus in state
2443 * where debugging must occcur at this time then transfer control
2444 * to the xslDebugBreak function
2446 void
2447 xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
2448 xsltTransformContextPtr ctxt)
2450 if (xsltDebuggerCurrentCallbacks.handler != NULL)
2451 xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
2455 * xslAddCall:
2456 * @templ : current template being applied
2457 * @source : the source node being processed
2459 * Add template "call" to call stack
2460 * Returns : 1 on sucess 0 otherwise an error may be printed if
2461 * WITH_XSLT_DEBUG_BREAKPOINTS is defined
2464 xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
2466 if (xsltDebuggerCurrentCallbacks.add != NULL)
2467 return(xsltDebuggerCurrentCallbacks.add(templ, source));
2468 return(0);
2472 * xslDropCall:
2474 * Drop the topmost item off the call stack
2476 void
2477 xslDropCall(void)
2479 if (xsltDebuggerCurrentCallbacks.drop != NULL)
2480 xsltDebuggerCurrentCallbacks.drop();