VirtualBox

source: vbox/trunk/src/libs/libxslt-1.1.22/libxslt/xsltutils.c@ 13005

最後變更 在這個檔案從13005是 7296,由 vboxsync 提交於 17 年 前

Added libxslt-1.1.22 sources.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Date Revision Author Id
檔案大小: 58.7 KB
 
1/*
2 * xsltutils.c: Utilities for the XSL Transformation 1.0 engine
3 *
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * [email protected]
10 */
11
12#define IN_LIBXSLT
13#include "libxslt.h"
14
15#ifndef XSLT_NEED_TRIO
16#include <stdio.h>
17#else
18#include <trio.h>
19#endif
20
21#include <string.h>
22#ifdef HAVE_SYS_TIME_H
23#include <sys/time.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_STDLIB_H
29#include <stdlib.h>
30#endif
31#include <stdarg.h>
32
33#include <libxml/xmlmemory.h>
34#include <libxml/tree.h>
35#include <libxml/HTMLtree.h>
36#include <libxml/xmlerror.h>
37#include <libxml/xmlIO.h>
38#include "xsltutils.h"
39#include "templates.h"
40#include "xsltInternals.h"
41#include "imports.h"
42#include "transform.h"
43
44/* gettimeofday on Windows ??? */
45#if defined(WIN32) && !defined(__CYGWIN__)
46#ifdef _MSC_VER
47#include <winsock2.h>
48#pragma comment(lib, "ws2_32.lib")
49#define gettimeofday(p1,p2)
50#define HAVE_GETTIMEOFDAY
51#define XSLT_WIN32_PERFORMANCE_COUNTER
52#endif /* _MS_VER */
53#endif /* WIN32 */
54
55/************************************************************************
56 * *
57 * Convenience function *
58 * *
59 ************************************************************************/
60
61/**
62 * xsltGetCNsProp:
63 * @style: the stylesheet
64 * @node: the node
65 * @name: the attribute name
66 * @nameSpace: the URI of the namespace
67 *
68 * Similar to xmlGetNsProp() but with a slightly different semantic
69 *
70 * Search and get the value of an attribute associated to a node
71 * This attribute has to be anchored in the namespace specified,
72 * or has no namespace and the element is in that namespace.
73 *
74 * This does the entity substitution.
75 * This function looks in DTD attribute declaration for #FIXED or
76 * default declaration values unless DTD use has been turned off.
77 *
78 * Returns the attribute value or NULL if not found. The string is allocated
79 * in the stylesheet dictionary.
80 */
81const xmlChar *
82xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,
83 const xmlChar *name, const xmlChar *nameSpace) {
84 xmlAttrPtr prop;
85 xmlDocPtr doc;
86 xmlNsPtr ns;
87 xmlChar *tmp;
88 const xmlChar *ret;
89
90 if ((node == NULL) || (style == NULL) || (style->dict == NULL))
91 return(NULL);
92
93 prop = node->properties;
94 if (nameSpace == NULL) {
95 return xmlGetProp(node, name);
96 }
97 while (prop != NULL) {
98 /*
99 * One need to have
100 * - same attribute names
101 * - and the attribute carrying that namespace
102 */
103 if ((xmlStrEqual(prop->name, name)) &&
104 (((prop->ns == NULL) && (node->ns != NULL) &&
105 (xmlStrEqual(node->ns->href, nameSpace))) ||
106 ((prop->ns != NULL) &&
107 (xmlStrEqual(prop->ns->href, nameSpace))))) {
108
109 tmp = xmlNodeListGetString(node->doc, prop->children, 1);
110 if (tmp == NULL)
111 ret = xmlDictLookup(style->dict, BAD_CAST "", 0);
112 else {
113 ret = xmlDictLookup(style->dict, tmp, -1);
114 xmlFree(tmp);
115 }
116 return ret;
117 }
118 prop = prop->next;
119 }
120 tmp = NULL;
121 /*
122 * Check if there is a default declaration in the internal
123 * or external subsets
124 */
125 doc = node->doc;
126 if (doc != NULL) {
127 if (doc->intSubset != NULL) {
128 xmlAttributePtr attrDecl;
129
130 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
131 if ((attrDecl == NULL) && (doc->extSubset != NULL))
132 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
133
134 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
135 /*
136 * The DTD declaration only allows a prefix search
137 */
138 ns = xmlSearchNs(doc, node, attrDecl->prefix);
139 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
140 return(xmlDictLookup(style->dict,
141 attrDecl->defaultValue, -1));
142 }
143 }
144 }
145 return(NULL);
146}
147/**
148 * xsltGetNsProp:
149 * @node: the node
150 * @name: the attribute name
151 * @nameSpace: the URI of the namespace
152 *
153 * Similar to xmlGetNsProp() but with a slightly different semantic
154 *
155 * Search and get the value of an attribute associated to a node
156 * This attribute has to be anchored in the namespace specified,
157 * or has no namespace and the element is in that namespace.
158 *
159 * This does the entity substitution.
160 * This function looks in DTD attribute declaration for #FIXED or
161 * default declaration values unless DTD use has been turned off.
162 *
163 * Returns the attribute value or NULL if not found.
164 * It's up to the caller to free the memory.
165 */
166xmlChar *
167xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
168 xmlAttrPtr prop;
169 xmlDocPtr doc;
170 xmlNsPtr ns;
171
172 if (node == NULL)
173 return(NULL);
174
175 prop = node->properties;
176 /*
177 * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former
178 * is not namespace-aware and will return an attribute with equal
179 * name regardless of its namespace.
180 * Example:
181 * <xsl:element foo:name="myName"/>
182 * So this would return "myName" even if an attribute @name
183 * in the XSLT was requested.
184 */
185 if (nameSpace == NULL)
186 return(xmlGetProp(node, name));
187 while (prop != NULL) {
188 /*
189 * One need to have
190 * - same attribute names
191 * - and the attribute carrying that namespace
192 */
193 if ((xmlStrEqual(prop->name, name)) &&
194 (((prop->ns == NULL) && (node->ns != NULL) &&
195 (xmlStrEqual(node->ns->href, nameSpace))) ||
196 ((prop->ns != NULL) &&
197 (xmlStrEqual(prop->ns->href, nameSpace))))) {
198 xmlChar *ret;
199
200 ret = xmlNodeListGetString(node->doc, prop->children, 1);
201 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
202 return(ret);
203 }
204 prop = prop->next;
205 }
206
207 /*
208 * Check if there is a default declaration in the internal
209 * or external subsets
210 */
211 doc = node->doc;
212 if (doc != NULL) {
213 if (doc->intSubset != NULL) {
214 xmlAttributePtr attrDecl;
215
216 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
217 if ((attrDecl == NULL) && (doc->extSubset != NULL))
218 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
219
220 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
221 /*
222 * The DTD declaration only allows a prefix search
223 */
224 ns = xmlSearchNs(doc, node, attrDecl->prefix);
225 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
226 return(xmlStrdup(attrDecl->defaultValue));
227 }
228 }
229 }
230 return(NULL);
231}
232
233/**
234 * xsltGetUTF8Char:
235 * @utf: a sequence of UTF-8 encoded bytes
236 * @len: a pointer to @bytes len
237 *
238 * Read one UTF8 Char from @utf
239 * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately
240 * and use the original API
241 *
242 * Returns the char value or -1 in case of error and update @len with the
243 * number of bytes used
244 */
245int
246xsltGetUTF8Char(const unsigned char *utf, int *len) {
247 unsigned int c;
248
249 if (utf == NULL)
250 goto error;
251 if (len == NULL)
252 goto error;
253 if (*len < 1)
254 goto error;
255
256 c = utf[0];
257 if (c & 0x80) {
258 if (*len < 2)
259 goto error;
260 if ((utf[1] & 0xc0) != 0x80)
261 goto error;
262 if ((c & 0xe0) == 0xe0) {
263 if (*len < 3)
264 goto error;
265 if ((utf[2] & 0xc0) != 0x80)
266 goto error;
267 if ((c & 0xf0) == 0xf0) {
268 if (*len < 4)
269 goto error;
270 if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
271 goto error;
272 *len = 4;
273 /* 4-byte code */
274 c = (utf[0] & 0x7) << 18;
275 c |= (utf[1] & 0x3f) << 12;
276 c |= (utf[2] & 0x3f) << 6;
277 c |= utf[3] & 0x3f;
278 } else {
279 /* 3-byte code */
280 *len = 3;
281 c = (utf[0] & 0xf) << 12;
282 c |= (utf[1] & 0x3f) << 6;
283 c |= utf[2] & 0x3f;
284 }
285 } else {
286 /* 2-byte code */
287 *len = 2;
288 c = (utf[0] & 0x1f) << 6;
289 c |= utf[1] & 0x3f;
290 }
291 } else {
292 /* 1-byte code */
293 *len = 1;
294 }
295 return(c);
296
297error:
298 if (len != NULL)
299 *len = 0;
300 return(-1);
301}
302
303#ifdef XSLT_REFACTORED
304
305/**
306 * xsltPointerListAddSize:
307 * @list: the pointer list structure
308 * @item: the item to be stored
309 * @initialSize: the initial size of the list
310 *
311 * Adds an item to the list.
312 *
313 * Returns the position of the added item in the list or
314 * -1 in case of an error.
315 */
316int
317xsltPointerListAddSize(xsltPointerListPtr list,
318 void *item,
319 int initialSize)
320{
321 if (list->items == NULL) {
322 if (initialSize <= 0)
323 initialSize = 1;
324 list->items = (void **) xmlMalloc(
325 initialSize * sizeof(void *));
326 if (list->items == NULL) {
327 xsltGenericError(xsltGenericErrorContext,
328 "xsltPointerListAddSize: memory allocation failure.\n");
329 return(-1);
330 }
331 list->number = 0;
332 list->size = initialSize;
333 } else if (list->size <= list->number) {
334 list->size *= 2;
335 list->items = (void **) xmlRealloc(list->items,
336 list->size * sizeof(void *));
337 if (list->items == NULL) {
338 xsltGenericError(xsltGenericErrorContext,
339 "xsltPointerListAddSize: memory re-allocation failure.\n");
340 list->size = 0;
341 return(-1);
342 }
343 }
344 list->items[list->number++] = item;
345 return(0);
346}
347
348/**
349 * xsltPointerListCreate:
350 * @initialSize: the initial size for the list
351 *
352 * Creates an xsltPointerList structure.
353 *
354 * Returns a xsltPointerList structure or NULL in case of an error.
355 */
356xsltPointerListPtr
357xsltPointerListCreate(int initialSize)
358{
359 xsltPointerListPtr ret;
360
361 ret = xmlMalloc(sizeof(xsltPointerList));
362 if (ret == NULL) {
363 xsltGenericError(xsltGenericErrorContext,
364 "xsltPointerListCreate: memory allocation failure.\n");
365 return (NULL);
366 }
367 memset(ret, 0, sizeof(xsltPointerList));
368 if (initialSize > 0) {
369 xsltPointerListAddSize(ret, NULL, initialSize);
370 ret->number = 0;
371 }
372 return (ret);
373}
374
375/**
376 * xsltPointerListFree:
377 * @list: pointer to the list to be freed
378 *
379 * Frees the xsltPointerList structure. This does not free
380 * the content of the list.
381 */
382void
383xsltPointerListFree(xsltPointerListPtr list)
384{
385 if (list == NULL)
386 return;
387 if (list->items != NULL)
388 xmlFree(list->items);
389 xmlFree(list);
390}
391
392/**
393 * xsltPointerListClear:
394 * @list: pointer to the list to be cleared
395 *
396 * Resets the list, but does not free the allocated array
397 * and does not free the content of the list.
398 */
399void
400xsltPointerListClear(xsltPointerListPtr list)
401{
402 if (list->items != NULL) {
403 xmlFree(list->items);
404 list->items = NULL;
405 }
406 list->number = 0;
407 list->size = 0;
408}
409
410#endif /* XSLT_REFACTORED */
411
412/************************************************************************
413 * *
414 * Handling of XSLT stylesheets messages *
415 * *
416 ************************************************************************/
417
418/**
419 * xsltMessage:
420 * @ctxt: an XSLT processing context
421 * @node: The current node
422 * @inst: The node containing the message instruction
423 *
424 * Process and xsl:message construct
425 */
426void
427xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
428 xmlGenericErrorFunc error = xsltGenericError;
429 void *errctx = xsltGenericErrorContext;
430 xmlChar *prop, *message;
431 int terminate = 0;
432
433 if ((ctxt == NULL) || (inst == NULL))
434 return;
435
436 if (ctxt->error != NULL) {
437 error = ctxt->error;
438 errctx = ctxt->errctx;
439 }
440
441 prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);
442 if (prop != NULL) {
443 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
444 terminate = 1;
445 } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
446 terminate = 0;
447 } else {
448 error(errctx,
449 "xsl:message : terminate expecting 'yes' or 'no'\n");
450 ctxt->state = XSLT_STATE_ERROR;
451 }
452 xmlFree(prop);
453 }
454 message = xsltEvalTemplateString(ctxt, node, inst);
455 if (message != NULL) {
456 int len = xmlStrlen(message);
457
458 error(errctx, "%s", (const char *)message);
459 if ((len > 0) && (message[len - 1] != '\n'))
460 error(errctx, "\n");
461 xmlFree(message);
462 }
463 if (terminate)
464 ctxt->state = XSLT_STATE_STOPPED;
465}
466
467/************************************************************************
468 * *
469 * Handling of out of context errors *
470 * *
471 ************************************************************************/
472
473#define XSLT_GET_VAR_STR(msg, str) { \
474 int size; \
475 int chars; \
476 char *larger; \
477 va_list ap; \
478 \
479 str = (char *) xmlMalloc(150); \
480 if (str == NULL) \
481 return; \
482 \
483 size = 150; \
484 \
485 while (1) { \
486 va_start(ap, msg); \
487 chars = vsnprintf(str, size, msg, ap); \
488 va_end(ap); \
489 if ((chars > -1) && (chars < size)) \
490 break; \
491 if (chars > -1) \
492 size += chars + 1; \
493 else \
494 size += 100; \
495 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
496 xmlFree(str); \
497 return; \
498 } \
499 str = larger; \
500 } \
501}
502/**
503 * xsltGenericErrorDefaultFunc:
504 * @ctx: an error context
505 * @msg: the message to display/transmit
506 * @...: extra parameters for the message display
507 *
508 * Default handler for out of context error messages.
509 */
510static void
511xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
512 va_list args;
513
514 if (xsltGenericErrorContext == NULL)
515 xsltGenericErrorContext = (void *) stderr;
516
517 va_start(args, msg);
518 vfprintf((FILE *)xsltGenericErrorContext, msg, args);
519 va_end(args);
520}
521
522xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
523void *xsltGenericErrorContext = NULL;
524
525
526/**
527 * xsltSetGenericErrorFunc:
528 * @ctx: the new error handling context
529 * @handler: the new handler function
530 *
531 * Function to reset the handler and the error context for out of
532 * context error messages.
533 * This simply means that @handler will be called for subsequent
534 * error messages while not parsing nor validating. And @ctx will
535 * be passed as first argument to @handler
536 * One can simply force messages to be emitted to another FILE * than
537 * stderr by setting @ctx to this file handle and @handler to NULL.
538 */
539void
540xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
541 xsltGenericErrorContext = ctx;
542 if (handler != NULL)
543 xsltGenericError = handler;
544 else
545 xsltGenericError = xsltGenericErrorDefaultFunc;
546}
547
548/**
549 * xsltGenericDebugDefaultFunc:
550 * @ctx: an error context
551 * @msg: the message to display/transmit
552 * @...: extra parameters for the message display
553 *
554 * Default handler for out of context error messages.
555 */
556static void
557xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
558 va_list args;
559
560 if (xsltGenericDebugContext == NULL)
561 return;
562
563 va_start(args, msg);
564 vfprintf((FILE *)xsltGenericDebugContext, msg, args);
565 va_end(args);
566}
567
568xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
569void *xsltGenericDebugContext = NULL;
570
571
572/**
573 * xsltSetGenericDebugFunc:
574 * @ctx: the new error handling context
575 * @handler: the new handler function
576 *
577 * Function to reset the handler and the error context for out of
578 * context error messages.
579 * This simply means that @handler will be called for subsequent
580 * error messages while not parsing or validating. And @ctx will
581 * be passed as first argument to @handler
582 * One can simply force messages to be emitted to another FILE * than
583 * stderr by setting @ctx to this file handle and @handler to NULL.
584 */
585void
586xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
587 xsltGenericDebugContext = ctx;
588 if (handler != NULL)
589 xsltGenericDebug = handler;
590 else
591 xsltGenericDebug = xsltGenericDebugDefaultFunc;
592}
593
594/**
595 * xsltPrintErrorContext:
596 * @ctxt: the transformation context
597 * @style: the stylesheet
598 * @node: the current node being processed
599 *
600 * Display the context of an error.
601 */
602void
603xsltPrintErrorContext(xsltTransformContextPtr ctxt,
604 xsltStylesheetPtr style, xmlNodePtr node) {
605 int line = 0;
606 const xmlChar *file = NULL;
607 const xmlChar *name = NULL;
608 const char *type = "error";
609 xmlGenericErrorFunc error = xsltGenericError;
610 void *errctx = xsltGenericErrorContext;
611
612 if (ctxt != NULL) {
613 ctxt->state = XSLT_STATE_ERROR;
614 if (ctxt->error != NULL) {
615 error = ctxt->error;
616 errctx = ctxt->errctx;
617 }
618 }
619 if ((node == NULL) && (ctxt != NULL))
620 node = ctxt->inst;
621
622 if (node != NULL) {
623 if ((node->type == XML_DOCUMENT_NODE) ||
624 (node->type == XML_HTML_DOCUMENT_NODE)) {
625 xmlDocPtr doc = (xmlDocPtr) node;
626
627 file = doc->URL;
628 } else {
629 line = xmlGetLineNo(node);
630 if ((node->doc != NULL) && (node->doc->URL != NULL))
631 file = node->doc->URL;
632 if (node->name != NULL)
633 name = node->name;
634 }
635 }
636
637 if (ctxt != NULL)
638 type = "runtime error";
639 else if (style != NULL) {
640#ifdef XSLT_REFACTORED
641 if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)
642 type = "compilation warning";
643 else
644 type = "compilation error";
645#else
646 type = "compilation error";
647#endif
648 }
649
650 if ((file != NULL) && (line != 0) && (name != NULL))
651 error(errctx, "%s: file %s line %d element %s\n",
652 type, file, line, name);
653 else if ((file != NULL) && (name != NULL))
654 error(errctx, "%s: file %s element %s\n", type, file, name);
655 else if ((file != NULL) && (line != 0))
656 error(errctx, "%s: file %s line %d\n", type, file, line);
657 else if (file != NULL)
658 error(errctx, "%s: file %s\n", type, file);
659 else if (name != NULL)
660 error(errctx, "%s: element %s\n", type, name);
661 else
662 error(errctx, "%s\n", type);
663}
664
665/**
666 * xsltSetTransformErrorFunc:
667 * @ctxt: the XSLT transformation context
668 * @ctx: the new error handling context
669 * @handler: the new handler function
670 *
671 * Function to reset the handler and the error context for out of
672 * context error messages specific to a given XSLT transromation.
673 *
674 * This simply means that @handler will be called for subsequent
675 * error messages while running the transformation.
676 */
677void
678xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,
679 void *ctx, xmlGenericErrorFunc handler)
680{
681 ctxt->error = handler;
682 ctxt->errctx = ctx;
683}
684
685/**
686 * xsltTransformError:
687 * @ctxt: an XSLT transformation context
688 * @style: the XSLT stylesheet used
689 * @node: the current node in the stylesheet
690 * @msg: the message to display/transmit
691 * @...: extra parameters for the message display
692 *
693 * Display and format an error messages, gives file, line, position and
694 * extra parameters, will use the specific transformation context if available
695 */
696void
697xsltTransformError(xsltTransformContextPtr ctxt,
698 xsltStylesheetPtr style,
699 xmlNodePtr node,
700 const char *msg, ...) {
701 xmlGenericErrorFunc error = xsltGenericError;
702 void *errctx = xsltGenericErrorContext;
703 char * str;
704
705 if (ctxt != NULL) {
706 ctxt->state = XSLT_STATE_ERROR;
707 if (ctxt->error != NULL) {
708 error = ctxt->error;
709 errctx = ctxt->errctx;
710 }
711 }
712 if ((node == NULL) && (ctxt != NULL))
713 node = ctxt->inst;
714 xsltPrintErrorContext(ctxt, style, node);
715 XSLT_GET_VAR_STR(msg, str);
716 error(errctx, "%s", str);
717 if (str != NULL)
718 xmlFree(str);
719}
720
721/************************************************************************
722 * *
723 * QNames *
724 * *
725 ************************************************************************/
726
727/**
728 * xsltSplitQName:
729 * @dict: a dictionary
730 * @name: the full QName
731 * @prefix: the return value
732 *
733 * Split QNames into prefix and local names, both allocated from a dictionary.
734 *
735 * Returns: the localname or NULL in case of error.
736 */
737const xmlChar *
738xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {
739 int len = 0;
740 const xmlChar *ret = NULL;
741
742 *prefix = NULL;
743 if ((name == NULL) || (dict == NULL)) return(NULL);
744 if (name[0] == ':')
745 return(xmlDictLookup(dict, name, -1));
746 while ((name[len] != 0) && (name[len] != ':')) len++;
747 if (name[len] == 0) return(xmlDictLookup(dict, name, -1));
748 *prefix = xmlDictLookup(dict, name, len);
749 ret = xmlDictLookup(dict, &name[len + 1], -1);
750 return(ret);
751}
752
753/**
754 * xsltGetQNameURI:
755 * @node: the node holding the QName
756 * @name: pointer to the initial QName value
757 *
758 * This function analyzes @name, if the name contains a prefix,
759 * the function seaches the associated namespace in scope for it.
760 * It will also replace @name value with the NCName, the old value being
761 * freed.
762 * Errors in the prefix lookup are signalled by setting @name to NULL.
763 *
764 * NOTE: the namespace returned is a pointer to the place where it is
765 * defined and hence has the same lifespan as the document holding it.
766 *
767 * Returns the namespace URI if there is a prefix, or NULL if @name is
768 * not prefixed.
769 */
770const xmlChar *
771xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)
772{
773 int len = 0;
774 xmlChar *qname;
775 xmlNsPtr ns;
776
777 if (name == NULL)
778 return(NULL);
779 qname = *name;
780 if ((qname == NULL) || (*qname == 0))
781 return(NULL);
782 if (node == NULL) {
783 xsltGenericError(xsltGenericErrorContext,
784 "QName: no element for namespace lookup %s\n",
785 qname);
786 xmlFree(qname);
787 *name = NULL;
788 return(NULL);
789 }
790
791 /* nasty but valid */
792 if (qname[0] == ':')
793 return(NULL);
794
795 /*
796 * we are not trying to validate but just to cut, and yes it will
797 * work even if this is a set of UTF-8 encoded chars
798 */
799 while ((qname[len] != 0) && (qname[len] != ':'))
800 len++;
801
802 if (qname[len] == 0)
803 return(NULL);
804
805 /*
806 * handle xml: separately, this one is magical
807 */
808 if ((qname[0] == 'x') && (qname[1] == 'm') &&
809 (qname[2] == 'l') && (qname[3] == ':')) {
810 if (qname[4] == 0)
811 return(NULL);
812 *name = xmlStrdup(&qname[4]);
813 xmlFree(qname);
814 return(XML_XML_NAMESPACE);
815 }
816
817 qname[len] = 0;
818 ns = xmlSearchNs(node->doc, node, qname);
819 if (ns == NULL) {
820 xsltGenericError(xsltGenericErrorContext,
821 "%s:%s : no namespace bound to prefix %s\n",
822 qname, &qname[len + 1], qname);
823 *name = NULL;
824 xmlFree(qname);
825 return(NULL);
826 }
827 *name = xmlStrdup(&qname[len + 1]);
828 xmlFree(qname);
829 return(ns->href);
830}
831
832/**
833 * xsltGetQNameURI2:
834 * @style: stylesheet pointer
835 * @node: the node holding the QName
836 * @name: pointer to the initial QName value
837 *
838 * This function is similar to xsltGetQNameURI, but is used when
839 * @name is a dictionary entry.
840 *
841 * Returns the namespace URI if there is a prefix, or NULL if @name is
842 * not prefixed.
843 */
844const xmlChar *
845xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
846 const xmlChar **name) {
847 int len = 0;
848 xmlChar *qname;
849 xmlNsPtr ns;
850
851 if (name == NULL)
852 return(NULL);
853 qname = (xmlChar *)*name;
854 if ((qname == NULL) || (*qname == 0))
855 return(NULL);
856 if (node == NULL) {
857 xsltGenericError(xsltGenericErrorContext,
858 "QName: no element for namespace lookup %s\n",
859 qname);
860 *name = NULL;
861 return(NULL);
862 }
863
864 /*
865 * we are not trying to validate but just to cut, and yes it will
866 * work even if this is a set of UTF-8 encoded chars
867 */
868 while ((qname[len] != 0) && (qname[len] != ':'))
869 len++;
870
871 if (qname[len] == 0)
872 return(NULL);
873
874 /*
875 * handle xml: separately, this one is magical
876 */
877 if ((qname[0] == 'x') && (qname[1] == 'm') &&
878 (qname[2] == 'l') && (qname[3] == ':')) {
879 if (qname[4] == 0)
880 return(NULL);
881 *name = xmlDictLookup(style->dict, &qname[4], -1);
882 return(XML_XML_NAMESPACE);
883 }
884
885 qname = xmlStrndup(*name, len);
886 ns = xmlSearchNs(node->doc, node, qname);
887 if (ns == NULL) {
888 if (style) {
889 xsltTransformError(NULL, style, node,
890 "No namespace bound to prefix '%s'.\n",
891 qname);
892 style->errors++;
893 } else {
894 xsltGenericError(xsltGenericErrorContext,
895 "%s : no namespace bound to prefix %s\n",
896 *name, qname);
897 }
898 *name = NULL;
899 xmlFree(qname);
900 return(NULL);
901 }
902 *name = xmlDictLookup(style->dict, (*name)+len+1, -1);
903 xmlFree(qname);
904 return(ns->href);
905}
906
907/************************************************************************
908 * *
909 * Sorting *
910 * *
911 ************************************************************************/
912
913/**
914 * xsltDocumentSortFunction:
915 * @list: the node set
916 *
917 * reorder the current node list @list accordingly to the document order
918 * This function is slow, obsolete and should not be used anymore.
919 */
920void
921xsltDocumentSortFunction(xmlNodeSetPtr list) {
922 int i, j;
923 int len, tst;
924 xmlNodePtr node;
925
926 if (list == NULL)
927 return;
928 len = list->nodeNr;
929 if (len <= 1)
930 return;
931 /* TODO: sort is really not optimized, does it needs to ? */
932 for (i = 0;i < len -1;i++) {
933 for (j = i + 1; j < len; j++) {
934 tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
935 if (tst == -1) {
936 node = list->nodeTab[i];
937 list->nodeTab[i] = list->nodeTab[j];
938 list->nodeTab[j] = node;
939 }
940 }
941 }
942}
943
944/**
945 * xsltComputeSortResult:
946 * @ctxt: a XSLT process context
947 * @sort: node list
948 *
949 * reorder the current node list accordingly to the set of sorting
950 * requirement provided by the array of nodes.
951 *
952 * Returns a ordered XPath nodeset or NULL in case of error.
953 */
954xmlXPathObjectPtr *
955xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
956#ifdef XSLT_REFACTORED
957 xsltStyleItemSortPtr comp;
958#else
959 xsltStylePreCompPtr comp;
960#endif
961 xmlXPathObjectPtr *results = NULL;
962 xmlNodeSetPtr list = NULL;
963 xmlXPathObjectPtr res;
964 int len = 0;
965 int i;
966 xmlNodePtr oldNode;
967 xmlNodePtr oldInst;
968 int oldPos, oldSize ;
969 int oldNsNr;
970 xmlNsPtr *oldNamespaces;
971
972 comp = sort->psvi;
973 if (comp == NULL) {
974 xsltGenericError(xsltGenericErrorContext,
975 "xsl:sort : compilation failed\n");
976 return(NULL);
977 }
978
979 if ((comp->select == NULL) || (comp->comp == NULL))
980 return(NULL);
981
982 list = ctxt->nodeList;
983 if ((list == NULL) || (list->nodeNr <= 1))
984 return(NULL);
985
986 len = list->nodeNr;
987
988 /* TODO: xsl:sort lang attribute */
989 /* TODO: xsl:sort case-order attribute */
990
991
992 results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
993 if (results == NULL) {
994 xsltGenericError(xsltGenericErrorContext,
995 "xsltComputeSortResult: memory allocation failure\n");
996 return(NULL);
997 }
998
999 oldNode = ctxt->node;
1000 oldInst = ctxt->inst;
1001 oldPos = ctxt->xpathCtxt->proximityPosition;
1002 oldSize = ctxt->xpathCtxt->contextSize;
1003 oldNsNr = ctxt->xpathCtxt->nsNr;
1004 oldNamespaces = ctxt->xpathCtxt->namespaces;
1005 for (i = 0;i < len;i++) {
1006 ctxt->inst = sort;
1007 ctxt->xpathCtxt->contextSize = len;
1008 ctxt->xpathCtxt->proximityPosition = i + 1;
1009 ctxt->node = list->nodeTab[i];
1010 ctxt->xpathCtxt->node = ctxt->node;
1011#ifdef XSLT_REFACTORED
1012 if (comp->inScopeNs != NULL) {
1013 ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
1014 ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
1015 } else {
1016 ctxt->xpathCtxt->namespaces = NULL;
1017 ctxt->xpathCtxt->nsNr = 0;
1018 }
1019#else
1020 ctxt->xpathCtxt->namespaces = comp->nsList;
1021 ctxt->xpathCtxt->nsNr = comp->nsNr;
1022#endif
1023 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
1024 if (res != NULL) {
1025 if (res->type != XPATH_STRING)
1026 res = xmlXPathConvertString(res);
1027 if (comp->number)
1028 res = xmlXPathConvertNumber(res);
1029 res->index = i; /* Save original pos for dupl resolv */
1030 if (comp->number) {
1031 if (res->type == XPATH_NUMBER) {
1032 results[i] = res;
1033 } else {
1034#ifdef WITH_XSLT_DEBUG_PROCESS
1035 xsltGenericDebug(xsltGenericDebugContext,
1036 "xsltComputeSortResult: select didn't evaluate to a number\n");
1037#endif
1038 results[i] = NULL;
1039 }
1040 } else {
1041 if (res->type == XPATH_STRING) {
1042 results[i] = res;
1043 } else {
1044#ifdef WITH_XSLT_DEBUG_PROCESS
1045 xsltGenericDebug(xsltGenericDebugContext,
1046 "xsltComputeSortResult: select didn't evaluate to a string\n");
1047#endif
1048 results[i] = NULL;
1049 }
1050 }
1051 } else {
1052 ctxt->state = XSLT_STATE_STOPPED;
1053 results[i] = NULL;
1054 }
1055 }
1056 ctxt->node = oldNode;
1057 ctxt->inst = oldInst;
1058 ctxt->xpathCtxt->contextSize = oldSize;
1059 ctxt->xpathCtxt->proximityPosition = oldPos;
1060 ctxt->xpathCtxt->nsNr = oldNsNr;
1061 ctxt->xpathCtxt->namespaces = oldNamespaces;
1062
1063 return(results);
1064}
1065
1066/**
1067 * xsltDefaultSortFunction:
1068 * @ctxt: a XSLT process context
1069 * @sorts: array of sort nodes
1070 * @nbsorts: the number of sorts in the array
1071 *
1072 * reorder the current node list accordingly to the set of sorting
1073 * requirement provided by the arry of nodes.
1074 */
1075void
1076xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
1077 int nbsorts) {
1078#ifdef XSLT_REFACTORED
1079 xsltStyleItemSortPtr comp;
1080#else
1081 xsltStylePreCompPtr comp;
1082#endif
1083 xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
1084 xmlXPathObjectPtr *results = NULL, *res;
1085 xmlNodeSetPtr list = NULL;
1086 int descending, number, desc, numb;
1087 int len = 0;
1088 int i, j, incr;
1089 int tst;
1090 int depth;
1091 xmlNodePtr node;
1092 xmlXPathObjectPtr tmp;
1093 int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
1094
1095 if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
1096 (nbsorts >= XSLT_MAX_SORT))
1097 return;
1098 if (sorts[0] == NULL)
1099 return;
1100 comp = sorts[0]->psvi;
1101 if (comp == NULL)
1102 return;
1103
1104 list = ctxt->nodeList;
1105 if ((list == NULL) || (list->nodeNr <= 1))
1106 return; /* nothing to do */
1107
1108 for (j = 0; j < nbsorts; j++) {
1109 comp = sorts[j]->psvi;
1110 tempstype[j] = 0;
1111 if ((comp->stype == NULL) && (comp->has_stype != 0)) {
1112 comp->stype =
1113 xsltEvalAttrValueTemplate(ctxt, sorts[j],
1114 (const xmlChar *) "data-type",
1115 XSLT_NAMESPACE);
1116 if (comp->stype != NULL) {
1117 tempstype[j] = 1;
1118 if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
1119 comp->number = 0;
1120 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
1121 comp->number = 1;
1122 else {
1123 xsltTransformError(ctxt, NULL, sorts[j],
1124 "xsltDoSortFunction: no support for data-type = %s\n",
1125 comp->stype);
1126 comp->number = 0; /* use default */
1127 }
1128 }
1129 }
1130 temporder[j] = 0;
1131 if ((comp->order == NULL) && (comp->has_order != 0)) {
1132 comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
1133 (const xmlChar *) "order",
1134 XSLT_NAMESPACE);
1135 if (comp->order != NULL) {
1136 temporder[j] = 1;
1137 if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
1138 comp->descending = 0;
1139 else if (xmlStrEqual(comp->order,
1140 (const xmlChar *) "descending"))
1141 comp->descending = 1;
1142 else {
1143 xsltTransformError(ctxt, NULL, sorts[j],
1144 "xsltDoSortFunction: invalid value %s for order\n",
1145 comp->order);
1146 comp->descending = 0; /* use default */
1147 }
1148 }
1149 }
1150 }
1151
1152 len = list->nodeNr;
1153
1154 resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
1155 for (i = 1;i < XSLT_MAX_SORT;i++)
1156 resultsTab[i] = NULL;
1157
1158 results = resultsTab[0];
1159
1160 comp = sorts[0]->psvi;
1161 descending = comp->descending;
1162 number = comp->number;
1163 if (results == NULL)
1164 return;
1165
1166 /* Shell's sort of node-set */
1167 for (incr = len / 2; incr > 0; incr /= 2) {
1168 for (i = incr; i < len; i++) {
1169 j = i - incr;
1170 if (results[i] == NULL)
1171 continue;
1172
1173 while (j >= 0) {
1174 if (results[j] == NULL)
1175 tst = 1;
1176 else {
1177 if (number) {
1178 /* We make NaN smaller than number in accordance
1179 with XSLT spec */
1180 if (xmlXPathIsNaN(results[j]->floatval)) {
1181 if (xmlXPathIsNaN(results[j + incr]->floatval))
1182 tst = 0;
1183 else
1184 tst = -1;
1185 } else if (xmlXPathIsNaN(results[j + incr]->floatval))
1186 tst = 1;
1187 else if (results[j]->floatval ==
1188 results[j + incr]->floatval)
1189 tst = 0;
1190 else if (results[j]->floatval >
1191 results[j + incr]->floatval)
1192 tst = 1;
1193 else tst = -1;
1194 } else {
1195 tst = xmlStrcmp(results[j]->stringval,
1196 results[j + incr]->stringval);
1197 }
1198 if (descending)
1199 tst = -tst;
1200 }
1201 if (tst == 0) {
1202 /*
1203 * Okay we need to use multi level sorts
1204 */
1205 depth = 1;
1206 while (depth < nbsorts) {
1207 if (sorts[depth] == NULL)
1208 break;
1209 comp = sorts[depth]->psvi;
1210 if (comp == NULL)
1211 break;
1212 desc = comp->descending;
1213 numb = comp->number;
1214
1215 /*
1216 * Compute the result of the next level for the
1217 * full set, this might be optimized ... or not
1218 */
1219 if (resultsTab[depth] == NULL)
1220 resultsTab[depth] = xsltComputeSortResult(ctxt,
1221 sorts[depth]);
1222 res = resultsTab[depth];
1223 if (res == NULL)
1224 break;
1225 if (res[j] == NULL) {
1226 if (res[j+incr] != NULL)
1227 tst = 1;
1228 } else {
1229 if (numb) {
1230 /* We make NaN smaller than number in
1231 accordance with XSLT spec */
1232 if (xmlXPathIsNaN(res[j]->floatval)) {
1233 if (xmlXPathIsNaN(res[j +
1234 incr]->floatval))
1235 tst = 0;
1236 else
1237 tst = -1;
1238 } else if (xmlXPathIsNaN(res[j + incr]->
1239 floatval))
1240 tst = 1;
1241 else if (res[j]->floatval == res[j + incr]->
1242 floatval)
1243 tst = 0;
1244 else if (res[j]->floatval >
1245 res[j + incr]->floatval)
1246 tst = 1;
1247 else tst = -1;
1248 } else {
1249 tst = xmlStrcmp(res[j]->stringval,
1250 res[j + incr]->stringval);
1251 }
1252 if (desc)
1253 tst = -tst;
1254 }
1255
1256 /*
1257 * if we still can't differenciate at this level
1258 * try one level deeper.
1259 */
1260 if (tst != 0)
1261 break;
1262 depth++;
1263 }
1264 }
1265 if (tst == 0) {
1266 tst = results[j]->index > results[j + incr]->index;
1267 }
1268 if (tst > 0) {
1269 tmp = results[j];
1270 results[j] = results[j + incr];
1271 results[j + incr] = tmp;
1272 node = list->nodeTab[j];
1273 list->nodeTab[j] = list->nodeTab[j + incr];
1274 list->nodeTab[j + incr] = node;
1275 depth = 1;
1276 while (depth < nbsorts) {
1277 if (sorts[depth] == NULL)
1278 break;
1279 if (resultsTab[depth] == NULL)
1280 break;
1281 res = resultsTab[depth];
1282 tmp = res[j];
1283 res[j] = res[j + incr];
1284 res[j + incr] = tmp;
1285 depth++;
1286 }
1287 j -= incr;
1288 } else
1289 break;
1290 }
1291 }
1292 }
1293
1294 for (j = 0; j < nbsorts; j++) {
1295 comp = sorts[j]->psvi;
1296 if (tempstype[j] == 1) {
1297 /* The data-type needs to be recomputed each time */
1298 xmlFree((void *)(comp->stype));
1299 comp->stype = NULL;
1300 }
1301 if (temporder[j] == 1) {
1302 /* The order needs to be recomputed each time */
1303 xmlFree((void *)(comp->order));
1304 comp->order = NULL;
1305 }
1306 if (resultsTab[j] != NULL) {
1307 for (i = 0;i < len;i++)
1308 xmlXPathFreeObject(resultsTab[j][i]);
1309 xmlFree(resultsTab[j]);
1310 }
1311 }
1312}
1313
1314
1315static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
1316
1317/**
1318 * xsltDoSortFunction:
1319 * @ctxt: a XSLT process context
1320 * @sorts: array of sort nodes
1321 * @nbsorts: the number of sorts in the array
1322 *
1323 * reorder the current node list accordingly to the set of sorting
1324 * requirement provided by the arry of nodes.
1325 * This is a wrapper function, the actual function used is specified
1326 * using xsltSetCtxtSortFunc() to set the context specific sort function,
1327 * or xsltSetSortFunc() to set the global sort function.
1328 * If a sort function is set on the context, this will get called.
1329 * Otherwise the global sort function is called.
1330 */
1331void
1332xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
1333 int nbsorts)
1334{
1335 if (ctxt->sortfunc != NULL)
1336 (ctxt->sortfunc)(ctxt, sorts, nbsorts);
1337 else if (xsltSortFunction != NULL)
1338 xsltSortFunction(ctxt, sorts, nbsorts);
1339}
1340
1341/**
1342 * xsltSetSortFunc:
1343 * @handler: the new handler function
1344 *
1345 * Function to reset the global handler for XSLT sorting.
1346 * If the handler is NULL, the default sort function will be used.
1347 */
1348void
1349xsltSetSortFunc(xsltSortFunc handler) {
1350 if (handler != NULL)
1351 xsltSortFunction = handler;
1352 else
1353 xsltSortFunction = xsltDefaultSortFunction;
1354}
1355
1356/**
1357 * xsltSetCtxtSortFunc:
1358 * @ctxt: a XSLT process context
1359 * @handler: the new handler function
1360 *
1361 * Function to set the handler for XSLT sorting
1362 * for the specified context.
1363 * If the handler is NULL, then the global
1364 * sort function will be called
1365 */
1366void
1367xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
1368 ctxt->sortfunc = handler;
1369}
1370
1371/************************************************************************
1372 * *
1373 * Parsing options *
1374 * *
1375 ************************************************************************/
1376
1377/**
1378 * xsltSetCtxtParseOptions:
1379 * @ctxt: a XSLT process context
1380 * @options: a combination of libxml2 xmlParserOption
1381 *
1382 * Change the default parser option passed by the XSLT engine to the
1383 * parser when using document() loading.
1384 *
1385 * Returns the previous options or -1 in case of error
1386 */
1387int
1388xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
1389{
1390 int oldopts;
1391
1392 if (ctxt == NULL)
1393 return(-1);
1394 oldopts = ctxt->parserOptions;
1395 if (ctxt->xinclude)
1396 oldopts |= XML_PARSE_XINCLUDE;
1397 ctxt->parserOptions = options;
1398 if (options & XML_PARSE_XINCLUDE)
1399 ctxt->xinclude = 1;
1400 else
1401 ctxt->xinclude = 0;
1402 return(oldopts);
1403}
1404
1405/************************************************************************
1406 * *
1407 * Output *
1408 * *
1409 ************************************************************************/
1410
1411/**
1412 * xsltSaveResultTo:
1413 * @buf: an output buffer
1414 * @result: the result xmlDocPtr
1415 * @style: the stylesheet
1416 *
1417 * Save the result @result obtained by applying the @style stylesheet
1418 * to an I/O output channel @buf
1419 *
1420 * Returns the number of byte written or -1 in case of failure.
1421 */
1422int
1423xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
1424 xsltStylesheetPtr style) {
1425 const xmlChar *encoding;
1426 int base;
1427 const xmlChar *method;
1428 int indent;
1429
1430 if ((buf == NULL) || (result == NULL) || (style == NULL))
1431 return(-1);
1432 if ((result->children == NULL) ||
1433 ((result->children->type == XML_DTD_NODE) &&
1434 (result->children->next == NULL)))
1435 return(0);
1436
1437 if ((style->methodURI != NULL) &&
1438 ((style->method == NULL) ||
1439 (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
1440 xsltGenericError(xsltGenericErrorContext,
1441 "xsltSaveResultTo : unknown ouput method\n");
1442 return(-1);
1443 }
1444
1445 base = buf->written;
1446
1447 XSLT_GET_IMPORT_PTR(method, style, method)
1448 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1449 XSLT_GET_IMPORT_INT(indent, style, indent);
1450
1451 if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
1452 method = (const xmlChar *) "html";
1453
1454 if ((method != NULL) &&
1455 (xmlStrEqual(method, (const xmlChar *) "html"))) {
1456 if (encoding != NULL) {
1457 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1458 } else {
1459 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1460 }
1461 if (indent == -1)
1462 indent = 1;
1463 htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
1464 indent);
1465 xmlOutputBufferFlush(buf);
1466 } else if ((method != NULL) &&
1467 (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
1468 if (encoding != NULL) {
1469 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1470 } else {
1471 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1472 }
1473 htmlDocContentDumpOutput(buf, result, (const char *) encoding);
1474 xmlOutputBufferFlush(buf);
1475 } else if ((method != NULL) &&
1476 (xmlStrEqual(method, (const xmlChar *) "text"))) {
1477 xmlNodePtr cur;
1478
1479 cur = result->children;
1480 while (cur != NULL) {
1481 if (cur->type == XML_TEXT_NODE)
1482 xmlOutputBufferWriteString(buf, (const char *) cur->content);
1483
1484 /*
1485 * Skip to next node
1486 */
1487 if (cur->children != NULL) {
1488 if ((cur->children->type != XML_ENTITY_DECL) &&
1489 (cur->children->type != XML_ENTITY_REF_NODE) &&
1490 (cur->children->type != XML_ENTITY_NODE)) {
1491 cur = cur->children;
1492 continue;
1493 }
1494 }
1495 if (cur->next != NULL) {
1496 cur = cur->next;
1497 continue;
1498 }
1499
1500 do {
1501 cur = cur->parent;
1502 if (cur == NULL)
1503 break;
1504 if (cur == (xmlNodePtr) style->doc) {
1505 cur = NULL;
1506 break;
1507 }
1508 if (cur->next != NULL) {
1509 cur = cur->next;
1510 break;
1511 }
1512 } while (cur != NULL);
1513 }
1514 xmlOutputBufferFlush(buf);
1515 } else {
1516 int omitXmlDecl;
1517 int standalone;
1518
1519 XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
1520 XSLT_GET_IMPORT_INT(standalone, style, standalone);
1521
1522 if (omitXmlDecl != 1) {
1523 xmlOutputBufferWriteString(buf, "<?xml version=");
1524 if (result->version != NULL)
1525 xmlBufferWriteQuotedString(buf->buffer, result->version);
1526 else
1527 xmlOutputBufferWriteString(buf, "\"1.0\"");
1528 if (encoding == NULL) {
1529 if (result->encoding != NULL)
1530 encoding = result->encoding;
1531 else if (result->charset != XML_CHAR_ENCODING_UTF8)
1532 encoding = (const xmlChar *)
1533 xmlGetCharEncodingName((xmlCharEncoding)
1534 result->charset);
1535 }
1536 if (encoding != NULL) {
1537 xmlOutputBufferWriteString(buf, " encoding=");
1538 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
1539 }
1540 switch (standalone) {
1541 case 0:
1542 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
1543 break;
1544 case 1:
1545 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
1546 break;
1547 default:
1548 break;
1549 }
1550 xmlOutputBufferWriteString(buf, "?>\n");
1551 }
1552 if (result->children != NULL) {
1553 xmlNodePtr child = result->children;
1554
1555 while (child != NULL) {
1556 xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
1557 (const char *) encoding);
1558 if ((child->type == XML_DTD_NODE) ||
1559 ((child->type == XML_COMMENT_NODE) &&
1560 (child->next != NULL)))
1561 xmlOutputBufferWriteString(buf, "\n");
1562 child = child->next;
1563 }
1564 xmlOutputBufferWriteString(buf, "\n");
1565 }
1566 xmlOutputBufferFlush(buf);
1567 }
1568 return(buf->written - base);
1569}
1570
1571/**
1572 * xsltSaveResultToFilename:
1573 * @URL: a filename or URL
1574 * @result: the result xmlDocPtr
1575 * @style: the stylesheet
1576 * @compression: the compression factor (0 - 9 included)
1577 *
1578 * Save the result @result obtained by applying the @style stylesheet
1579 * to a file or @URL
1580 *
1581 * Returns the number of byte written or -1 in case of failure.
1582 */
1583int
1584xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
1585 xsltStylesheetPtr style, int compression) {
1586 xmlOutputBufferPtr buf;
1587 const xmlChar *encoding;
1588 int ret;
1589
1590 if ((URL == NULL) || (result == NULL) || (style == NULL))
1591 return(-1);
1592 if (result->children == NULL)
1593 return(0);
1594
1595 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1596 if (encoding != NULL) {
1597 xmlCharEncodingHandlerPtr encoder;
1598
1599 encoder = xmlFindCharEncodingHandler((char *)encoding);
1600 if ((encoder != NULL) &&
1601 (xmlStrEqual((const xmlChar *)encoder->name,
1602 (const xmlChar *) "UTF-8")))
1603 encoder = NULL;
1604 buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
1605 } else {
1606 buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
1607 }
1608 if (buf == NULL)
1609 return(-1);
1610 xsltSaveResultTo(buf, result, style);
1611 ret = xmlOutputBufferClose(buf);
1612 return(ret);
1613}
1614
1615/**
1616 * xsltSaveResultToFile:
1617 * @file: a FILE * I/O
1618 * @result: the result xmlDocPtr
1619 * @style: the stylesheet
1620 *
1621 * Save the result @result obtained by applying the @style stylesheet
1622 * to an open FILE * I/O.
1623 * This does not close the FILE @file
1624 *
1625 * Returns the number of bytes written or -1 in case of failure.
1626 */
1627int
1628xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
1629 xmlOutputBufferPtr buf;
1630 const xmlChar *encoding;
1631 int ret;
1632
1633 if ((file == NULL) || (result == NULL) || (style == NULL))
1634 return(-1);
1635 if (result->children == NULL)
1636 return(0);
1637
1638 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1639 if (encoding != NULL) {
1640 xmlCharEncodingHandlerPtr encoder;
1641
1642 encoder = xmlFindCharEncodingHandler((char *)encoding);
1643 if ((encoder != NULL) &&
1644 (xmlStrEqual((const xmlChar *)encoder->name,
1645 (const xmlChar *) "UTF-8")))
1646 encoder = NULL;
1647 buf = xmlOutputBufferCreateFile(file, encoder);
1648 } else {
1649 buf = xmlOutputBufferCreateFile(file, NULL);
1650 }
1651
1652 if (buf == NULL)
1653 return(-1);
1654 xsltSaveResultTo(buf, result, style);
1655 ret = xmlOutputBufferClose(buf);
1656 return(ret);
1657}
1658
1659/**
1660 * xsltSaveResultToFd:
1661 * @fd: a file descriptor
1662 * @result: the result xmlDocPtr
1663 * @style: the stylesheet
1664 *
1665 * Save the result @result obtained by applying the @style stylesheet
1666 * to an open file descriptor
1667 * This does not close the descriptor.
1668 *
1669 * Returns the number of bytes written or -1 in case of failure.
1670 */
1671int
1672xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
1673 xmlOutputBufferPtr buf;
1674 const xmlChar *encoding;
1675 int ret;
1676
1677 if ((fd < 0) || (result == NULL) || (style == NULL))
1678 return(-1);
1679 if (result->children == NULL)
1680 return(0);
1681
1682 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1683 if (encoding != NULL) {
1684 xmlCharEncodingHandlerPtr encoder;
1685
1686 encoder = xmlFindCharEncodingHandler((char *)encoding);
1687 if ((encoder != NULL) &&
1688 (xmlStrEqual((const xmlChar *)encoder->name,
1689 (const xmlChar *) "UTF-8")))
1690 encoder = NULL;
1691 buf = xmlOutputBufferCreateFd(fd, encoder);
1692 } else {
1693 buf = xmlOutputBufferCreateFd(fd, NULL);
1694 }
1695 if (buf == NULL)
1696 return(-1);
1697 xsltSaveResultTo(buf, result, style);
1698 ret = xmlOutputBufferClose(buf);
1699 return(ret);
1700}
1701
1702/**
1703 * xsltSaveResultToString:
1704 * @doc_txt_ptr: Memory pointer for allocated XML text
1705 * @doc_txt_len: Length of the generated XML text
1706 * @result: the result xmlDocPtr
1707 * @style: the stylesheet
1708 *
1709 * Save the result @result obtained by applying the @style stylesheet
1710 * to a new allocated string.
1711 *
1712 * Returns 0 in case of success and -1 in case of error
1713 */
1714int
1715xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len,
1716 xmlDocPtr result, xsltStylesheetPtr style) {
1717 xmlOutputBufferPtr buf;
1718 const xmlChar *encoding;
1719
1720 *doc_txt_ptr = NULL;
1721 *doc_txt_len = 0;
1722 if (result->children == NULL)
1723 return(0);
1724
1725 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1726 if (encoding != NULL) {
1727 xmlCharEncodingHandlerPtr encoder;
1728
1729 encoder = xmlFindCharEncodingHandler((char *)encoding);
1730 if ((encoder != NULL) &&
1731 (xmlStrEqual((const xmlChar *)encoder->name,
1732 (const xmlChar *) "UTF-8")))
1733 encoder = NULL;
1734 buf = xmlAllocOutputBuffer(encoder);
1735 } else {
1736 buf = xmlAllocOutputBuffer(NULL);
1737 }
1738 if (buf == NULL)
1739 return(-1);
1740 xsltSaveResultTo(buf, result, style);
1741 if (buf->conv != NULL) {
1742 *doc_txt_len = buf->conv->use;
1743 *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
1744 } else {
1745 *doc_txt_len = buf->buffer->use;
1746 *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
1747 }
1748 (void)xmlOutputBufferClose(buf);
1749 return 0;
1750}
1751
1752/************************************************************************
1753 * *
1754 * Generating profiling informations *
1755 * *
1756 ************************************************************************/
1757
1758static long calibration = -1;
1759
1760/**
1761 * xsltCalibrateTimestamps:
1762 *
1763 * Used for to calibrate the xsltTimestamp() function
1764 * Should work if launched at startup and we don't loose our quantum :-)
1765 *
1766 * Returns the number of milliseconds used by xsltTimestamp()
1767 */
1768static long
1769xsltCalibrateTimestamps(void) {
1770 register int i;
1771
1772 for (i = 0;i < 999;i++)
1773 xsltTimestamp();
1774 return(xsltTimestamp() / 1000);
1775}
1776
1777/**
1778 * xsltCalibrateAdjust:
1779 * @delta: a negative dealy value found
1780 *
1781 * Used for to correct the calibration for xsltTimestamp()
1782 */
1783void
1784xsltCalibrateAdjust(long delta) {
1785 calibration += delta;
1786}
1787
1788/**
1789 * xsltTimestamp:
1790 *
1791 * Used for gathering profiling data
1792 *
1793 * Returns the number of tenth of milliseconds since the beginning of the
1794 * profiling
1795 */
1796long
1797xsltTimestamp(void)
1798{
1799#ifdef XSLT_WIN32_PERFORMANCE_COUNTER
1800 BOOL ok;
1801 LARGE_INTEGER performanceCount;
1802 LARGE_INTEGER performanceFrequency;
1803 LONGLONG quadCount;
1804 double seconds;
1805 static LONGLONG startupQuadCount = 0;
1806 static LONGLONG startupQuadFreq = 0;
1807
1808 ok = QueryPerformanceCounter(&performanceCount);
1809 if (!ok)
1810 return 0;
1811 quadCount = performanceCount.QuadPart;
1812 if (calibration < 0) {
1813 calibration = 0;
1814 ok = QueryPerformanceFrequency(&performanceFrequency);
1815 if (!ok)
1816 return 0;
1817 startupQuadFreq = performanceFrequency.QuadPart;
1818 startupQuadCount = quadCount;
1819 return (0);
1820 }
1821 if (startupQuadFreq == 0)
1822 return 0;
1823 seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
1824 return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
1825
1826#else /* XSLT_WIN32_PERFORMANCE_COUNTER */
1827#ifdef HAVE_GETTIMEOFDAY
1828 static struct timeval startup;
1829 struct timeval cur;
1830 long tics;
1831
1832 if (calibration < 0) {
1833 gettimeofday(&startup, NULL);
1834 calibration = 0;
1835 calibration = xsltCalibrateTimestamps();
1836 gettimeofday(&startup, NULL);
1837 return (0);
1838 }
1839
1840 gettimeofday(&cur, NULL);
1841 tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1842 tics += (cur.tv_usec - startup.tv_usec) /
1843 (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1844
1845 tics -= calibration;
1846 return(tics);
1847#else
1848
1849 /* Neither gettimeofday() nor Win32 performance counter available */
1850
1851 return (0);
1852
1853#endif /* HAVE_GETTIMEOFDAY */
1854#endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
1855}
1856
1857#define MAX_TEMPLATES 10000
1858
1859/**
1860 * xsltSaveProfiling:
1861 * @ctxt: an XSLT context
1862 * @output: a FILE * for saving the informations
1863 *
1864 * Save the profiling informations on @output
1865 */
1866void
1867xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
1868 int nb, i,j;
1869 int max;
1870 int total;
1871 long totalt;
1872 xsltTemplatePtr *templates;
1873 xsltStylesheetPtr style;
1874 xsltTemplatePtr template;
1875
1876 if ((output == NULL) || (ctxt == NULL))
1877 return;
1878 if (ctxt->profile == 0)
1879 return;
1880
1881 nb = 0;
1882 max = MAX_TEMPLATES;
1883 templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
1884 if (templates == NULL)
1885 return;
1886
1887 style = ctxt->style;
1888 while (style != NULL) {
1889 template = style->templates;
1890 while (template != NULL) {
1891 if (nb >= max)
1892 break;
1893
1894 if (template->nbCalls > 0)
1895 templates[nb++] = template;
1896 template = template->next;
1897 }
1898
1899 style = xsltNextImport(style);
1900 }
1901
1902 for (i = 0;i < nb -1;i++) {
1903 for (j = i + 1; j < nb; j++) {
1904 if ((templates[i]->time <= templates[j]->time) ||
1905 ((templates[i]->time == templates[j]->time) &&
1906 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
1907 template = templates[j];
1908 templates[j] = templates[i];
1909 templates[i] = template;
1910 }
1911 }
1912 }
1913
1914 fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n",
1915 "number", "match", "name", "mode");
1916 total = 0;
1917 totalt = 0;
1918 for (i = 0;i < nb;i++) {
1919 fprintf(output, "%5d ", i);
1920 if (templates[i]->match != NULL) {
1921 if (xmlStrlen(templates[i]->match) > 20)
1922 fprintf(output, "%s\n%26s", templates[i]->match, "");
1923 else
1924 fprintf(output, "%20s", templates[i]->match);
1925 } else {
1926 fprintf(output, "%20s", "");
1927 }
1928 if (templates[i]->name != NULL) {
1929 if (xmlStrlen(templates[i]->name) > 20)
1930 fprintf(output, "%s\n%46s", templates[i]->name, "");
1931 else
1932 fprintf(output, "%20s", templates[i]->name);
1933 } else {
1934 fprintf(output, "%20s", "");
1935 }
1936 if (templates[i]->mode != NULL) {
1937 if (xmlStrlen(templates[i]->mode) > 10)
1938 fprintf(output, "%s\n%56s", templates[i]->mode, "");
1939 else
1940 fprintf(output, "%10s", templates[i]->mode);
1941 } else {
1942 fprintf(output, "%10s", "");
1943 }
1944 fprintf(output, " %6d", templates[i]->nbCalls);
1945 fprintf(output, " %6ld %6ld\n", templates[i]->time,
1946 templates[i]->time / templates[i]->nbCalls);
1947 total += templates[i]->nbCalls;
1948 totalt += templates[i]->time;
1949 }
1950 fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
1951
1952 xmlFree(templates);
1953}
1954
1955/************************************************************************
1956 * *
1957 * Fetching profiling informations *
1958 * *
1959 ************************************************************************/
1960
1961/**
1962 * xsltGetProfileInformation:
1963 * @ctxt: a transformation context
1964 *
1965 * This function should be called after the transformation completed
1966 * to extract template processing profiling informations if availble.
1967 * The informations are returned as an XML document tree like
1968 * <?xml version="1.0"?>
1969 * <profile>
1970 * <template rank="1" match="*" name=""
1971 * mode="" calls="6" time="48" average="8"/>
1972 * <template rank="2" match="item2|item3" name=""
1973 * mode="" calls="10" time="30" average="3"/>
1974 * <template rank="3" match="item1" name=""
1975 * mode="" calls="5" time="17" average="3"/>
1976 * </profile>
1977 * The caller will need to free up the returned tree with xmlFreeDoc()
1978 *
1979 * Returns the xmlDocPtr corresponding to the result or NULL if not available.
1980 */
1981
1982xmlDocPtr
1983xsltGetProfileInformation(xsltTransformContextPtr ctxt)
1984{
1985 xmlDocPtr ret = NULL;
1986 xmlNodePtr root, child;
1987 char buf[100];
1988
1989 xsltStylesheetPtr style;
1990 xsltTemplatePtr *templates;
1991 xsltTemplatePtr templ;
1992 int nb = 0, max = 0, i, j;
1993
1994 if (!ctxt)
1995 return NULL;
1996
1997 if (!ctxt->profile)
1998 return NULL;
1999
2000 nb = 0;
2001 max = 10000;
2002 templates =
2003 (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
2004 if (templates == NULL)
2005 return NULL;
2006
2007 /*
2008 * collect all the templates in an array
2009 */
2010 style = ctxt->style;
2011 while (style != NULL) {
2012 templ = style->templates;
2013 while (templ != NULL) {
2014 if (nb >= max)
2015 break;
2016
2017 if (templ->nbCalls > 0)
2018 templates[nb++] = templ;
2019 templ = templ->next;
2020 }
2021
2022 style = (xsltStylesheetPtr) xsltNextImport(style);
2023 }
2024
2025 /*
2026 * Sort the array by time spent
2027 */
2028 for (i = 0; i < nb - 1; i++) {
2029 for (j = i + 1; j < nb; j++) {
2030 if ((templates[i]->time <= templates[j]->time) ||
2031 ((templates[i]->time == templates[j]->time) &&
2032 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2033 templ = templates[j];
2034 templates[j] = templates[i];
2035 templates[i] = templ;
2036 }
2037 }
2038 }
2039
2040 /*
2041 * Generate a document corresponding to the results.
2042 */
2043 ret = xmlNewDoc(BAD_CAST "1.0");
2044 root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
2045 xmlDocSetRootElement(ret, root);
2046
2047 for (i = 0; i < nb; i++) {
2048 child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
2049 sprintf(buf, "%d", i + 1);
2050 xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
2051 xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
2052 xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
2053 xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
2054
2055 sprintf(buf, "%d", templates[i]->nbCalls);
2056 xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
2057
2058 sprintf(buf, "%ld", templates[i]->time);
2059 xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
2060
2061 sprintf(buf, "%ld", templates[i]->time / templates[i]->nbCalls);
2062 xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
2063 };
2064
2065 xmlFree(templates);
2066
2067 return ret;
2068}
2069
2070/************************************************************************
2071 * *
2072 * Hooks for libxml2 XPath *
2073 * *
2074 ************************************************************************/
2075
2076/**
2077 * xsltXPathCompile:
2078 * @style: the stylesheet
2079 * @str: the XPath expression
2080 *
2081 * Compile an XPath expression
2082 *
2083 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2084 * the caller has to free the object.
2085 */
2086xmlXPathCompExprPtr
2087xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
2088 xmlXPathContextPtr xpathCtxt;
2089 xmlXPathCompExprPtr ret;
2090
2091 if (style != NULL) {
2092#ifdef XSLT_REFACTORED_XPATHCOMP
2093 if (XSLT_CCTXT(style)) {
2094 /*
2095 * Proposed by Jerome Pesenti
2096 * --------------------------
2097 * For better efficiency we'll reuse the compilation
2098 * context's XPath context. For the common stylesheet using
2099 * XPath expressions this will reduce compilation time to
2100 * about 50%.
2101 *
2102 * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
2103 */
2104 xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
2105 xpathCtxt->doc = style->doc;
2106 } else
2107 xpathCtxt = xmlXPathNewContext(style->doc);
2108#else
2109 xpathCtxt = xmlXPathNewContext(style->doc);
2110#endif
2111 if (xpathCtxt == NULL)
2112 return NULL;
2113 xpathCtxt->dict = style->dict;
2114 } else {
2115 xpathCtxt = xmlXPathNewContext(NULL);
2116 if (xpathCtxt == NULL)
2117 return NULL;
2118 }
2119 /*
2120 * Compile the expression.
2121 */
2122 ret = xmlXPathCtxtCompile(xpathCtxt, str);
2123
2124#ifdef XSLT_REFACTORED_XPATHCOMP
2125 if ((style == NULL) || (! XSLT_CCTXT(style))) {
2126 xmlXPathFreeContext(xpathCtxt);
2127 }
2128#else
2129 xmlXPathFreeContext(xpathCtxt);
2130#endif
2131 /*
2132 * TODO: there is a lot of optimizations which should be possible
2133 * like variable slot precomputations, function precomputations, etc.
2134 */
2135
2136 return(ret);
2137}
2138
2139/************************************************************************
2140 * *
2141 * Hooks for the debugger *
2142 * *
2143 ************************************************************************/
2144
2145/*
2146 * There is currently only 3 debugging callback defined
2147 * Debugger callbacks are disabled by default
2148 */
2149#define XSLT_CALLBACK_NUMBER 3
2150
2151typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
2152typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
2153struct _xsltDebuggerCallbacks {
2154 xsltHandleDebuggerCallback handler;
2155 xsltAddCallCallback add;
2156 xsltDropCallCallback drop;
2157};
2158
2159static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
2160 NULL, /* handler */
2161 NULL, /* add */
2162 NULL /* drop */
2163};
2164
2165int xslDebugStatus;
2166
2167/**
2168 * xsltSetDebuggerStatus:
2169 * @value : the value to be set
2170 *
2171 * This function sets the value of xslDebugStatus.
2172 */
2173void
2174xsltSetDebuggerStatus(int value)
2175{
2176 xslDebugStatus = value;
2177}
2178
2179/**
2180 * xsltGetDebuggerStatus:
2181 *
2182 * Get xslDebugStatus.
2183 *
2184 * Returns the value of xslDebugStatus.
2185 */
2186int
2187xsltGetDebuggerStatus(void)
2188{
2189 return(xslDebugStatus);
2190}
2191
2192/**
2193 * xsltSetDebuggerCallbacks:
2194 * @no : number of callbacks
2195 * @block : the block of callbacks
2196 *
2197 * This function allow to plug a debugger into the XSLT library
2198 * @block points to a block of memory containing the address of @no
2199 * callback routines.
2200 *
2201 * Returns 0 in case of success and -1 in case of error
2202 */
2203int
2204xsltSetDebuggerCallbacks(int no, void *block)
2205{
2206 xsltDebuggerCallbacksPtr callbacks;
2207
2208 if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
2209 return(-1);
2210
2211 callbacks = (xsltDebuggerCallbacksPtr) block;
2212 xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
2213 xsltDebuggerCurrentCallbacks.add = callbacks->add;
2214 xsltDebuggerCurrentCallbacks.drop = callbacks->drop;
2215 return(0);
2216}
2217
2218/**
2219 * xslHandleDebugger:
2220 * @cur : source node being executed
2221 * @node : data node being processed
2222 * @templ : temlate that applies to node
2223 * @ctxt : the xslt transform context
2224 *
2225 * If either cur or node are a breakpoint, or xslDebugStatus in state
2226 * where debugging must occcur at this time then transfer control
2227 * to the xslDebugBreak function
2228 */
2229void
2230xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
2231 xsltTransformContextPtr ctxt)
2232{
2233 if (xsltDebuggerCurrentCallbacks.handler != NULL)
2234 xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
2235}
2236
2237/**
2238 * xslAddCall:
2239 * @templ : current template being applied
2240 * @source : the source node being processed
2241 *
2242 * Add template "call" to call stack
2243 * Returns : 1 on sucess 0 otherwise an error may be printed if
2244 * WITH_XSLT_DEBUG_BREAKPOINTS is defined
2245 */
2246int
2247xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
2248{
2249 if (xsltDebuggerCurrentCallbacks.add != NULL)
2250 return(xsltDebuggerCurrentCallbacks.add(templ, source));
2251 return(0);
2252}
2253
2254/**
2255 * xslDropCall:
2256 *
2257 * Drop the topmost item off the call stack
2258 */
2259void
2260xslDropCall(void)
2261{
2262 if (xsltDebuggerCurrentCallbacks.drop != NULL)
2263 xsltDebuggerCurrentCallbacks.drop();
2264}
2265
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette