2 * xsltutils.c: Utilities for the XSL Transformation 1.0 engine
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
9 * Daniel.Veillard@imag.fr
12 #include "xsltconfig.h"
17 #include <libxml/xmlversion.h>
18 #include <libxml/xmlmemory.h>
19 #include <libxml/tree.h>
20 #include <libxml/xmlerror.h>
21 #include <libxml/xmlIO.h>
22 #include "xsltutils.h"
23 #include "templates.h"
24 #include "xsltInternals.h"
27 /************************************************************************
29 * Handling of XSLT stylesheets messages *
31 ************************************************************************/
35 * @ctxt: an XSLT processing context
36 * @node: The current node
37 * @inst: The node containing the message instruction
39 * Process and xsl:message construct
42 xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
43 xmlChar *prop, *message;
46 if ((ctxt == NULL) || (inst == NULL))
49 prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", XSLT_NAMESPACE);
51 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
53 } else if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
56 xsltGenericError(xsltGenericErrorContext,
57 "xsl:message : terminate expecting 'yes' or 'no'\n");
61 message = xsltEvalTemplateString(ctxt, node, inst);
62 if (message != NULL) {
63 xsltGenericError(xsltGenericErrorContext, (const char *)message);
67 ctxt->state = XSLT_STATE_STOPPED;
70 /************************************************************************
72 * Handling of out of context errors *
74 ************************************************************************/
77 * xsltGenericErrorDefaultFunc:
78 * @ctx: an error context
79 * @msg: the message to display/transmit
80 * @...: extra parameters for the message display
82 * Default handler for out of context error messages.
85 xsltGenericErrorDefaultFunc(void *ctx, const char *msg, ...) {
88 if (xsltGenericErrorContext == NULL)
89 xsltGenericErrorContext = (void *) stderr;
92 vfprintf((FILE *)xsltGenericErrorContext, msg, args);
96 xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
97 void *xsltGenericErrorContext = NULL;
101 * xsltSetGenericErrorFunc:
102 * @ctx: the new error handling context
103 * @handler: the new handler function
105 * Function to reset the handler and the error context for out of
106 * context error messages.
107 * This simply means that @handler will be called for subsequent
108 * error messages while not parsing nor validating. And @ctx will
109 * be passed as first argument to @handler
110 * One can simply force messages to be emitted to another FILE * than
111 * stderr by setting @ctx to this file handle and @handler to NULL.
114 xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
115 xsltGenericErrorContext = ctx;
117 xsltGenericError = handler;
119 xsltGenericError = xsltGenericErrorDefaultFunc;
123 * xsltGenericDebugDefaultFunc:
124 * @ctx: an error context
125 * @msg: the message to display/transmit
126 * @...: extra parameters for the message display
128 * Default handler for out of context error messages.
131 xsltGenericDebugDefaultFunc(void *ctx, const char *msg, ...) {
134 if (xsltGenericDebugContext == NULL)
138 vfprintf((FILE *)xsltGenericDebugContext, msg, args);
142 xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
143 void *xsltGenericDebugContext = NULL;
147 * xsltSetGenericDebugFunc:
148 * @ctx: the new error handling context
149 * @handler: the new handler function
151 * Function to reset the handler and the error context for out of
152 * context error messages.
153 * This simply means that @handler will be called for subsequent
154 * error messages while not parsing nor validating. And @ctx will
155 * be passed as first argument to @handler
156 * One can simply force messages to be emitted to another FILE * than
157 * stderr by setting @ctx to this file handle and @handler to NULL.
160 xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
161 xsltGenericDebugContext = ctx;
163 xsltGenericDebug = handler;
165 xsltGenericDebug = xsltGenericDebugDefaultFunc;
168 /************************************************************************
172 ************************************************************************/
176 * @list: the node set
177 * @results: the results
178 * @descending: direction of order
179 * @number: the type of the result
181 * reorder the current node list @list accordingly to the values
182 * present in the array of results @results
185 xsltSortFunction(xmlNodeSetPtr list, xmlXPathObjectPtr *results,
186 int descending, int number) {
190 xmlXPathObjectPtr tmp;
192 if ((list == NULL) || (results == NULL))
197 /* TODO: sort is really not optimized, does it needs to ? */
198 for (i = 0;i < len -1;i++) {
199 for (j = i + 1; j < len; j++) {
200 if (results[i] == NULL)
202 else if (results[j] == NULL)
205 tst = (results[i]->floatval > results[j]->floatval);
209 tst = xmlStrcmp(results[i]->stringval, results[j]->stringval);
215 results[i] = results[j];
217 node = list->nodeTab[i];
218 list->nodeTab[i] = list->nodeTab[j];
219 list->nodeTab[j] = node;
225 /************************************************************************
229 ************************************************************************/
233 * @buf: an output buffer
234 * @result: the result xmlDocPtr
235 * @style: the stylesheet
237 * Save the result @result obtained by applying the @style stylesheet
238 * to an I/O output channel @buf
240 * Returns the number of byte written or -1 in case of failure.
243 xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
244 xsltStylesheetPtr style) {
245 const xmlChar *encoding;
249 if ((buf == NULL) || (result == NULL) || (style == NULL))
252 if (style->methodURI != NULL) {
253 xsltGenericError(xsltGenericErrorContext,
254 "xsltSaveResultTo : unknown ouput method\n");
258 /* TODO: when outputing and having imported stylesheets, apply cascade */
260 encoding = style->encoding;
261 if (style->method == NULL)
262 root = xmlDocGetRootElement(result);
265 if (((style->method != NULL) &&
266 (xmlStrEqual(style->method, (const xmlChar *) "html"))) ||
268 (xmlStrEqual(root->name, (const xmlChar *) "html")))){
269 htmlDocContentDumpOutput(buf, result, (const char *) encoding);
270 } else if ((style->method != NULL) &&
271 (xmlStrEqual(style->method, (const xmlChar *) "text"))) {
274 cur = result->children;
275 while (cur != NULL) {
276 if (cur->type == XML_TEXT_NODE)
277 xmlOutputBufferWriteString(buf, (const char *) cur->content);
281 if (style->omitXmlDeclaration != 1) {
282 xmlOutputBufferWriteString(buf, "<?xml version=");
283 if (result->version != NULL)
284 xmlBufferWriteQuotedString(buf->buffer, result->version);
286 xmlOutputBufferWriteString(buf, "\"1.0\"");
287 if (encoding == NULL) {
288 if (result->encoding != NULL)
289 encoding = result->encoding;
290 else if (result->charset != XML_CHAR_ENCODING_UTF8)
291 encoding = (const xmlChar *)
292 xmlGetCharEncodingName((xmlCharEncoding)
295 if (encoding != NULL) {
296 xmlOutputBufferWriteString(buf, " encoding=");
297 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
299 switch (style->standalone) {
301 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
304 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
309 xmlOutputBufferWriteString(buf, "?>\n");
311 if (result->children != NULL) {
312 xmlNodePtr child = result->children;
314 while (child != NULL) {
315 xmlNodeDumpOutput(buf, result, child, 0, (style->indent == 1),
316 (const char *) encoding);
317 xmlOutputBufferWriteString(buf, "\n");
321 xmlOutputBufferFlush(buf);
323 return(buf->written - base);
327 * xsltSaveResultToFilename:
328 * @URL: a filename or URL
329 * @result: the result xmlDocPtr
330 * @style: the stylesheet
331 * @compression: the compression factor (0 - 9 included)
333 * Save the result @result obtained by applying the @style stylesheet
334 * to a file or URL @URL
336 * Returns the number of byte written or -1 in case of failure.
339 xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
340 xsltStylesheetPtr style, int compression) {
341 xmlOutputBufferPtr buf;
344 if ((URL == NULL) || (result == NULL) || (style == NULL))
347 buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
350 xsltSaveResultTo(buf, result, style);
351 ret = xmlOutputBufferClose(buf);
356 * xsltSaveResultToFile:
357 * @file: a FILE * I/O
358 * @result: the result xmlDocPtr
359 * @style: the stylesheet
361 * Save the result @result obtained by applying the @style stylesheet
362 * to an open FILE * I/O.
363 * This does not close the FILE @file
365 * Returns the number of byte written or -1 in case of failure.
368 xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
369 xmlOutputBufferPtr buf;
372 if ((file == NULL) || (result == NULL) || (style == NULL))
375 buf = xmlOutputBufferCreateFile(file, NULL);
378 xsltSaveResultTo(buf, result, style);
379 ret = xmlOutputBufferClose(buf);
384 * xsltSaveResultToFd:
385 * @fd: a file descriptor
386 * @result: the result xmlDocPtr
387 * @style: the stylesheet
389 * Save the result @result obtained by applying the @style stylesheet
390 * to an open file descriptor
391 * This does not close the descriptor.
393 * Returns the number of byte written or -1 in case of failure.
396 xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
397 xmlOutputBufferPtr buf;
400 if ((fd < 0) || (result == NULL) || (style == NULL))
403 buf = xmlOutputBufferCreateFd(fd, NULL);
406 xsltSaveResultTo(buf, result, style);
407 ret = xmlOutputBufferClose(buf);