Coverage Report

Created: 2024-01-23 06:30

/src/libxslt/libxslt/transform.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * transform.c: Implementation of the XSL Transformation 1.0 engine
3
 *              transform part, i.e. applying a Stylesheet to a document
4
 *
5
 * References:
6
 *   http://www.w3.org/TR/1999/REC-xslt-19991116
7
 *
8
 *   Michael Kay "XSLT Programmer's Reference" pp 637-643
9
 *   Writing Multiple Output Files
10
 *
11
 *   XSLT-1.1 Working Draft
12
 *   http://www.w3.org/TR/xslt11#multiple-output
13
 *
14
 * See Copyright for the status of this software.
15
 *
16
 * daniel@veillard.com
17
 */
18
19
#define IN_LIBXSLT
20
#include "libxslt.h"
21
22
#include <limits.h>
23
#include <string.h>
24
#include <stdio.h>
25
#include <stddef.h>
26
27
#include <libxml/xmlmemory.h>
28
#include <libxml/parser.h>
29
#include <libxml/tree.h>
30
#include <libxml/valid.h>
31
#include <libxml/hash.h>
32
#include <libxml/encoding.h>
33
#include <libxml/xmlerror.h>
34
#include <libxml/xpath.h>
35
#include <libxml/parserInternals.h>
36
#include <libxml/xpathInternals.h>
37
#include <libxml/HTMLtree.h>
38
#include <libxml/debugXML.h>
39
#include <libxml/uri.h>
40
#include "xslt.h"
41
#include "xsltInternals.h"
42
#include "xsltutils.h"
43
#include "xsltlocale.h"
44
#include "pattern.h"
45
#include "transform.h"
46
#include "variables.h"
47
#include "numbersInternals.h"
48
#include "namespaces.h"
49
#include "attributes.h"
50
#include "templates.h"
51
#include "imports.h"
52
#include "keys.h"
53
#include "documents.h"
54
#include "extensions.h"
55
#include "extra.h"
56
#include "preproc.h"
57
#include "security.h"
58
59
#ifdef WITH_XSLT_DEBUG
60
#define WITH_XSLT_DEBUG_EXTRA
61
#define WITH_XSLT_DEBUG_PROCESS
62
#define WITH_XSLT_DEBUG_VARIABLE
63
#endif
64
65
#define XSLT_GENERATE_HTML_DOCTYPE
66
#ifdef XSLT_GENERATE_HTML_DOCTYPE
67
static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
68
        const xmlChar **systemID);
69
#endif
70
71
int xsltMaxDepth = 3000;
72
int xsltMaxVars = 15000;
73
74
/*
75
 * Useful macros
76
 */
77
78
#ifndef FALSE
79
# define FALSE (0 == 1)
80
# define TRUE (!FALSE)
81
#endif
82
83
#define IS_BLANK_NODE(n)            \
84
0
    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
85
86
87
/*
88
* Forward declarations
89
*/
90
91
static xmlNsPtr
92
xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
93
94
static xmlNodePtr
95
xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
96
       xmlNodePtr node, xmlNodePtr insert, int isLRE,
97
       int topElemVisited);
98
99
static void
100
xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
101
           xmlNodePtr contextNode, xmlNodePtr list,
102
           xsltTemplatePtr templ);
103
104
static void
105
xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
106
          xmlNodePtr contextNode,
107
          xmlNodePtr list,
108
          xsltTemplatePtr templ,
109
          xsltStackElemPtr withParams);
110
111
/**
112
 * templPush:
113
 * @ctxt: the transformation context
114
 * @value:  the template to push on the stack
115
 *
116
 * Push a template on the stack
117
 *
118
 * Returns the new index in the stack or 0 in case of error
119
 */
120
static int
121
templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)
122
0
{
123
0
    if (ctxt->templMax == 0) {
124
0
        ctxt->templMax = 4;
125
0
        ctxt->templTab =
126
0
            (xsltTemplatePtr *) xmlMalloc(ctxt->templMax *
127
0
                                          sizeof(ctxt->templTab[0]));
128
0
        if (ctxt->templTab == NULL) {
129
0
            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
130
0
            return (0);
131
0
        }
132
0
    }
133
0
    else if (ctxt->templNr >= ctxt->templMax) {
134
0
        ctxt->templMax *= 2;
135
0
        ctxt->templTab =
136
0
            (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,
137
0
                                           ctxt->templMax *
138
0
                                           sizeof(ctxt->templTab[0]));
139
0
        if (ctxt->templTab == NULL) {
140
0
            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
141
0
            return (0);
142
0
        }
143
0
    }
144
0
    ctxt->templTab[ctxt->templNr] = value;
145
0
    ctxt->templ = value;
146
0
    return (ctxt->templNr++);
147
0
}
148
/**
149
 * templPop:
150
 * @ctxt: the transformation context
151
 *
152
 * Pop a template value from the stack
153
 *
154
 * Returns the stored template value
155
 */
156
static xsltTemplatePtr
157
templPop(xsltTransformContextPtr ctxt)
158
0
{
159
0
    xsltTemplatePtr ret;
160
161
0
    if (ctxt->templNr <= 0)
162
0
        return (0);
163
0
    ctxt->templNr--;
164
0
    if (ctxt->templNr > 0)
165
0
        ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
166
0
    else
167
0
        ctxt->templ = (xsltTemplatePtr) 0;
168
0
    ret = ctxt->templTab[ctxt->templNr];
169
0
    ctxt->templTab[ctxt->templNr] = 0;
170
0
    return (ret);
171
0
}
172
173
/**
174
 * xsltLocalVariablePop:
175
 * @ctxt: the transformation context
176
 * @limitNr: number of variables which should remain
177
 * @level: the depth in the xsl:template's tree
178
 *
179
 * Pops all variable values at the given @depth from the stack.
180
 *
181
 * Returns the stored variable value
182
 * **NOTE:**
183
 * This is an internal routine and should not be called by users!
184
 */
185
void
186
xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
187
0
{
188
0
    xsltStackElemPtr variable;
189
190
0
    if (ctxt->varsNr <= 0)
191
0
        return;
192
193
0
    do {
194
0
  if (ctxt->varsNr <= limitNr)
195
0
      break;
196
0
  variable = ctxt->varsTab[ctxt->varsNr - 1];
197
0
  if (variable->level <= level)
198
0
      break;
199
0
  if (variable->level >= 0)
200
0
      xsltFreeStackElemList(variable);
201
0
  ctxt->varsNr--;
202
0
    } while (ctxt->varsNr != 0);
203
0
    if (ctxt->varsNr > 0)
204
0
        ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
205
0
    else
206
0
        ctxt->vars = NULL;
207
0
}
208
209
/**
210
 * xsltTemplateParamsCleanup:
211
 *
212
 * Removes xsl:param and xsl:with-param items from the
213
 * variable-stack. Only xsl:with-param items are not freed.
214
 */
215
static void
216
xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)
217
0
{
218
0
    xsltStackElemPtr param;
219
220
0
    for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
221
0
  param = ctxt->varsTab[ctxt->varsNr -1];
222
  /*
223
  * Free xsl:param items.
224
  * xsl:with-param items will have a level of -1 or -2.
225
  */
226
0
  if (param->level >= 0) {
227
0
      xsltFreeStackElemList(param);
228
0
  }
229
0
    }
230
0
    if (ctxt->varsNr > 0)
231
0
        ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
232
0
    else
233
0
        ctxt->vars = NULL;
234
0
}
235
236
#ifdef WITH_PROFILER
237
238
/**
239
 * profPush:
240
 * @ctxt: the transformation context
241
 * @value:  the profiling value to push on the stack
242
 *
243
 * Push a profiling value on the stack
244
 *
245
 * Returns the new index in the stack or 0 in case of error
246
 */
247
static int
248
profPush(xsltTransformContextPtr ctxt, long value)
249
{
250
    if (ctxt->profMax == 0) {
251
        ctxt->profMax = 4;
252
        ctxt->profTab =
253
            (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
254
        if (ctxt->profTab == NULL) {
255
            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
256
            return (0);
257
        }
258
    }
259
    else if (ctxt->profNr >= ctxt->profMax) {
260
        ctxt->profMax *= 2;
261
        ctxt->profTab =
262
            (long *) xmlRealloc(ctxt->profTab,
263
                                ctxt->profMax * sizeof(ctxt->profTab[0]));
264
        if (ctxt->profTab == NULL) {
265
            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
266
            return (0);
267
        }
268
    }
269
    ctxt->profTab[ctxt->profNr] = value;
270
    ctxt->prof = value;
271
    return (ctxt->profNr++);
272
}
273
/**
274
 * profPop:
275
 * @ctxt: the transformation context
276
 *
277
 * Pop a profiling value from the stack
278
 *
279
 * Returns the stored profiling value
280
 */
281
static long
282
profPop(xsltTransformContextPtr ctxt)
283
{
284
    long ret;
285
286
    if (ctxt->profNr <= 0)
287
        return (0);
288
    ctxt->profNr--;
289
    if (ctxt->profNr > 0)
290
        ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
291
    else
292
        ctxt->prof = (long) 0;
293
    ret = ctxt->profTab[ctxt->profNr];
294
    ctxt->profTab[ctxt->profNr] = 0;
295
    return (ret);
296
}
297
298
static void
299
profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent)
300
{
301
    int i;
302
303
    if (templ->templMax == 0) {
304
        templ->templMax = 4;
305
        templ->templCalledTab =
306
            (xsltTemplatePtr *) xmlMalloc(templ->templMax *
307
                                          sizeof(templ->templCalledTab[0]));
308
        templ->templCountTab =
309
            (int *) xmlMalloc(templ->templMax *
310
                                          sizeof(templ->templCountTab[0]));
311
        if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
312
            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
313
            return;
314
        }
315
    }
316
    else if (templ->templNr >= templ->templMax) {
317
        templ->templMax *= 2;
318
        templ->templCalledTab =
319
            (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab,
320
                                           templ->templMax *
321
                                           sizeof(templ->templCalledTab[0]));
322
        templ->templCountTab =
323
            (int *) xmlRealloc(templ->templCountTab,
324
                                           templ->templMax *
325
                                           sizeof(templ->templCountTab[0]));
326
        if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
327
            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
328
            return;
329
        }
330
    }
331
332
    for (i = 0; i < templ->templNr; i++) {
333
        if (templ->templCalledTab[i] == parent) {
334
            templ->templCountTab[i]++;
335
            break;
336
        }
337
    }
338
    if (i == templ->templNr) {
339
        /* not found, add new one */
340
        templ->templCalledTab[templ->templNr] = parent;
341
        templ->templCountTab[templ->templNr] = 1;
342
        templ->templNr++;
343
    }
344
}
345
346
#endif /* WITH_PROFILER */
347
348
/**
349
 * xsltPreCompEval:
350
 * @ctxt: transform context
351
 * @node: context node
352
 * @comp: precompiled expression
353
 *
354
 * Evaluate a precompiled XPath expression.
355
 */
356
static xmlXPathObjectPtr
357
xsltPreCompEval(xsltTransformContextPtr ctxt, xmlNodePtr node,
358
0
                xsltStylePreCompPtr comp) {
359
0
    xmlXPathObjectPtr res;
360
0
    xmlXPathContextPtr xpctxt;
361
0
    xmlNodePtr oldXPContextNode;
362
0
    xmlNsPtr *oldXPNamespaces;
363
0
    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
364
365
0
    xpctxt = ctxt->xpathCtxt;
366
0
    oldXPContextNode = xpctxt->node;
367
0
    oldXPProximityPosition = xpctxt->proximityPosition;
368
0
    oldXPContextSize = xpctxt->contextSize;
369
0
    oldXPNsNr = xpctxt->nsNr;
370
0
    oldXPNamespaces = xpctxt->namespaces;
371
372
0
    xpctxt->node = node;
373
#ifdef XSLT_REFACTORED
374
    if (comp->inScopeNs != NULL) {
375
        xpctxt->namespaces = comp->inScopeNs->list;
376
        xpctxt->nsNr = comp->inScopeNs->xpathNumber;
377
    } else {
378
        xpctxt->namespaces = NULL;
379
        xpctxt->nsNr = 0;
380
    }
381
#else
382
0
    xpctxt->namespaces = comp->nsList;
383
0
    xpctxt->nsNr = comp->nsNr;
384
0
#endif
385
386
0
    res = xmlXPathCompiledEval(comp->comp, xpctxt);
387
388
0
    xpctxt->node = oldXPContextNode;
389
0
    xpctxt->proximityPosition = oldXPProximityPosition;
390
0
    xpctxt->contextSize = oldXPContextSize;
391
0
    xpctxt->nsNr = oldXPNsNr;
392
0
    xpctxt->namespaces = oldXPNamespaces;
393
394
0
    return(res);
395
0
}
396
397
/**
398
 * xsltPreCompEvalToBoolean:
399
 * @ctxt: transform context
400
 * @node: context node
401
 * @comp: precompiled expression
402
 *
403
 * Evaluate a precompiled XPath expression as boolean.
404
 */
405
static int
406
xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt, xmlNodePtr node,
407
0
                         xsltStylePreCompPtr comp) {
408
0
    int res;
409
0
    xmlXPathContextPtr xpctxt;
410
0
    xmlNodePtr oldXPContextNode;
411
0
    xmlNsPtr *oldXPNamespaces;
412
0
    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
413
414
0
    xpctxt = ctxt->xpathCtxt;
415
0
    oldXPContextNode = xpctxt->node;
416
0
    oldXPProximityPosition = xpctxt->proximityPosition;
417
0
    oldXPContextSize = xpctxt->contextSize;
418
0
    oldXPNsNr = xpctxt->nsNr;
419
0
    oldXPNamespaces = xpctxt->namespaces;
420
421
0
    xpctxt->node = node;
422
#ifdef XSLT_REFACTORED
423
    if (comp->inScopeNs != NULL) {
424
        xpctxt->namespaces = comp->inScopeNs->list;
425
        xpctxt->nsNr = comp->inScopeNs->xpathNumber;
426
    } else {
427
        xpctxt->namespaces = NULL;
428
        xpctxt->nsNr = 0;
429
    }
430
#else
431
0
    xpctxt->namespaces = comp->nsList;
432
0
    xpctxt->nsNr = comp->nsNr;
433
0
#endif
434
435
0
    res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
436
437
0
    xpctxt->node = oldXPContextNode;
438
0
    xpctxt->proximityPosition = oldXPProximityPosition;
439
0
    xpctxt->contextSize = oldXPContextSize;
440
0
    xpctxt->nsNr = oldXPNsNr;
441
0
    xpctxt->namespaces = oldXPNamespaces;
442
443
0
    return(res);
444
0
}
445
446
/************************************************************************
447
 *                  *
448
 *      XInclude default settings     *
449
 *                  *
450
 ************************************************************************/
451
452
static int xsltDoXIncludeDefault = 0;
453
454
/**
455
 * xsltSetXIncludeDefault:
456
 * @xinclude: whether to do XInclude processing
457
 *
458
 * Set whether XInclude should be processed on document being loaded by default
459
 */
460
void
461
0
xsltSetXIncludeDefault(int xinclude) {
462
0
    xsltDoXIncludeDefault = (xinclude != 0);
463
0
}
464
465
/**
466
 * xsltGetXIncludeDefault:
467
 *
468
 * Provides the default state for XInclude processing
469
 *
470
 * Returns 0 if there is no processing 1 otherwise
471
 */
472
int
473
3.69k
xsltGetXIncludeDefault(void) {
474
3.69k
    return(xsltDoXIncludeDefault);
475
3.69k
}
476
477
static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
478
479
/**
480
 * xsltDebugSetDefaultTrace:
481
 * @val: tracing level mask
482
 *
483
 * Set the default debug tracing level mask
484
 */
485
0
void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {
486
0
  xsltDefaultTrace = val;
487
0
}
488
489
/**
490
 * xsltDebugGetDefaultTrace:
491
 *
492
 * Get the current default debug tracing level mask
493
 *
494
 * Returns the current default debug tracing level mask
495
 */
496
0
xsltDebugTraceCodes xsltDebugGetDefaultTrace(void) {
497
0
  return xsltDefaultTrace;
498
0
}
499
500
/************************************************************************
501
 *                  *
502
 *      Handling of Transformation Contexts   *
503
 *                  *
504
 ************************************************************************/
505
506
static xsltTransformCachePtr
507
xsltTransformCacheCreate(void)
508
3.69k
{
509
3.69k
    xsltTransformCachePtr ret;
510
511
3.69k
    ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));
512
3.69k
    if (ret == NULL) {
513
0
  xsltTransformError(NULL, NULL, NULL,
514
0
      "xsltTransformCacheCreate : malloc failed\n");
515
0
  return(NULL);
516
0
    }
517
3.69k
    memset(ret, 0, sizeof(xsltTransformCache));
518
3.69k
    return(ret);
519
3.69k
}
520
521
static void
522
xsltTransformCacheFree(xsltTransformCachePtr cache)
523
0
{
524
0
    if (cache == NULL)
525
0
  return;
526
    /*
527
    * Free tree fragments.
528
    */
529
0
    if (cache->RVT) {
530
0
  xmlDocPtr tmp, cur = cache->RVT;
531
0
  while (cur) {
532
0
      tmp = cur;
533
0
      cur = (xmlDocPtr) cur->next;
534
0
      if (tmp->_private != NULL) {
535
    /*
536
    * Tree the document info.
537
    */
538
0
    xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);
539
0
    xmlFree(tmp->_private);
540
0
      }
541
0
      xmlFreeDoc(tmp);
542
0
  }
543
0
    }
544
    /*
545
    * Free vars/params.
546
    */
547
0
    if (cache->stackItems) {
548
0
  xsltStackElemPtr tmp, cur = cache->stackItems;
549
0
  while (cur) {
550
0
      tmp = cur;
551
0
      cur = cur->next;
552
      /*
553
      * REVISIT TODO: Should be call a destruction-function
554
      * instead?
555
      */
556
0
      xmlFree(tmp);
557
0
  }
558
0
    }
559
0
    xmlFree(cache);
560
0
}
561
562
/**
563
 * xsltNewTransformContext:
564
 * @style:  a parsed XSLT stylesheet
565
 * @doc:  the input document
566
 *
567
 * Create a new XSLT TransformContext
568
 *
569
 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
570
 */
571
xsltTransformContextPtr
572
3.69k
xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
573
3.69k
    xsltTransformContextPtr cur;
574
3.69k
    xsltDocumentPtr docu;
575
3.69k
    int i;
576
577
3.69k
    xsltInitGlobals();
578
579
3.69k
    cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
580
3.69k
    if (cur == NULL) {
581
0
  xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
582
0
    "xsltNewTransformContext : malloc failed\n");
583
0
  return(NULL);
584
0
    }
585
3.69k
    memset(cur, 0, sizeof(xsltTransformContext));
586
587
3.69k
    cur->cache = xsltTransformCacheCreate();
588
3.69k
    if (cur->cache == NULL)
589
0
  goto internal_err;
590
    /*
591
     * setup of the dictionary must be done early as some of the
592
     * processing later like key handling may need it.
593
     */
594
3.69k
    cur->dict = xmlDictCreateSub(style->dict);
595
3.69k
    cur->internalized = ((style->internalized) && (cur->dict != NULL));
596
#ifdef WITH_XSLT_DEBUG
597
    xsltGenericDebug(xsltGenericDebugContext,
598
       "Creating sub-dictionary from stylesheet for transformation\n");
599
#endif
600
601
    /*
602
     * initialize the template stack
603
     */
604
3.69k
    cur->templTab = (xsltTemplatePtr *)
605
3.69k
          xmlMalloc(10 * sizeof(xsltTemplatePtr));
606
3.69k
    if (cur->templTab == NULL) {
607
0
  xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
608
0
    "xsltNewTransformContext: out of memory\n");
609
0
  goto internal_err;
610
0
    }
611
3.69k
    cur->templNr = 0;
612
3.69k
    cur->templMax = 5;
613
3.69k
    cur->templ = NULL;
614
3.69k
    cur->maxTemplateDepth = xsltMaxDepth;
615
616
    /*
617
     * initialize the variables stack
618
     */
619
3.69k
    cur->varsTab = (xsltStackElemPtr *)
620
3.69k
          xmlMalloc(10 * sizeof(xsltStackElemPtr));
621
3.69k
    if (cur->varsTab == NULL) {
622
0
        xmlGenericError(xmlGenericErrorContext,
623
0
    "xsltNewTransformContext: out of memory\n");
624
0
  goto internal_err;
625
0
    }
626
3.69k
    cur->varsNr = 0;
627
3.69k
    cur->varsMax = 10;
628
3.69k
    cur->vars = NULL;
629
3.69k
    cur->varsBase = 0;
630
3.69k
    cur->maxTemplateVars = xsltMaxVars;
631
632
    /*
633
     * the profiling stack is not initialized by default
634
     */
635
3.69k
    cur->profTab = NULL;
636
3.69k
    cur->profNr = 0;
637
3.69k
    cur->profMax = 0;
638
3.69k
    cur->prof = 0;
639
640
3.69k
    cur->style = style;
641
3.69k
    cur->xpathCtxt = xmlXPathNewContext(doc);
642
3.69k
    if (cur->xpathCtxt == NULL) {
643
0
  xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
644
0
    "xsltNewTransformContext : xmlXPathNewContext failed\n");
645
0
  goto internal_err;
646
0
    }
647
    /*
648
    * Create an XPath cache.
649
    */
650
3.69k
    if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
651
0
  goto internal_err;
652
    /*
653
     * Initialize the extras array
654
     */
655
3.69k
    if (style->extrasNr != 0) {
656
0
  cur->extrasMax = style->extrasNr + 20;
657
0
  cur->extras = (xsltRuntimeExtraPtr)
658
0
      xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
659
0
  if (cur->extras == NULL) {
660
0
      xmlGenericError(xmlGenericErrorContext,
661
0
        "xsltNewTransformContext: out of memory\n");
662
0
      goto internal_err;
663
0
  }
664
0
  cur->extrasNr = style->extrasNr;
665
0
  for (i = 0;i < cur->extrasMax;i++) {
666
0
      cur->extras[i].info = NULL;
667
0
      cur->extras[i].deallocate = NULL;
668
0
      cur->extras[i].val.ptr = NULL;
669
0
  }
670
3.69k
    } else {
671
3.69k
  cur->extras = NULL;
672
3.69k
  cur->extrasNr = 0;
673
3.69k
  cur->extrasMax = 0;
674
3.69k
    }
675
676
3.69k
    XSLT_REGISTER_VARIABLE_LOOKUP(cur);
677
3.69k
    XSLT_REGISTER_FUNCTION_LOOKUP(cur);
678
3.69k
    cur->xpathCtxt->nsHash = style->nsHash;
679
    /*
680
     * Initialize the registered external modules
681
     */
682
3.69k
    xsltInitCtxtExts(cur);
683
    /*
684
     * Setup document element ordering for later efficiencies
685
     * (bug 133289)
686
     */
687
3.69k
    if (xslDebugStatus == XSLT_DEBUG_NONE)
688
3.69k
        xmlXPathOrderDocElems(doc);
689
    /*
690
     * Must set parserOptions before calling xsltNewDocument
691
     * (bug 164530)
692
     */
693
3.69k
    cur->parserOptions = XSLT_PARSE_OPTIONS;
694
3.69k
    docu = xsltNewDocument(cur, doc);
695
3.69k
    if (docu == NULL) {
696
0
  xsltTransformError(cur, NULL, (xmlNodePtr)doc,
697
0
    "xsltNewTransformContext : xsltNewDocument failed\n");
698
0
  goto internal_err;
699
0
    }
700
3.69k
    docu->main = 1;
701
3.69k
    cur->document = docu;
702
3.69k
    cur->inst = NULL;
703
3.69k
    cur->outputFile = NULL;
704
3.69k
    cur->sec = xsltGetDefaultSecurityPrefs();
705
3.69k
    cur->debugStatus = xslDebugStatus;
706
3.69k
    cur->traceCode = (unsigned long*) &xsltDefaultTrace;
707
3.69k
    cur->xinclude = xsltGetXIncludeDefault();
708
3.69k
    cur->keyInitLevel = 0;
709
710
3.69k
    cur->newLocale = xsltNewLocale;
711
3.69k
    cur->freeLocale = xsltFreeLocale;
712
3.69k
    cur->genSortKey = xsltStrxfrm;
713
714
3.69k
    return(cur);
715
716
0
internal_err:
717
0
    if (cur != NULL)
718
0
  xsltFreeTransformContext(cur);
719
0
    return(NULL);
720
3.69k
}
721
722
/**
723
 * xsltFreeTransformContext:
724
 * @ctxt:  an XSLT transform context
725
 *
726
 * Free up the memory allocated by @ctxt
727
 */
728
void
729
0
xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
730
0
    if (ctxt == NULL)
731
0
  return;
732
733
    /*
734
     * Shutdown the extension modules associated to the stylesheet
735
     * used if needed.
736
     */
737
0
    xsltShutdownCtxtExts(ctxt);
738
739
0
    if (ctxt->xpathCtxt != NULL) {
740
0
  ctxt->xpathCtxt->nsHash = NULL;
741
0
  xmlXPathFreeContext(ctxt->xpathCtxt);
742
0
    }
743
0
    if (ctxt->templTab != NULL)
744
0
  xmlFree(ctxt->templTab);
745
0
    if (ctxt->varsTab != NULL)
746
0
  xmlFree(ctxt->varsTab);
747
0
    if (ctxt->profTab != NULL)
748
0
  xmlFree(ctxt->profTab);
749
0
    if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
750
0
  int i;
751
752
0
  for (i = 0;i < ctxt->extrasNr;i++) {
753
0
      if ((ctxt->extras[i].deallocate != NULL) &&
754
0
    (ctxt->extras[i].info != NULL))
755
0
    ctxt->extras[i].deallocate(ctxt->extras[i].info);
756
0
  }
757
0
  xmlFree(ctxt->extras);
758
0
    }
759
0
    xsltFreeGlobalVariables(ctxt);
760
0
    xsltFreeDocuments(ctxt);
761
0
    xsltFreeCtxtExts(ctxt);
762
0
    xsltFreeRVTs(ctxt);
763
0
    xsltTransformCacheFree(ctxt->cache);
764
0
    xmlDictFree(ctxt->dict);
765
#ifdef WITH_XSLT_DEBUG
766
    xsltGenericDebug(xsltGenericDebugContext,
767
                     "freeing transformation dictionary\n");
768
#endif
769
0
    memset(ctxt, -1, sizeof(xsltTransformContext));
770
0
    xmlFree(ctxt);
771
0
}
772
773
/************************************************************************
774
 *                  *
775
 *      Copy of Nodes in an XSLT fashion    *
776
 *                  *
777
 ************************************************************************/
778
779
/**
780
 * xsltAddChild:
781
 * @parent:  the parent node
782
 * @cur:  the child node
783
 *
784
 * Wrapper version of xmlAddChild with a more consistent behaviour on
785
 * error. One expect the use to be child = xsltAddChild(parent, child);
786
 * and the routine will take care of not leaking on errors or node merge
787
 *
788
 * Returns the child is successfully attached or NULL if merged or freed
789
 */
790
static xmlNodePtr
791
0
xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
792
0
   xmlNodePtr ret;
793
794
0
   if (cur == NULL)
795
0
       return(NULL);
796
0
   if (parent == NULL) {
797
0
       xmlFreeNode(cur);
798
0
       return(NULL);
799
0
   }
800
0
   ret = xmlAddChild(parent, cur);
801
802
0
   return(ret);
803
0
}
804
805
/**
806
 * xsltAddTextString:
807
 * @ctxt:  a XSLT process context
808
 * @target:  the text node where the text will be attached
809
 * @string:  the text string
810
 * @len:  the string length in byte
811
 *
812
 * Extend the current text node with the new string, it handles coalescing
813
 *
814
 * Returns: the text node
815
 */
816
static xmlNodePtr
817
xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
818
0
      const xmlChar *string, int len) {
819
    /*
820
     * optimization
821
     */
822
0
    if ((len <= 0) || (string == NULL) || (target == NULL))
823
0
        return(target);
824
825
0
    if (ctxt->lasttext == target->content) {
826
0
        int minSize;
827
828
        /* Check for integer overflow accounting for NUL terminator. */
829
0
        if (len >= INT_MAX - ctxt->lasttuse) {
830
0
            xsltTransformError(ctxt, NULL, target,
831
0
                "xsltCopyText: text allocation failed\n");
832
0
            return(NULL);
833
0
        }
834
0
        minSize = ctxt->lasttuse + len + 1;
835
836
0
        if (ctxt->lasttsize < minSize) {
837
0
      xmlChar *newbuf;
838
0
      int size;
839
0
            int extra;
840
841
            /* Double buffer size but increase by at least 100 bytes. */
842
0
            extra = minSize < 100 ? 100 : minSize;
843
844
            /* Check for integer overflow. */
845
0
            if (extra > INT_MAX - ctxt->lasttsize) {
846
0
                size = INT_MAX;
847
0
            }
848
0
            else {
849
0
                size = ctxt->lasttsize + extra;
850
0
            }
851
852
0
      newbuf = (xmlChar *) xmlRealloc(target->content,size);
853
0
      if (newbuf == NULL) {
854
0
    xsltTransformError(ctxt, NULL, target,
855
0
     "xsltCopyText: text allocation failed\n");
856
0
    return(NULL);
857
0
      }
858
0
      ctxt->lasttsize = size;
859
0
      ctxt->lasttext = newbuf;
860
0
      target->content = newbuf;
861
0
  }
862
0
  memcpy(&(target->content[ctxt->lasttuse]), string, len);
863
0
  ctxt->lasttuse += len;
864
0
  target->content[ctxt->lasttuse] = 0;
865
0
    } else {
866
0
  xmlNodeAddContent(target, string);
867
0
  ctxt->lasttext = target->content;
868
0
  len = xmlStrlen(target->content);
869
0
  ctxt->lasttsize = len;
870
0
  ctxt->lasttuse = len;
871
0
    }
872
0
    return(target);
873
0
}
874
875
/**
876
 * xsltCopyTextString:
877
 * @ctxt:  a XSLT process context
878
 * @target:  the element where the text will be attached
879
 * @string:  the text string
880
 * @noescape:  should disable-escaping be activated for this text node.
881
 *
882
 * Adds @string to a newly created or an existent text node child of
883
 * @target.
884
 *
885
 * Returns: the text node, where the text content of @cur is copied to.
886
 *          NULL in case of API or internal errors.
887
 */
888
xmlNodePtr
889
xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
890
             const xmlChar *string, int noescape)
891
0
{
892
0
    xmlNodePtr copy;
893
0
    int len;
894
895
0
    if (string == NULL)
896
0
  return(NULL);
897
898
#ifdef WITH_XSLT_DEBUG_PROCESS
899
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
900
         "xsltCopyTextString: copy text %s\n",
901
         string));
902
#endif
903
904
    /*
905
    * Play safe and reset the merging mechanism for every new
906
    * target node.
907
    */
908
0
    if ((target == NULL) || (target->children == NULL)) {
909
0
  ctxt->lasttext = NULL;
910
0
    }
911
912
    /* handle coalescing of text nodes here */
913
0
    len = xmlStrlen(string);
914
0
    if ((ctxt->type == XSLT_OUTPUT_XML) &&
915
0
  (ctxt->style->cdataSection != NULL) &&
916
0
  (target != NULL) &&
917
0
  (target->type == XML_ELEMENT_NODE) &&
918
0
  (((target->ns == NULL) &&
919
0
    (xmlHashLookup2(ctxt->style->cdataSection,
920
0
              target->name, NULL) != NULL)) ||
921
0
   ((target->ns != NULL) &&
922
0
    (xmlHashLookup2(ctxt->style->cdataSection,
923
0
                    target->name, target->ns->href) != NULL))))
924
0
    {
925
  /*
926
  * Process "cdata-section-elements".
927
  */
928
0
  if ((target->last != NULL) &&
929
0
      (target->last->type == XML_CDATA_SECTION_NODE))
930
0
  {
931
0
      return(xsltAddTextString(ctxt, target->last, string, len));
932
0
  }
933
0
  copy = xmlNewCDataBlock(ctxt->output, string, len);
934
0
    } else if (noescape) {
935
  /*
936
  * Process "disable-output-escaping".
937
  */
938
0
  if ((target != NULL) && (target->last != NULL) &&
939
0
      (target->last->type == XML_TEXT_NODE) &&
940
0
      (target->last->name == xmlStringTextNoenc))
941
0
  {
942
0
      return(xsltAddTextString(ctxt, target->last, string, len));
943
0
  }
944
0
  copy = xmlNewTextLen(string, len);
945
0
  if (copy != NULL)
946
0
      copy->name = xmlStringTextNoenc;
947
0
    } else {
948
  /*
949
  * Default processing.
950
  */
951
0
  if ((target != NULL) && (target->last != NULL) &&
952
0
      (target->last->type == XML_TEXT_NODE) &&
953
0
      (target->last->name == xmlStringText)) {
954
0
      return(xsltAddTextString(ctxt, target->last, string, len));
955
0
  }
956
0
  copy = xmlNewTextLen(string, len);
957
0
    }
958
0
    if (copy != NULL && target != NULL)
959
0
  copy = xsltAddChild(target, copy);
960
0
    if (copy != NULL) {
961
0
  ctxt->lasttext = copy->content;
962
0
  ctxt->lasttsize = len;
963
0
  ctxt->lasttuse = len;
964
0
    } else {
965
0
  xsltTransformError(ctxt, NULL, target,
966
0
       "xsltCopyTextString: text copy failed\n");
967
0
  ctxt->lasttext = NULL;
968
0
    }
969
0
    return(copy);
970
0
}
971
972
/**
973
 * xsltCopyText:
974
 * @ctxt:  a XSLT process context
975
 * @target:  the element where the text will be attached
976
 * @cur:  the text or CDATA node
977
 * @interned:  the string is in the target doc dictionary
978
 *
979
 * Copy the text content of @cur and append it to @target's children.
980
 *
981
 * Returns: the text node, where the text content of @cur is copied to.
982
 *          NULL in case of API or internal errors.
983
 */
984
static xmlNodePtr
985
xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
986
       xmlNodePtr cur, int interned)
987
0
{
988
0
    xmlNodePtr copy;
989
990
0
    if ((cur->type != XML_TEXT_NODE) &&
991
0
  (cur->type != XML_CDATA_SECTION_NODE))
992
0
  return(NULL);
993
0
    if (cur->content == NULL)
994
0
  return(NULL);
995
996
#ifdef WITH_XSLT_DEBUG_PROCESS
997
    if (cur->type == XML_CDATA_SECTION_NODE) {
998
  XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
999
       "xsltCopyText: copy CDATA text %s\n",
1000
       cur->content));
1001
    } else if (cur->name == xmlStringTextNoenc) {
1002
  XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
1003
         "xsltCopyText: copy unescaped text %s\n",
1004
       cur->content));
1005
    } else {
1006
  XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
1007
       "xsltCopyText: copy text %s\n",
1008
       cur->content));
1009
    }
1010
#endif
1011
1012
    /*
1013
    * Play save and reset the merging mechanism for every new
1014
    * target node.
1015
    */
1016
0
    if ((target == NULL) || (target->children == NULL)) {
1017
0
  ctxt->lasttext = NULL;
1018
0
    }
1019
1020
0
    if ((ctxt->style->cdataSection != NULL) &&
1021
0
  (ctxt->type == XSLT_OUTPUT_XML) &&
1022
0
  (target != NULL) &&
1023
0
  (target->type == XML_ELEMENT_NODE) &&
1024
0
  (((target->ns == NULL) &&
1025
0
    (xmlHashLookup2(ctxt->style->cdataSection,
1026
0
              target->name, NULL) != NULL)) ||
1027
0
   ((target->ns != NULL) &&
1028
0
    (xmlHashLookup2(ctxt->style->cdataSection,
1029
0
                    target->name, target->ns->href) != NULL))))
1030
0
    {
1031
  /*
1032
  * Process "cdata-section-elements".
1033
  */
1034
  /*
1035
  * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
1036
  */
1037
  /*
1038
  * TODO: Since this doesn't merge adjacent CDATA-section nodes,
1039
  * we'll get: <![CDATA[x]]><!CDATA[y]]>.
1040
  * TODO: Reported in #321505.
1041
  */
1042
0
  if ((target->last != NULL) &&
1043
0
       (target->last->type == XML_CDATA_SECTION_NODE))
1044
0
  {
1045
      /*
1046
      * Append to existing CDATA-section node.
1047
      */
1048
0
      copy = xsltAddTextString(ctxt, target->last, cur->content,
1049
0
    xmlStrlen(cur->content));
1050
0
      goto exit;
1051
0
  } else {
1052
0
      unsigned int len;
1053
1054
0
      len = xmlStrlen(cur->content);
1055
0
      copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
1056
0
      if (copy == NULL)
1057
0
    goto exit;
1058
0
      ctxt->lasttext = copy->content;
1059
0
      ctxt->lasttsize = len;
1060
0
      ctxt->lasttuse = len;
1061
0
  }
1062
0
    } else if ((target != NULL) &&
1063
0
  (target->last != NULL) &&
1064
  /* both escaped or both non-escaped text-nodes */
1065
0
  (((target->last->type == XML_TEXT_NODE) &&
1066
0
  (target->last->name == cur->name)) ||
1067
        /* non-escaped text nodes and CDATA-section nodes */
1068
0
  (((target->last->type == XML_CDATA_SECTION_NODE) &&
1069
0
  (cur->name == xmlStringTextNoenc)))))
1070
0
    {
1071
  /*
1072
   * we are appending to an existing text node
1073
   */
1074
0
  copy = xsltAddTextString(ctxt, target->last, cur->content,
1075
0
      xmlStrlen(cur->content));
1076
0
  goto exit;
1077
0
    } else if ((interned) && (target != NULL) &&
1078
0
  (target->doc != NULL) &&
1079
0
  (target->doc->dict == ctxt->dict))
1080
0
    {
1081
  /*
1082
  * TODO: DO we want to use this also for "text" output?
1083
  */
1084
0
        copy = xmlNewTextLen(NULL, 0);
1085
0
  if (copy == NULL)
1086
0
      goto exit;
1087
0
  if (cur->name == xmlStringTextNoenc)
1088
0
      copy->name = xmlStringTextNoenc;
1089
1090
  /*
1091
   * Must confirm that content is in dict (bug 302821)
1092
   * TODO: This check should be not needed for text coming
1093
   * from the stylesheets
1094
   */
1095
0
  if (xmlDictOwns(ctxt->dict, cur->content))
1096
0
      copy->content = cur->content;
1097
0
  else {
1098
0
      if ((copy->content = xmlStrdup(cur->content)) == NULL)
1099
0
    return NULL;
1100
0
  }
1101
1102
0
  ctxt->lasttext = NULL;
1103
0
    } else {
1104
        /*
1105
   * normal processing. keep counters to extend the text node
1106
   * in xsltAddTextString if needed.
1107
   */
1108
0
        unsigned int len;
1109
1110
0
  len = xmlStrlen(cur->content);
1111
0
  copy = xmlNewTextLen(cur->content, len);
1112
0
  if (copy == NULL)
1113
0
      goto exit;
1114
0
  if (cur->name == xmlStringTextNoenc)
1115
0
      copy->name = xmlStringTextNoenc;
1116
0
  ctxt->lasttext = copy->content;
1117
0
  ctxt->lasttsize = len;
1118
0
  ctxt->lasttuse = len;
1119
0
    }
1120
0
    if (copy != NULL) {
1121
0
  if (target != NULL) {
1122
0
      copy->doc = target->doc;
1123
      /*
1124
      * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1125
      *  to ensure that the optimized text-merging mechanism
1126
      *  won't interfere with normal node-merging in any case.
1127
      */
1128
0
      copy = xsltAddChild(target, copy);
1129
0
  }
1130
0
    } else {
1131
0
  xsltTransformError(ctxt, NULL, target,
1132
0
       "xsltCopyText: text copy failed\n");
1133
0
    }
1134
1135
0
exit:
1136
0
    if ((copy == NULL) || (copy->content == NULL)) {
1137
0
  xsltTransformError(ctxt, NULL, target,
1138
0
      "Internal error in xsltCopyText(): "
1139
0
      "Failed to copy the string.\n");
1140
0
  ctxt->state = XSLT_STATE_STOPPED;
1141
0
    }
1142
0
    return(copy);
1143
0
}
1144
1145
/**
1146
 * xsltShallowCopyAttr:
1147
 * @ctxt:  a XSLT process context
1148
 * @invocNode: responsible node in the stylesheet; used for error reports
1149
 * @target:  the element where the attribute will be grafted
1150
 * @attr: the attribute to be copied
1151
 *
1152
 * Do a copy of an attribute.
1153
 * Called by:
1154
 *  - xsltCopyTree()
1155
 *  - xsltCopyOf()
1156
 *  - xsltCopy()
1157
 *
1158
 * Returns: a new xmlAttrPtr, or NULL in case of error.
1159
 */
1160
static xmlAttrPtr
1161
xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1162
       xmlNodePtr target, xmlAttrPtr attr)
1163
0
{
1164
0
    xmlAttrPtr copy;
1165
0
    xmlChar *value;
1166
1167
0
    if (attr == NULL)
1168
0
  return(NULL);
1169
1170
0
    if (target->type != XML_ELEMENT_NODE) {
1171
0
  xsltTransformError(ctxt, NULL, invocNode,
1172
0
      "Cannot add an attribute node to a non-element node.\n");
1173
0
  return(NULL);
1174
0
    }
1175
1176
0
    if (target->children != NULL) {
1177
0
  xsltTransformError(ctxt, NULL, invocNode,
1178
0
      "Attribute nodes must be added before "
1179
0
      "any child nodes to an element.\n");
1180
0
  return(NULL);
1181
0
    }
1182
1183
0
    value = xmlNodeListGetString(attr->doc, attr->children, 1);
1184
0
    if (attr->ns != NULL) {
1185
0
  xmlNsPtr ns;
1186
1187
0
  ns = xsltGetSpecialNamespace(ctxt, invocNode,
1188
0
      attr->ns->href, attr->ns->prefix, target);
1189
0
  if (ns == NULL) {
1190
0
      xsltTransformError(ctxt, NULL, invocNode,
1191
0
    "Namespace fixup error: Failed to acquire an in-scope "
1192
0
    "namespace binding of the copied attribute '{%s}%s'.\n",
1193
0
    attr->ns->href, attr->name);
1194
      /*
1195
      * TODO: Should we just stop here?
1196
      */
1197
0
  }
1198
  /*
1199
  * Note that xmlSetNsProp() will take care of duplicates
1200
  * and assigns the new namespace even to a duplicate.
1201
  */
1202
0
  copy = xmlSetNsProp(target, ns, attr->name, value);
1203
0
    } else {
1204
0
  copy = xmlSetNsProp(target, NULL, attr->name, value);
1205
0
    }
1206
0
    if (value != NULL)
1207
0
  xmlFree(value);
1208
1209
0
    if (copy == NULL)
1210
0
  return(NULL);
1211
1212
#if 0
1213
    /*
1214
    * NOTE: This was optimized according to bug #342695.
1215
    * TODO: Can this further be optimized, if source and target
1216
    *  share the same dict and attr->children is just 1 text node
1217
    *  which is in the dict? How probable is such a case?
1218
    */
1219
    /*
1220
    * TODO: Do we need to create an empty text node if the value
1221
    *  is the empty string?
1222
    */
1223
    value = xmlNodeListGetString(attr->doc, attr->children, 1);
1224
    if (value != NULL) {
1225
  txtNode = xmlNewDocText(target->doc, NULL);
1226
  if (txtNode == NULL)
1227
      return(NULL);
1228
  if ((target->doc != NULL) &&
1229
      (target->doc->dict != NULL))
1230
  {
1231
      txtNode->content =
1232
    (xmlChar *) xmlDictLookup(target->doc->dict,
1233
        BAD_CAST value, -1);
1234
      xmlFree(value);
1235
  } else
1236
      txtNode->content = value;
1237
  copy->children = txtNode;
1238
    }
1239
#endif
1240
1241
0
    return(copy);
1242
0
}
1243
1244
/**
1245
 * xsltCopyAttrListNoOverwrite:
1246
 * @ctxt:  a XSLT process context
1247
 * @invocNode: responsible node in the stylesheet; used for error reports
1248
 * @target:  the element where the new attributes will be grafted
1249
 * @attr:  the first attribute in the list to be copied
1250
 *
1251
 * Copies a list of attribute nodes, starting with @attr, over to the
1252
 * @target element node.
1253
 *
1254
 * Called by:
1255
 *  - xsltCopyTree()
1256
 *
1257
 * Returns 0 on success and -1 on errors and internal errors.
1258
 */
1259
static int
1260
xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
1261
          xmlNodePtr invocNode,
1262
          xmlNodePtr target, xmlAttrPtr attr)
1263
0
{
1264
0
    xmlAttrPtr copy;
1265
0
    xmlNsPtr origNs = NULL, copyNs = NULL;
1266
0
    xmlChar *value;
1267
1268
    /*
1269
    * Don't use xmlCopyProp() here, since it will try to
1270
    * reconciliate namespaces.
1271
    */
1272
0
    while (attr != NULL) {
1273
  /*
1274
  * Find a namespace node in the tree of @target.
1275
  * Avoid searching for the same ns.
1276
  */
1277
0
  if (attr->ns != origNs) {
1278
0
      origNs = attr->ns;
1279
0
      if (attr->ns != NULL) {
1280
0
    copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
1281
0
        attr->ns->href, attr->ns->prefix, target);
1282
0
    if (copyNs == NULL)
1283
0
        return(-1);
1284
0
      } else
1285
0
    copyNs = NULL;
1286
0
  }
1287
  /*
1288
   * If attribute has a value, we need to copy it (watching out
1289
   * for possible entities)
1290
   */
1291
0
  if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
1292
0
            (attr->children->next == NULL)) {
1293
0
            copy = xmlNewNsProp(target, copyNs, attr->name,
1294
0
                                attr->children->content);
1295
0
        } else if (attr->children != NULL) {
1296
0
      value = xmlNodeListGetString(attr->doc, attr->children, 1);
1297
0
            copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
1298
0
      xmlFree(value);
1299
0
        } else {
1300
0
            copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
1301
0
        }
1302
1303
0
  if (copy == NULL)
1304
0
      return(-1);
1305
1306
0
  attr = attr->next;
1307
0
    }
1308
0
    return(0);
1309
0
}
1310
1311
/**
1312
 * xsltShallowCopyElem:
1313
 * @ctxt:  the XSLT process context
1314
 * @node:  the element node in the source tree
1315
 *         or the Literal Result Element
1316
 * @insert:  the parent in the result tree
1317
 * @isLRE: if @node is a Literal Result Element
1318
 *
1319
 * Make a copy of the element node @node
1320
 * and insert it as last child of @insert.
1321
 *
1322
 * URGENT TODO: The problem with this one (for the non-refactored code)
1323
 * is that it is used for both, Literal Result Elements *and*
1324
 * copying input nodes.
1325
 *
1326
 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1327
 *
1328
 * Called from:
1329
 *   xsltApplySequenceConstructor()
1330
 *    (for Literal Result Elements - which is a problem)
1331
 *   xsltCopy() (for shallow-copying elements via xsl:copy)
1332
 *
1333
 * Returns a pointer to the new node, or NULL in case of error
1334
 */
1335
static xmlNodePtr
1336
xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
1337
        xmlNodePtr insert, int isLRE)
1338
0
{
1339
0
    xmlNodePtr copy;
1340
1341
0
    if ((node->type == XML_DTD_NODE) || (insert == NULL))
1342
0
  return(NULL);
1343
0
    if ((node->type == XML_TEXT_NODE) ||
1344
0
  (node->type == XML_CDATA_SECTION_NODE))
1345
0
  return(xsltCopyText(ctxt, insert, node, 0));
1346
1347
0
    copy = xmlDocCopyNode(node, insert->doc, 0);
1348
0
    if (copy != NULL) {
1349
0
  copy->doc = ctxt->output;
1350
0
  copy = xsltAddChild(insert, copy);
1351
0
        if (copy == NULL) {
1352
0
             xsltTransformError(ctxt, NULL, node,
1353
0
                "xsltShallowCopyElem: copy failed\n");
1354
0
             return (copy);
1355
0
        }
1356
1357
0
  if (node->type == XML_ELEMENT_NODE) {
1358
      /*
1359
       * Add namespaces as they are needed
1360
       */
1361
0
      if (node->nsDef != NULL) {
1362
    /*
1363
    * TODO: Remove the LRE case in the refactored code
1364
    * gets enabled.
1365
    */
1366
0
    if (isLRE)
1367
0
        xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1368
0
    else
1369
0
        xsltCopyNamespaceListInternal(copy, node->nsDef);
1370
0
      }
1371
1372
      /*
1373
      * URGENT TODO: The problem with this is that it does not
1374
      *  copy over all namespace nodes in scope.
1375
      *  The damn thing about this is, that we would need to
1376
      *  use the xmlGetNsList(), for every single node; this is
1377
      *  also done in xsltCopyTree(), but only for the top node.
1378
      */
1379
0
      if (node->ns != NULL) {
1380
0
    if (isLRE) {
1381
        /*
1382
        * REVISIT TODO: Since the non-refactored code still does
1383
        *  ns-aliasing, we need to call xsltGetNamespace() here.
1384
        *  Remove this when ready.
1385
        */
1386
0
        copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
1387
0
    } else {
1388
0
        copy->ns = xsltGetSpecialNamespace(ctxt,
1389
0
      node, node->ns->href, node->ns->prefix, copy);
1390
1391
0
    }
1392
0
      } else if ((insert->type == XML_ELEMENT_NODE) &&
1393
0
           (insert->ns != NULL))
1394
0
      {
1395
    /*
1396
    * "Undeclare" the default namespace.
1397
    */
1398
0
    xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
1399
0
      }
1400
0
  }
1401
0
    } else {
1402
0
  xsltTransformError(ctxt, NULL, node,
1403
0
    "xsltShallowCopyElem: copy %s failed\n", node->name);
1404
0
    }
1405
0
    return(copy);
1406
0
}
1407
1408
/**
1409
 * xsltCopyTreeList:
1410
 * @ctxt:  a XSLT process context
1411
 * @invocNode: responsible node in the stylesheet; used for error reports
1412
 * @list:  the list of element nodes in the source tree.
1413
 * @insert:  the parent in the result tree.
1414
 * @isLRE:  is this a literal result element list
1415
 * @topElemVisited: indicates if a top-most element was already processed
1416
 *
1417
 * Make a copy of the full list of tree @list
1418
 * and insert it as last children of @insert
1419
 *
1420
 * NOTE: Not to be used for Literal Result Elements.
1421
 *
1422
 * Used by:
1423
 *  - xsltCopyOf()
1424
 *
1425
 * Returns a pointer to the new list, or NULL in case of error
1426
 */
1427
static xmlNodePtr
1428
xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1429
     xmlNodePtr list,
1430
     xmlNodePtr insert, int isLRE, int topElemVisited)
1431
0
{
1432
0
    xmlNodePtr copy, ret = NULL;
1433
1434
0
    while (list != NULL) {
1435
0
  copy = xsltCopyTree(ctxt, invocNode,
1436
0
      list, insert, isLRE, topElemVisited);
1437
0
  if (copy != NULL) {
1438
0
      if (ret == NULL) {
1439
0
    ret = copy;
1440
0
      }
1441
0
  }
1442
0
  list = list->next;
1443
0
    }
1444
0
    return(ret);
1445
0
}
1446
1447
/**
1448
 * xsltCopyNamespaceListInternal:
1449
 * @node:  the target node
1450
 * @cur:  the first namespace
1451
 *
1452
 * Do a copy of a namespace list. If @node is non-NULL the
1453
 * new namespaces are added automatically.
1454
 * Called by:
1455
 *   xsltCopyTree()
1456
 *
1457
 * QUESTION: What is the exact difference between this function
1458
 *  and xsltCopyNamespaceList() in "namespaces.c"?
1459
 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1460
 *
1461
 * Returns: a new xmlNsPtr, or NULL in case of error.
1462
 */
1463
static xmlNsPtr
1464
0
xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
1465
0
    xmlNsPtr ret = NULL;
1466
0
    xmlNsPtr p = NULL, q, luNs;
1467
1468
0
    if (ns == NULL)
1469
0
  return(NULL);
1470
    /*
1471
     * One can add namespaces only on element nodes
1472
     */
1473
0
    if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
1474
0
  elem = NULL;
1475
1476
0
    do {
1477
0
  if (ns->type != XML_NAMESPACE_DECL)
1478
0
      break;
1479
  /*
1480
   * Avoid duplicating namespace declarations on the tree.
1481
   */
1482
0
  if (elem != NULL) {
1483
0
      if ((elem->ns != NULL) &&
1484
0
    xmlStrEqual(elem->ns->prefix, ns->prefix) &&
1485
0
    xmlStrEqual(elem->ns->href, ns->href))
1486
0
      {
1487
0
    ns = ns->next;
1488
0
    continue;
1489
0
      }
1490
0
      luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
1491
0
      if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
1492
0
      {
1493
0
    ns = ns->next;
1494
0
    continue;
1495
0
      }
1496
0
  }
1497
0
  q = xmlNewNs(elem, ns->href, ns->prefix);
1498
0
  if (p == NULL) {
1499
0
      ret = p = q;
1500
0
  } else if (q != NULL) {
1501
0
      p->next = q;
1502
0
      p = q;
1503
0
  }
1504
0
  ns = ns->next;
1505
0
    } while (ns != NULL);
1506
0
    return(ret);
1507
0
}
1508
1509
/**
1510
 * xsltShallowCopyNsNode:
1511
 * @ctxt:  the XSLT transformation context
1512
 * @invocNode: responsible node in the stylesheet; used for error reports
1513
 * @insert:  the target element node in the result tree
1514
 * @ns: the namespace node
1515
 *
1516
 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1517
 *
1518
 * Returns a new/existing ns-node, or NULL.
1519
 */
1520
static xmlNsPtr
1521
xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
1522
          xmlNodePtr invocNode,
1523
          xmlNodePtr insert,
1524
          xmlNsPtr ns)
1525
0
{
1526
    /*
1527
     * TODO: Contrary to header comments, this is declared as int.
1528
     * be modified to return a node pointer, or NULL if any error
1529
     */
1530
0
    xmlNsPtr tmpns;
1531
1532
0
    if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
1533
0
  return(NULL);
1534
1535
0
    if (insert->children != NULL) {
1536
0
  xsltTransformError(ctxt, NULL, invocNode,
1537
0
      "Namespace nodes must be added before "
1538
0
      "any child nodes are added to an element.\n");
1539
0
  return(NULL);
1540
0
    }
1541
    /*
1542
     * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1543
     * an equal prefix. We definitively won't do that.
1544
     *
1545
     * MSXML 4.0 and the .NET ignores ns-decls for which an
1546
     * equal prefix is already in use.
1547
     *
1548
     * Saxon raises an error like:
1549
     * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1550
     * nodes with the same name".
1551
     *
1552
     * NOTE: We'll currently follow MSXML here.
1553
     * REVISIT TODO: Check if it's better to follow Saxon here.
1554
     */
1555
0
    if (ns->prefix == NULL) {
1556
  /*
1557
  * If we are adding ns-nodes to an element using e.g.
1558
  * <xsl:copy-of select="/foo/namespace::*">, then we need
1559
  * to ensure that we don't incorrectly declare a default
1560
  * namespace on an element in no namespace, which otherwise
1561
  * would move the element incorrectly into a namespace, if
1562
  * the node tree is serialized.
1563
  */
1564
0
  if (insert->ns == NULL)
1565
0
      goto occupied;
1566
0
    } else if ((ns->prefix[0] == 'x') &&
1567
0
  xmlStrEqual(ns->prefix, BAD_CAST "xml"))
1568
0
    {
1569
  /*
1570
  * The XML namespace is built in.
1571
  */
1572
0
  return(NULL);
1573
0
    }
1574
1575
0
    if (insert->nsDef != NULL) {
1576
0
  tmpns = insert->nsDef;
1577
0
  do {
1578
0
      if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
1579
0
    if ((tmpns->prefix == ns->prefix) ||
1580
0
        xmlStrEqual(tmpns->prefix, ns->prefix))
1581
0
    {
1582
        /*
1583
        * Same prefix.
1584
        */
1585
0
        if (xmlStrEqual(tmpns->href, ns->href))
1586
0
      return(NULL);
1587
0
        goto occupied;
1588
0
    }
1589
0
      }
1590
0
      tmpns = tmpns->next;
1591
0
  } while (tmpns != NULL);
1592
0
    }
1593
0
    tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
1594
0
    if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
1595
0
  return(NULL);
1596
    /*
1597
    * Declare a new namespace.
1598
    * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1599
    * that it will again search the already declared namespaces
1600
    * for a duplicate :-/
1601
    */
1602
0
    return(xmlNewNs(insert, ns->href, ns->prefix));
1603
1604
0
occupied:
1605
    /*
1606
    * TODO: We could as well raise an error here (like Saxon does),
1607
    * or at least generate a warning.
1608
    */
1609
0
    return(NULL);
1610
0
}
1611
1612
/**
1613
 * xsltCopyTree:
1614
 * @ctxt:  the XSLT transformation context
1615
 * @invocNode: responsible node in the stylesheet; used for error reports
1616
 * @node:  the element node in the source tree
1617
 * @insert:  the parent in the result tree
1618
 * @isLRE:  indicates if @node is a Literal Result Element
1619
 * @topElemVisited: indicates if a top-most element was already processed
1620
 *
1621
 * Make a copy of the full tree under the element node @node
1622
 * and insert it as last child of @insert
1623
 *
1624
 * NOTE: Not to be used for Literal Result Elements.
1625
 *
1626
 * Used by:
1627
 *  - xsltCopyOf()
1628
 *
1629
 * Returns a pointer to the new tree, or NULL in case of error
1630
 */
1631
static xmlNodePtr
1632
xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1633
       xmlNodePtr node, xmlNodePtr insert, int isLRE,
1634
       int topElemVisited)
1635
0
{
1636
0
    xmlNodePtr copy;
1637
1638
0
    if (node == NULL)
1639
0
  return(NULL);
1640
0
    switch (node->type) {
1641
0
        case XML_ELEMENT_NODE:
1642
0
        case XML_ENTITY_REF_NODE:
1643
0
        case XML_ENTITY_NODE:
1644
0
        case XML_PI_NODE:
1645
0
        case XML_COMMENT_NODE:
1646
0
        case XML_DOCUMENT_NODE:
1647
0
        case XML_HTML_DOCUMENT_NODE:
1648
#ifdef LIBXML_DOCB_ENABLED
1649
        case XML_DOCB_DOCUMENT_NODE:
1650
#endif
1651
0
      break;
1652
0
        case XML_TEXT_NODE: {
1653
0
      int noenc = (node->name == xmlStringTextNoenc);
1654
0
      return(xsltCopyTextString(ctxt, insert, node->content, noenc));
1655
0
      }
1656
0
        case XML_CDATA_SECTION_NODE:
1657
0
      return(xsltCopyTextString(ctxt, insert, node->content, 0));
1658
0
        case XML_ATTRIBUTE_NODE:
1659
0
      return((xmlNodePtr)
1660
0
    xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
1661
0
        case XML_NAMESPACE_DECL:
1662
0
      return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
1663
0
    insert, (xmlNsPtr) node));
1664
1665
0
        case XML_DOCUMENT_TYPE_NODE:
1666
0
        case XML_DOCUMENT_FRAG_NODE:
1667
0
        case XML_NOTATION_NODE:
1668
0
        case XML_DTD_NODE:
1669
0
        case XML_ELEMENT_DECL:
1670
0
        case XML_ATTRIBUTE_DECL:
1671
0
        case XML_ENTITY_DECL:
1672
0
        case XML_XINCLUDE_START:
1673
0
        case XML_XINCLUDE_END:
1674
0
            return(NULL);
1675
0
    }
1676
0
    if (XSLT_IS_RES_TREE_FRAG(node)) {
1677
0
  if (node->children != NULL)
1678
0
      copy = xsltCopyTreeList(ctxt, invocNode,
1679
0
    node->children, insert, 0, 0);
1680
0
  else
1681
0
      copy = NULL;
1682
0
  return(copy);
1683
0
    }
1684
0
    copy = xmlDocCopyNode(node, insert->doc, 0);
1685
0
    if (copy != NULL) {
1686
0
  copy->doc = ctxt->output;
1687
0
  copy = xsltAddChild(insert, copy);
1688
0
        if (copy == NULL) {
1689
0
            xsltTransformError(ctxt, NULL, invocNode,
1690
0
            "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1691
0
            return (copy);
1692
0
        }
1693
  /*
1694
   * The node may have been coalesced into another text node.
1695
   */
1696
0
  if (insert->last != copy)
1697
0
      return(insert->last);
1698
0
  copy->next = NULL;
1699
1700
0
  if (node->type == XML_ELEMENT_NODE) {
1701
      /*
1702
      * Copy in-scope namespace nodes.
1703
      *
1704
      * REVISIT: Since we try to reuse existing in-scope ns-decls by
1705
      *  using xmlSearchNsByHref(), this will eventually change
1706
      *  the prefix of an original ns-binding; thus it might
1707
      *  break QNames in element/attribute content.
1708
      * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1709
      *  context, plus a ns-lookup function, which writes directly
1710
      *  to a given list, then we wouldn't need to create/free the
1711
      *  nsList every time.
1712
      */
1713
0
      if ((topElemVisited == 0) &&
1714
0
    (node->parent != NULL) &&
1715
0
    (node->parent->type != XML_DOCUMENT_NODE) &&
1716
0
    (node->parent->type != XML_HTML_DOCUMENT_NODE))
1717
0
      {
1718
0
    xmlNsPtr *nsList, *curns, ns;
1719
1720
    /*
1721
    * If this is a top-most element in a tree to be
1722
    * copied, then we need to ensure that all in-scope
1723
    * namespaces are copied over. For nodes deeper in the
1724
    * tree, it is sufficient to reconcile only the ns-decls
1725
    * (node->nsDef entries).
1726
    */
1727
1728
0
    nsList = xmlGetNsList(node->doc, node);
1729
0
    if (nsList != NULL) {
1730
0
        curns = nsList;
1731
0
        do {
1732
      /*
1733
      * Search by prefix first in order to break as less
1734
      * QNames in element/attribute content as possible.
1735
      */
1736
0
      ns = xmlSearchNs(insert->doc, insert,
1737
0
          (*curns)->prefix);
1738
1739
0
      if ((ns == NULL) ||
1740
0
          (! xmlStrEqual(ns->href, (*curns)->href)))
1741
0
      {
1742
0
          ns = NULL;
1743
          /*
1744
          * Search by namespace name.
1745
          * REVISIT TODO: Currently disabled.
1746
          */
1747
#if 0
1748
          ns = xmlSearchNsByHref(insert->doc,
1749
        insert, (*curns)->href);
1750
#endif
1751
0
      }
1752
0
      if (ns == NULL) {
1753
          /*
1754
          * Declare a new namespace on the copied element.
1755
          */
1756
0
          ns = xmlNewNs(copy, (*curns)->href,
1757
0
        (*curns)->prefix);
1758
          /* TODO: Handle errors */
1759
0
      }
1760
0
      if (node->ns == *curns) {
1761
          /*
1762
          * If this was the original's namespace then set
1763
          * the generated counterpart on the copy.
1764
          */
1765
0
          copy->ns = ns;
1766
0
      }
1767
0
      curns++;
1768
0
        } while (*curns != NULL);
1769
0
        xmlFree(nsList);
1770
0
    }
1771
0
      } else if (node->nsDef != NULL) {
1772
    /*
1773
    * Copy over all namespace declaration attributes.
1774
    */
1775
0
    if (node->nsDef != NULL) {
1776
0
        if (isLRE)
1777
0
      xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1778
0
        else
1779
0
      xsltCopyNamespaceListInternal(copy, node->nsDef);
1780
0
    }
1781
0
      }
1782
      /*
1783
      * Set the namespace.
1784
      */
1785
0
      if (node->ns != NULL) {
1786
0
    if (copy->ns == NULL) {
1787
        /*
1788
        * This will map copy->ns to one of the newly created
1789
        * in-scope ns-decls, OR create a new ns-decl on @copy.
1790
        */
1791
0
        copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
1792
0
      node->ns->href, node->ns->prefix, copy);
1793
0
    }
1794
0
      } else if ((insert->type == XML_ELEMENT_NODE) &&
1795
0
    (insert->ns != NULL))
1796
0
      {
1797
    /*
1798
    * "Undeclare" the default namespace on @copy with xmlns="".
1799
    */
1800
0
    xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
1801
0
      }
1802
      /*
1803
      * Copy attribute nodes.
1804
      */
1805
0
      if (node->properties != NULL) {
1806
0
    xsltCopyAttrListNoOverwrite(ctxt, invocNode,
1807
0
        copy, node->properties);
1808
0
      }
1809
0
      if (topElemVisited == 0)
1810
0
    topElemVisited = 1;
1811
0
  }
1812
  /*
1813
  * Copy the subtree.
1814
  */
1815
0
  if (node->children != NULL) {
1816
0
      xsltCopyTreeList(ctxt, invocNode,
1817
0
    node->children, copy, isLRE, topElemVisited);
1818
0
  }
1819
0
    } else {
1820
0
  xsltTransformError(ctxt, NULL, invocNode,
1821
0
      "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1822
0
    }
1823
0
    return(copy);
1824
0
}
1825
1826
/************************************************************************
1827
 *                  *
1828
 *    Error/fallback processing       *
1829
 *                  *
1830
 ************************************************************************/
1831
1832
/**
1833
 * xsltApplyFallbacks:
1834
 * @ctxt:  a XSLT process context
1835
 * @node:  the node in the source tree.
1836
 * @inst:  the node generating the error
1837
 *
1838
 * Process possible xsl:fallback nodes present under @inst
1839
 *
1840
 * Returns the number of xsl:fallback element found and processed
1841
 */
1842
static int
1843
xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,
1844
0
             xmlNodePtr inst) {
1845
1846
0
    xmlNodePtr child;
1847
0
    int ret = 0;
1848
1849
0
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
1850
0
  (inst->children == NULL))
1851
0
  return(0);
1852
1853
0
    child = inst->children;
1854
0
    while (child != NULL) {
1855
0
        if ((IS_XSLT_ELEM(child)) &&
1856
0
            (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
1857
#ifdef WITH_XSLT_DEBUG_PARSING
1858
      xsltGenericDebug(xsltGenericDebugContext,
1859
           "applying xsl:fallback\n");
1860
#endif
1861
0
      ret++;
1862
0
      xsltApplySequenceConstructor(ctxt, node, child->children,
1863
0
    NULL);
1864
0
  }
1865
0
  child = child->next;
1866
0
    }
1867
0
    return(ret);
1868
0
}
1869
1870
/************************************************************************
1871
 *                  *
1872
 *      Default processing        *
1873
 *                  *
1874
 ************************************************************************/
1875
1876
/**
1877
 * xsltDefaultProcessOneNode:
1878
 * @ctxt:  a XSLT process context
1879
 * @node:  the node in the source tree.
1880
 * @params: extra parameters passed to the template if any
1881
 *
1882
 * Process the source node with the default built-in template rule:
1883
 * <xsl:template match="*|/">
1884
 *   <xsl:apply-templates/>
1885
 * </xsl:template>
1886
 *
1887
 * and
1888
 *
1889
 * <xsl:template match="text()|@*">
1890
 *   <xsl:value-of select="."/>
1891
 * </xsl:template>
1892
 *
1893
 * Note also that namespace declarations are copied directly:
1894
 *
1895
 * the built-in template rule is the only template rule that is applied
1896
 * for namespace nodes.
1897
 */
1898
static void
1899
xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
1900
0
        xsltStackElemPtr params) {
1901
0
    xmlNodePtr copy;
1902
0
    xmlNodePtr cur;
1903
0
    int nbchild = 0, oldSize;
1904
0
    int childno = 0, oldPos;
1905
0
    xsltTemplatePtr template;
1906
1907
0
    CHECK_STOPPED;
1908
    /*
1909
     * Handling of leaves
1910
     */
1911
0
    switch (node->type) {
1912
0
  case XML_DOCUMENT_NODE:
1913
0
  case XML_HTML_DOCUMENT_NODE:
1914
0
  case XML_ELEMENT_NODE:
1915
0
      break;
1916
0
  case XML_CDATA_SECTION_NODE:
1917
#ifdef WITH_XSLT_DEBUG_PROCESS
1918
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1919
       "xsltDefaultProcessOneNode: copy CDATA %s\n",
1920
    node->content));
1921
#endif
1922
0
      copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1923
0
      if (copy == NULL) {
1924
0
    xsltTransformError(ctxt, NULL, node,
1925
0
     "xsltDefaultProcessOneNode: cdata copy failed\n");
1926
0
      }
1927
0
      return;
1928
0
  case XML_TEXT_NODE:
1929
#ifdef WITH_XSLT_DEBUG_PROCESS
1930
      if (node->content == NULL) {
1931
    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1932
     "xsltDefaultProcessOneNode: copy empty text\n"));
1933
    return;
1934
      } else {
1935
    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1936
     "xsltDefaultProcessOneNode: copy text %s\n",
1937
      node->content));
1938
            }
1939
#endif
1940
0
      copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1941
0
      if (copy == NULL) {
1942
0
    xsltTransformError(ctxt, NULL, node,
1943
0
     "xsltDefaultProcessOneNode: text copy failed\n");
1944
0
      }
1945
0
      return;
1946
0
  case XML_ATTRIBUTE_NODE:
1947
0
      cur = node->children;
1948
0
      while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
1949
0
    cur = cur->next;
1950
0
      if (cur == NULL) {
1951
0
    xsltTransformError(ctxt, NULL, node,
1952
0
     "xsltDefaultProcessOneNode: no text for attribute\n");
1953
0
      } else {
1954
#ifdef WITH_XSLT_DEBUG_PROCESS
1955
    if (cur->content == NULL) {
1956
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1957
         "xsltDefaultProcessOneNode: copy empty text\n"));
1958
    } else {
1959
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1960
         "xsltDefaultProcessOneNode: copy text %s\n",
1961
      cur->content));
1962
                }
1963
#endif
1964
0
    copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1965
0
    if (copy == NULL) {
1966
0
        xsltTransformError(ctxt, NULL, node,
1967
0
         "xsltDefaultProcessOneNode: text copy failed\n");
1968
0
    }
1969
0
      }
1970
0
      return;
1971
0
  default:
1972
0
      return;
1973
0
    }
1974
    /*
1975
     * Handling of Elements: first pass, counting
1976
     */
1977
0
    cur = node->children;
1978
0
    while (cur != NULL) {
1979
0
  if (IS_XSLT_REAL_NODE(cur))
1980
0
      nbchild++;
1981
0
  cur = cur->next;
1982
0
    }
1983
1984
    /*
1985
     * Handling of Elements: second pass, actual processing
1986
     *
1987
     * Note that params are passed to the next template. This matches
1988
     * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
1989
     */
1990
0
    oldSize = ctxt->xpathCtxt->contextSize;
1991
0
    oldPos = ctxt->xpathCtxt->proximityPosition;
1992
0
    cur = node->children;
1993
0
    while (cur != NULL) {
1994
0
  childno++;
1995
0
  switch (cur->type) {
1996
0
      case XML_DOCUMENT_NODE:
1997
0
      case XML_HTML_DOCUMENT_NODE:
1998
0
      case XML_ELEMENT_NODE:
1999
0
    ctxt->xpathCtxt->contextSize = nbchild;
2000
0
    ctxt->xpathCtxt->proximityPosition = childno;
2001
0
    xsltProcessOneNode(ctxt, cur, params);
2002
0
    break;
2003
0
      case XML_CDATA_SECTION_NODE:
2004
0
    template = xsltGetTemplate(ctxt, cur, NULL);
2005
0
    if (template) {
2006
#ifdef WITH_XSLT_DEBUG_PROCESS
2007
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2008
     "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
2009
             cur->content));
2010
#endif
2011
        /*
2012
        * Instantiate the xsl:template.
2013
        */
2014
0
        xsltApplyXSLTTemplate(ctxt, cur, template->content,
2015
0
      template, params);
2016
0
    } else /* if (ctxt->mode == NULL) */ {
2017
#ifdef WITH_XSLT_DEBUG_PROCESS
2018
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2019
         "xsltDefaultProcessOneNode: copy CDATA %s\n",
2020
             cur->content));
2021
#endif
2022
0
        copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2023
0
        if (copy == NULL) {
2024
0
      xsltTransformError(ctxt, NULL, cur,
2025
0
          "xsltDefaultProcessOneNode: cdata copy failed\n");
2026
0
        }
2027
0
    }
2028
0
    break;
2029
0
      case XML_TEXT_NODE:
2030
0
    template = xsltGetTemplate(ctxt, cur, NULL);
2031
0
    if (template) {
2032
#ifdef WITH_XSLT_DEBUG_PROCESS
2033
        XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2034
       "xsltDefaultProcessOneNode: applying template for text %s\n",
2035
             cur->content));
2036
#endif
2037
0
        ctxt->xpathCtxt->contextSize = nbchild;
2038
0
        ctxt->xpathCtxt->proximityPosition = childno;
2039
        /*
2040
        * Instantiate the xsl:template.
2041
        */
2042
0
        xsltApplyXSLTTemplate(ctxt, cur, template->content,
2043
0
      template, params);
2044
0
    } else /* if (ctxt->mode == NULL) */ {
2045
#ifdef WITH_XSLT_DEBUG_PROCESS
2046
        if (cur->content == NULL) {
2047
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2048
       "xsltDefaultProcessOneNode: copy empty text\n"));
2049
        } else {
2050
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2051
         "xsltDefaultProcessOneNode: copy text %s\n",
2052
           cur->content));
2053
                    }
2054
#endif
2055
0
        copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2056
0
        if (copy == NULL) {
2057
0
      xsltTransformError(ctxt, NULL, cur,
2058
0
          "xsltDefaultProcessOneNode: text copy failed\n");
2059
0
        }
2060
0
    }
2061
0
    break;
2062
0
      case XML_PI_NODE:
2063
0
      case XML_COMMENT_NODE:
2064
0
    template = xsltGetTemplate(ctxt, cur, NULL);
2065
0
    if (template) {
2066
#ifdef WITH_XSLT_DEBUG_PROCESS
2067
        if (cur->type == XML_PI_NODE) {
2068
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2069
         "xsltDefaultProcessOneNode: template found for PI %s\n",
2070
                       cur->name));
2071
        } else if (cur->type == XML_COMMENT_NODE) {
2072
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2073
         "xsltDefaultProcessOneNode: template found for comment\n"));
2074
                    }
2075
#endif
2076
0
        ctxt->xpathCtxt->contextSize = nbchild;
2077
0
        ctxt->xpathCtxt->proximityPosition = childno;
2078
        /*
2079
        * Instantiate the xsl:template.
2080
        */
2081
0
        xsltApplyXSLTTemplate(ctxt, cur, template->content,
2082
0
      template, params);
2083
0
    }
2084
0
    break;
2085
0
      default:
2086
0
    break;
2087
0
  }
2088
0
  cur = cur->next;
2089
0
    }
2090
0
    ctxt->xpathCtxt->contextSize = oldSize;
2091
0
    ctxt->xpathCtxt->proximityPosition = oldPos;
2092
0
}
2093
2094
/**
2095
 * xsltProcessOneNode:
2096
 * @ctxt:  a XSLT process context
2097
 * @contextNode:  the "current node" in the source tree
2098
 * @withParams:  extra parameters (e.g. xsl:with-param) passed to the
2099
 *               template if any
2100
 *
2101
 * Process the source node.
2102
 */
2103
void
2104
xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
2105
             xsltStackElemPtr withParams)
2106
0
{
2107
0
    xsltTemplatePtr templ;
2108
0
    xmlNodePtr oldNode;
2109
2110
0
    templ = xsltGetTemplate(ctxt, contextNode, NULL);
2111
    /*
2112
     * If no template is found, apply the default rule.
2113
     */
2114
0
    if (templ == NULL) {
2115
#ifdef WITH_XSLT_DEBUG_PROCESS
2116
  if (contextNode->type == XML_DOCUMENT_NODE) {
2117
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2118
       "xsltProcessOneNode: no template found for /\n"));
2119
  } else if (contextNode->type == XML_CDATA_SECTION_NODE) {
2120
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2121
       "xsltProcessOneNode: no template found for CDATA\n"));
2122
  } else if (contextNode->type == XML_ATTRIBUTE_NODE) {
2123
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2124
       "xsltProcessOneNode: no template found for attribute %s\n",
2125
                       ((xmlAttrPtr) contextNode)->name));
2126
  } else  {
2127
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2128
       "xsltProcessOneNode: no template found for %s\n", contextNode->name));
2129
        }
2130
#endif
2131
0
  oldNode = ctxt->node;
2132
0
  ctxt->node = contextNode;
2133
0
  xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
2134
0
  ctxt->node = oldNode;
2135
0
  return;
2136
0
    }
2137
2138
0
    if (contextNode->type == XML_ATTRIBUTE_NODE) {
2139
0
  xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2140
  /*
2141
  * Set the "current template rule".
2142
  */
2143
0
  ctxt->currentTemplateRule = templ;
2144
2145
#ifdef WITH_XSLT_DEBUG_PROCESS
2146
  XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2147
       "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2148
                   templ->match, contextNode->name));
2149
#endif
2150
0
  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2151
2152
0
  ctxt->currentTemplateRule = oldCurTempRule;
2153
0
    } else {
2154
0
  xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2155
  /*
2156
  * Set the "current template rule".
2157
  */
2158
0
  ctxt->currentTemplateRule = templ;
2159
2160
#ifdef WITH_XSLT_DEBUG_PROCESS
2161
  if (contextNode->type == XML_DOCUMENT_NODE) {
2162
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2163
       "xsltProcessOneNode: applying template '%s' for /\n",
2164
                       templ->match));
2165
  } else {
2166
      XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2167
       "xsltProcessOneNode: applying template '%s' for %s\n",
2168
                       templ->match, contextNode->name));
2169
        }
2170
#endif
2171
0
  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2172
2173
0
  ctxt->currentTemplateRule = oldCurTempRule;
2174
0
    }
2175
0
}
2176
2177
#ifdef WITH_DEBUGGER
2178
static xmlNodePtr
2179
xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
2180
             xmlNodePtr contextNode,
2181
             xmlNodePtr list,
2182
             xsltTemplatePtr templ,
2183
             int *addCallResult)
2184
{
2185
    xmlNodePtr debugedNode = NULL;
2186
2187
    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2188
        if (templ) {
2189
            *addCallResult = xslAddCall(templ, templ->elem);
2190
        } else {
2191
            *addCallResult = xslAddCall(NULL, list);
2192
        }
2193
        switch (ctxt->debugStatus) {
2194
            case XSLT_DEBUG_RUN_RESTART:
2195
            case XSLT_DEBUG_QUIT:
2196
                if (*addCallResult)
2197
                    xslDropCall();
2198
                return(NULL);
2199
        }
2200
        if (templ) {
2201
            xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
2202
            debugedNode = templ->elem;
2203
        } else if (list) {
2204
            xslHandleDebugger(list, contextNode, templ, ctxt);
2205
            debugedNode = list;
2206
        } else if (ctxt->inst) {
2207
            xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
2208
            debugedNode = ctxt->inst;
2209
        }
2210
    }
2211
    return(debugedNode);
2212
}
2213
#endif /* WITH_DEBUGGER */
2214
2215
/**
2216
 * xsltLocalVariablePush:
2217
 * @ctxt: the transformation context
2218
 * @variable: variable to be pushed to the variable stack
2219
 * @level: new value for variable's level
2220
 *
2221
 * Places the variable onto the local variable stack
2222
 *
2223
 * Returns: 0 for success, -1 for any error
2224
 * **NOTE:**
2225
 * This is an internal routine and should not be called by users!
2226
 */
2227
int
2228
xsltLocalVariablePush(xsltTransformContextPtr ctxt,
2229
          xsltStackElemPtr variable,
2230
          int level)
2231
0
{
2232
0
    if (ctxt->varsMax == 0) {
2233
0
  ctxt->varsMax = 10;
2234
0
  ctxt->varsTab =
2235
0
      (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
2236
0
      sizeof(ctxt->varsTab[0]));
2237
0
  if (ctxt->varsTab == NULL) {
2238
0
      xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
2239
0
      return (-1);
2240
0
  }
2241
0
    }
2242
0
    if (ctxt->varsNr >= ctxt->varsMax) {
2243
0
  ctxt->varsMax *= 2;
2244
0
  ctxt->varsTab =
2245
0
      (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
2246
0
      ctxt->varsMax *
2247
0
      sizeof(ctxt->varsTab[0]));
2248
0
  if (ctxt->varsTab == NULL) {
2249
0
      xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2250
0
      return (-1);
2251
0
  }
2252
0
    }
2253
0
    ctxt->varsTab[ctxt->varsNr++] = variable;
2254
0
    ctxt->vars = variable;
2255
0
    variable->level = level;
2256
0
    return(0);
2257
0
}
2258
2259
/**
2260
 * xsltReleaseLocalRVTs:
2261
 *
2262
 * Fragments which are results of extension instructions
2263
 * are preserved; all other fragments are freed/cached.
2264
 */
2265
static void
2266
xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
2267
0
{
2268
0
    xmlDocPtr cur = ctxt->localRVT, tmp;
2269
2270
0
    if (cur == base)
2271
0
        return;
2272
0
    if (cur->prev != NULL)
2273
0
        xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
2274
2275
    /* Reset localRVT early because some RVTs might be registered again. */
2276
0
    ctxt->localRVT = base;
2277
0
    if (base != NULL)
2278
0
        base->prev = NULL;
2279
2280
0
    do {
2281
0
        tmp = cur;
2282
0
        cur = (xmlDocPtr) cur->next;
2283
0
        if (tmp->compression == XSLT_RVT_LOCAL) {
2284
0
            xsltReleaseRVT(ctxt, tmp);
2285
0
        } else if (tmp->compression == XSLT_RVT_GLOBAL) {
2286
0
            xsltRegisterPersistRVT(ctxt, tmp);
2287
0
        } else if (tmp->compression == XSLT_RVT_FUNC_RESULT) {
2288
            /*
2289
             * This will either register the RVT again or move it to the
2290
             * context variable.
2291
             */
2292
0
            xsltRegisterLocalRVT(ctxt, tmp);
2293
0
            tmp->compression = XSLT_RVT_FUNC_RESULT;
2294
0
        } else {
2295
0
            xmlGenericError(xmlGenericErrorContext,
2296
0
                    "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2297
0
                    tmp->psvi);
2298
0
        }
2299
0
    } while (cur != base);
2300
0
}
2301
2302
/**
2303
 * xsltApplySequenceConstructor:
2304
 * @ctxt:  a XSLT process context
2305
 * @contextNode:  the "current node" in the source tree
2306
 * @list:  the nodes of a sequence constructor;
2307
 *         (plus leading xsl:param elements)
2308
 * @templ: the compiled xsl:template (optional)
2309
 *
2310
 * Processes a sequence constructor.
2311
 *
2312
 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2313
 * semantics of "current template rule". I.e. the field ctxt->templ
2314
 * is not intended to reflect this, thus always pushed onto the
2315
 * template stack.
2316
 */
2317
static void
2318
xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
2319
           xmlNodePtr contextNode, xmlNodePtr list,
2320
           xsltTemplatePtr templ)
2321
0
{
2322
0
    xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
2323
0
    xmlNodePtr cur, insert, copy = NULL;
2324
0
    int level = 0, oldVarsNr;
2325
0
    xmlDocPtr oldLocalFragmentTop;
2326
2327
#ifdef XSLT_REFACTORED
2328
    xsltStylePreCompPtr info;
2329
#endif
2330
2331
#ifdef WITH_DEBUGGER
2332
    int addCallResult = 0;
2333
    xmlNodePtr debuggedNode = NULL;
2334
#endif
2335
2336
0
    if (ctxt == NULL)
2337
0
  return;
2338
2339
#ifdef WITH_DEBUGGER
2340
    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2341
  debuggedNode =
2342
      xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2343
    list, templ, &addCallResult);
2344
  if (debuggedNode == NULL)
2345
      return;
2346
    }
2347
#endif
2348
2349
0
    if (list == NULL)
2350
0
        return;
2351
0
    CHECK_STOPPED;
2352
2353
    /*
2354
    * Check for infinite recursion: stop if the maximum of nested templates
2355
    * is excceeded. Adjust xsltMaxDepth if you need more.
2356
    */
2357
0
    if (ctxt->depth >= ctxt->maxTemplateDepth) {
2358
0
        xsltTransformError(ctxt, NULL, list,
2359
0
      "xsltApplySequenceConstructor: A potential infinite template "
2360
0
            "recursion was detected.\n"
2361
0
      "You can adjust xsltMaxDepth (--maxdepth) in order to "
2362
0
      "raise the maximum number of nested template calls and "
2363
0
      "variables/params (currently set to %d).\n",
2364
0
      ctxt->maxTemplateDepth);
2365
0
        xsltDebug(ctxt, contextNode, list, NULL);
2366
0
  ctxt->state = XSLT_STATE_STOPPED;
2367
0
        return;
2368
0
    }
2369
0
    ctxt->depth++;
2370
2371
0
    oldLocalFragmentTop = ctxt->localRVT;
2372
0
    oldInsert = insert = ctxt->insert;
2373
0
    oldInst = oldCurInst = ctxt->inst;
2374
0
    oldContextNode = ctxt->node;
2375
    /*
2376
    * Save current number of variables on the stack; new vars are popped when
2377
    * exiting.
2378
    */
2379
0
    oldVarsNr = ctxt->varsNr;
2380
    /*
2381
    * Process the sequence constructor.
2382
    */
2383
0
    cur = list;
2384
0
    while (cur != NULL) {
2385
0
        if (ctxt->opLimit != 0) {
2386
0
            if (ctxt->opCount >= ctxt->opLimit) {
2387
0
    xsltTransformError(ctxt, NULL, cur,
2388
0
        "xsltApplySequenceConstructor: "
2389
0
                    "Operation limit exceeded\n");
2390
0
          ctxt->state = XSLT_STATE_STOPPED;
2391
0
                goto error;
2392
0
            }
2393
0
            ctxt->opCount += 1;
2394
0
        }
2395
2396
0
        ctxt->inst = cur;
2397
2398
#ifdef WITH_DEBUGGER
2399
        switch (ctxt->debugStatus) {
2400
            case XSLT_DEBUG_RUN_RESTART:
2401
            case XSLT_DEBUG_QUIT:
2402
                break;
2403
2404
        }
2405
#endif
2406
        /*
2407
         * Test; we must have a valid insertion point.
2408
         */
2409
0
        if (insert == NULL) {
2410
2411
#ifdef WITH_XSLT_DEBUG_PROCESS
2412
            XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2413
    "xsltApplySequenceConstructor: insert == NULL !\n"));
2414
#endif
2415
0
            goto error;
2416
0
        }
2417
2418
#ifdef WITH_DEBUGGER
2419
        if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
2420
            xslHandleDebugger(cur, contextNode, templ, ctxt);
2421
#endif
2422
2423
#ifdef XSLT_REFACTORED
2424
  if (cur->type == XML_ELEMENT_NODE) {
2425
      info = (xsltStylePreCompPtr) cur->psvi;
2426
      /*
2427
      * We expect a compiled representation on:
2428
      * 1) XSLT instructions of this XSLT version (1.0)
2429
      *    (with a few exceptions)
2430
      * 2) Literal result elements
2431
      * 3) Extension instructions
2432
      * 4) XSLT instructions of future XSLT versions
2433
      *    (forwards-compatible mode).
2434
      */
2435
      if (info == NULL) {
2436
    /*
2437
    * Handle the rare cases where we don't expect a compiled
2438
    * representation on an XSLT element.
2439
    */
2440
    if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
2441
        xsltMessage(ctxt, contextNode, cur);
2442
        goto skip_children;
2443
    }
2444
    /*
2445
    * Something really went wrong:
2446
    */
2447
    xsltTransformError(ctxt, NULL, cur,
2448
        "Internal error in xsltApplySequenceConstructor(): "
2449
        "The element '%s' in the stylesheet has no compiled "
2450
        "representation.\n",
2451
        cur->name);
2452
                goto skip_children;
2453
            }
2454
2455
      if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
2456
    xsltStyleItemLRElementInfoPtr lrInfo =
2457
        (xsltStyleItemLRElementInfoPtr) info;
2458
    /*
2459
    * Literal result elements
2460
    * --------------------------------------------------------
2461
    */
2462
#ifdef WITH_XSLT_DEBUG_PROCESS
2463
    XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2464
        xsltGenericDebug(xsltGenericDebugContext,
2465
        "xsltApplySequenceConstructor: copy literal result "
2466
        "element '%s'\n", cur->name));
2467
#endif
2468
    /*
2469
    * Copy the raw element-node.
2470
    * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2471
    *     == NULL)
2472
    *   goto error;
2473
    */
2474
    copy = xmlDocCopyNode(cur, insert->doc, 0);
2475
    if (copy == NULL) {
2476
        xsltTransformError(ctxt, NULL, cur,
2477
      "Internal error in xsltApplySequenceConstructor(): "
2478
      "Failed to copy literal result element '%s'.\n",
2479
      cur->name);
2480
        goto error;
2481
    } else {
2482
        /*
2483
        * Add the element-node to the result tree.
2484
        */
2485
        copy->doc = ctxt->output;
2486
        copy = xsltAddChild(insert, copy);
2487
        /*
2488
        * Create effective namespaces declarations.
2489
        * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2490
        */
2491
        if (lrInfo->effectiveNs != NULL) {
2492
      xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
2493
      xmlNsPtr ns, lastns = NULL;
2494
2495
      while (effNs != NULL) {
2496
          /*
2497
          * Avoid generating redundant namespace
2498
          * declarations; thus lookup if there is already
2499
          * such a ns-decl in the result.
2500
          */
2501
          ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
2502
          if ((ns != NULL) &&
2503
        (xmlStrEqual(ns->href, effNs->nsName)))
2504
          {
2505
        effNs = effNs->next;
2506
        continue;
2507
          }
2508
          ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
2509
          if (ns == NULL) {
2510
        xsltTransformError(ctxt, NULL, cur,
2511
            "Internal error in "
2512
            "xsltApplySequenceConstructor(): "
2513
            "Failed to copy a namespace "
2514
            "declaration.\n");
2515
        goto error;
2516
          }
2517
2518
          if (lastns == NULL)
2519
        copy->nsDef = ns;
2520
          else
2521
        lastns->next =ns;
2522
          lastns = ns;
2523
2524
          effNs = effNs->next;
2525
      }
2526
2527
        }
2528
        /*
2529
        * NOTE that we don't need to apply ns-alising: this was
2530
        *  already done at compile-time.
2531
        */
2532
        if (cur->ns != NULL) {
2533
      /*
2534
      * If there's no such ns-decl in the result tree,
2535
      * then xsltGetSpecialNamespace() will
2536
      * create a ns-decl on the copied node.
2537
      */
2538
      copy->ns = xsltGetSpecialNamespace(ctxt, cur,
2539
          cur->ns->href, cur->ns->prefix, copy);
2540
        } else {
2541
      /*
2542
      * Undeclare the default namespace if needed.
2543
      * This can be skipped, if the result element has
2544
      *  no ns-decls, in which case the result element
2545
      *  obviously does not declare a default namespace;
2546
      *  AND there's either no parent, or the parent
2547
      *  element is in no namespace; this means there's no
2548
      *  default namespace is scope to care about.
2549
      *
2550
      * REVISIT: This might result in massive
2551
      *  generation of ns-decls if nodes in a default
2552
      *  namespaces are mixed with nodes in no namespace.
2553
      *
2554
      */
2555
      if (copy->nsDef ||
2556
          ((insert != NULL) &&
2557
           (insert->type == XML_ELEMENT_NODE) &&
2558
           (insert->ns != NULL)))
2559
      {
2560
          xsltGetSpecialNamespace(ctxt, cur,
2561
        NULL, NULL, copy);
2562
      }
2563
        }
2564
    }
2565
    /*
2566
    * SPEC XSLT 2.0 "Each attribute of the literal result
2567
    *  element, other than an attribute in the XSLT namespace,
2568
    *  is processed to produce an attribute for the element in
2569
    *  the result tree."
2570
    * NOTE: See bug #341325.
2571
    */
2572
    if (cur->properties != NULL) {
2573
        xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2574
    }
2575
      } else if (IS_XSLT_ELEM_FAST(cur)) {
2576
    /*
2577
    * XSLT instructions
2578
    * --------------------------------------------------------
2579
    */
2580
    if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
2581
        /*
2582
        * We hit an unknown XSLT element.
2583
        * Try to apply one of the fallback cases.
2584
        */
2585
        ctxt->insert = insert;
2586
        if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2587
      xsltTransformError(ctxt, NULL, cur,
2588
          "The is no fallback behaviour defined for "
2589
          "the unknown XSLT element '%s'.\n",
2590
          cur->name);
2591
        }
2592
        ctxt->insert = oldInsert;
2593
    } else if (info->func != NULL) {
2594
        /*
2595
        * Execute the XSLT instruction.
2596
        */
2597
        ctxt->insert = insert;
2598
2599
        info->func(ctxt, contextNode, cur,
2600
      (xsltElemPreCompPtr) info);
2601
2602
        /*
2603
        * Cleanup temporary tree fragments.
2604
        */
2605
        if (oldLocalFragmentTop != ctxt->localRVT)
2606
      xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2607
2608
        ctxt->insert = oldInsert;
2609
    } else if (info->type == XSLT_FUNC_VARIABLE) {
2610
        xsltStackElemPtr tmpvar = ctxt->vars;
2611
2612
        xsltParseStylesheetVariable(ctxt, cur);
2613
2614
        if (tmpvar != ctxt->vars) {
2615
      /*
2616
      * TODO: Using a @tmpvar is an annoying workaround, but
2617
      *  the current mechanisms do not provide any other way
2618
      *  of knowing if the var was really pushed onto the
2619
      *  stack.
2620
      */
2621
      ctxt->vars->level = level;
2622
        }
2623
    } else if (info->type == XSLT_FUNC_MESSAGE) {
2624
        /*
2625
        * TODO: Won't be hit, since we don't compile xsl:message.
2626
        */
2627
        xsltMessage(ctxt, contextNode, cur);
2628
    } else {
2629
        xsltTransformError(ctxt, NULL, cur,
2630
      "Unexpected XSLT element '%s'.\n", cur->name);
2631
    }
2632
    goto skip_children;
2633
2634
      } else {
2635
    xsltTransformFunction func;
2636
    /*
2637
    * Extension intructions (elements)
2638
    * --------------------------------------------------------
2639
    */
2640
    if (cur->psvi == xsltExtMarker) {
2641
        /*
2642
        * The xsltExtMarker was set during the compilation
2643
        * of extension instructions if there was no registered
2644
        * handler for this specific extension function at
2645
        * compile-time.
2646
        * Libxslt will now lookup if a handler is
2647
        * registered in the context of this transformation.
2648
        */
2649
        func = xsltExtElementLookup(ctxt, cur->name,
2650
                                                cur->ns->href);
2651
    } else
2652
        func = ((xsltElemPreCompPtr) cur->psvi)->func;
2653
2654
    if (func == NULL) {
2655
        /*
2656
        * No handler available.
2657
        * Try to execute fallback behaviour via xsl:fallback.
2658
        */
2659
#ifdef WITH_XSLT_DEBUG_PROCESS
2660
        XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2661
      xsltGenericDebug(xsltGenericDebugContext,
2662
          "xsltApplySequenceConstructor: unknown extension %s\n",
2663
          cur->name));
2664
#endif
2665
        ctxt->insert = insert;
2666
        if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2667
      xsltTransformError(ctxt, NULL, cur,
2668
          "Unknown extension instruction '{%s}%s'.\n",
2669
          cur->ns->href, cur->name);
2670
        }
2671
        ctxt->insert = oldInsert;
2672
    } else {
2673
        /*
2674
        * Execute the handler-callback.
2675
        */
2676
#ifdef WITH_XSLT_DEBUG_PROCESS
2677
        XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2678
      "xsltApplySequenceConstructor: extension construct %s\n",
2679
      cur->name));
2680
#endif
2681
                    /*
2682
                     * Disable the xsltCopyTextString optimization for
2683
                     * extension elements. Extensions could append text using
2684
                     * xmlAddChild which will free the buffer pointed to by
2685
                     * 'lasttext'. This buffer could later be reallocated with
2686
                     * a different size than recorded in 'lasttsize'. See bug
2687
                     * #777432.
2688
                     */
2689
                    if (cur->psvi == xsltExtMarker) {
2690
                        ctxt->lasttext = NULL;
2691
                    }
2692
2693
        ctxt->insert = insert;
2694
2695
        func(ctxt, contextNode, cur, cur->psvi);
2696
2697
        /*
2698
        * Cleanup temporary tree fragments.
2699
        */
2700
        if (oldLocalFragmentTop != ctxt->localRVT)
2701
      xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2702
2703
        ctxt->insert = oldInsert;
2704
    }
2705
    goto skip_children;
2706
      }
2707
2708
  } else if (XSLT_IS_TEXT_NODE(cur)) {
2709
      /*
2710
      * Text
2711
      * ------------------------------------------------------------
2712
      */
2713
#ifdef WITH_XSLT_DEBUG_PROCESS
2714
            if (cur->name == xmlStringTextNoenc) {
2715
                XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2716
        xsltGenericDebug(xsltGenericDebugContext,
2717
        "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2718
        cur->content));
2719
            } else {
2720
                XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2721
        xsltGenericDebug(xsltGenericDebugContext,
2722
        "xsltApplySequenceConstructor: copy text '%s'\n",
2723
        cur->content));
2724
            }
2725
#endif
2726
            if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2727
    goto error;
2728
  }
2729
2730
#else /* XSLT_REFACTORED */
2731
2732
0
        if (IS_XSLT_ELEM(cur)) {
2733
            /*
2734
             * This is an XSLT node
2735
             */
2736
0
            xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
2737
2738
0
            if (info == NULL) {
2739
0
                if (IS_XSLT_NAME(cur, "message")) {
2740
0
                    xsltMessage(ctxt, contextNode, cur);
2741
0
                } else {
2742
                    /*
2743
                     * That's an error try to apply one of the fallback cases
2744
                     */
2745
0
                    ctxt->insert = insert;
2746
0
                    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2747
0
                        xsltGenericError(xsltGenericErrorContext,
2748
0
          "xsltApplySequenceConstructor: %s was not compiled\n",
2749
0
          cur->name);
2750
0
                    }
2751
0
                    ctxt->insert = oldInsert;
2752
0
                }
2753
0
                goto skip_children;
2754
0
            }
2755
2756
0
            if (info->func != NULL) {
2757
0
    oldCurInst = ctxt->inst;
2758
0
    ctxt->inst = cur;
2759
0
                ctxt->insert = insert;
2760
2761
0
                info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
2762
2763
    /*
2764
    * Cleanup temporary tree fragments.
2765
    */
2766
0
    if (oldLocalFragmentTop != ctxt->localRVT)
2767
0
        xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2768
2769
0
                ctxt->insert = oldInsert;
2770
0
    ctxt->inst = oldCurInst;
2771
0
                goto skip_children;
2772
0
            }
2773
2774
0
            if (IS_XSLT_NAME(cur, "variable")) {
2775
0
    xsltStackElemPtr tmpvar = ctxt->vars;
2776
2777
0
    oldCurInst = ctxt->inst;
2778
0
    ctxt->inst = cur;
2779
2780
0
    xsltParseStylesheetVariable(ctxt, cur);
2781
2782
0
    ctxt->inst = oldCurInst;
2783
2784
0
    if (tmpvar != ctxt->vars) {
2785
        /*
2786
        * TODO: Using a @tmpvar is an annoying workaround, but
2787
        *  the current mechanisms do not provide any other way
2788
        *  of knowing if the var was really pushed onto the
2789
        *  stack.
2790
        */
2791
0
        ctxt->vars->level = level;
2792
0
    }
2793
0
            } else if (IS_XSLT_NAME(cur, "message")) {
2794
0
                xsltMessage(ctxt, contextNode, cur);
2795
0
            } else {
2796
0
    xsltTransformError(ctxt, NULL, cur,
2797
0
        "Unexpected XSLT element '%s'.\n", cur->name);
2798
0
            }
2799
0
            goto skip_children;
2800
0
        } else if ((cur->type == XML_TEXT_NODE) ||
2801
0
                   (cur->type == XML_CDATA_SECTION_NODE)) {
2802
2803
            /*
2804
             * This text comes from the stylesheet
2805
             * For stylesheets, the set of whitespace-preserving
2806
             * element names consists of just xsl:text.
2807
             */
2808
#ifdef WITH_XSLT_DEBUG_PROCESS
2809
            if (cur->type == XML_CDATA_SECTION_NODE) {
2810
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2811
                                 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2812
                                 cur->content));
2813
            } else if (cur->name == xmlStringTextNoenc) {
2814
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2815
                                 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2816
                                 cur->content));
2817
            } else {
2818
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2819
                                 "xsltApplySequenceConstructor: copy text %s\n",
2820
                                 cur->content));
2821
            }
2822
#endif
2823
0
            if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2824
0
    goto error;
2825
0
        } else if ((cur->type == XML_ELEMENT_NODE) &&
2826
0
                   (cur->ns != NULL) && (cur->psvi != NULL)) {
2827
0
            xsltTransformFunction function;
2828
2829
0
      oldCurInst = ctxt->inst;
2830
0
      ctxt->inst = cur;
2831
            /*
2832
             * Flagged as an extension element
2833
             */
2834
0
            if (cur->psvi == xsltExtMarker)
2835
0
                function = xsltExtElementLookup(ctxt, cur->name,
2836
0
                                                cur->ns->href);
2837
0
            else
2838
0
                function = ((xsltElemPreCompPtr) cur->psvi)->func;
2839
2840
0
            if (function == NULL) {
2841
0
                xmlNodePtr child;
2842
0
                int found = 0;
2843
2844
#ifdef WITH_XSLT_DEBUG_PROCESS
2845
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2846
        "xsltApplySequenceConstructor: unknown extension %s\n",
2847
                    cur->name));
2848
#endif
2849
                /*
2850
                 * Search if there are fallbacks
2851
                 */
2852
0
                ctxt->insert = insert;
2853
0
                child = cur->children;
2854
0
                while (child != NULL) {
2855
0
                    if ((IS_XSLT_ELEM(child)) &&
2856
0
                        (IS_XSLT_NAME(child, "fallback")))
2857
0
        {
2858
0
                        found = 1;
2859
0
                        xsltApplySequenceConstructor(ctxt, contextNode,
2860
0
          child->children, NULL);
2861
0
                    }
2862
0
                    child = child->next;
2863
0
                }
2864
0
                ctxt->insert = oldInsert;
2865
2866
0
                if (!found) {
2867
0
                    xsltTransformError(ctxt, NULL, cur,
2868
0
      "xsltApplySequenceConstructor: failed to find extension %s\n",
2869
0
      cur->name);
2870
0
                }
2871
0
            } else {
2872
#ifdef WITH_XSLT_DEBUG_PROCESS
2873
                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2874
        "xsltApplySequenceConstructor: extension construct %s\n",
2875
                    cur->name));
2876
#endif
2877
2878
                /*
2879
                 * Disable the xsltCopyTextString optimization for
2880
                 * extension elements. Extensions could append text using
2881
                 * xmlAddChild which will free the buffer pointed to by
2882
                 * 'lasttext'. This buffer could later be reallocated with
2883
                 * a different size than recorded in 'lasttsize'. See bug
2884
                 * #777432.
2885
                 */
2886
0
                if (cur->psvi == xsltExtMarker) {
2887
0
              ctxt->lasttext = NULL;
2888
0
                }
2889
2890
0
                ctxt->insert = insert;
2891
2892
0
                function(ctxt, contextNode, cur, cur->psvi);
2893
    /*
2894
    * Cleanup temporary tree fragments.
2895
    */
2896
0
    if (oldLocalFragmentTop != ctxt->localRVT)
2897
0
        xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2898
2899
0
                ctxt->insert = oldInsert;
2900
2901
0
            }
2902
0
      ctxt->inst = oldCurInst;
2903
0
            goto skip_children;
2904
0
        } else if (cur->type == XML_ELEMENT_NODE) {
2905
#ifdef WITH_XSLT_DEBUG_PROCESS
2906
            XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2907
    "xsltApplySequenceConstructor: copy node %s\n",
2908
                cur->name));
2909
#endif
2910
0
      oldCurInst = ctxt->inst;
2911
0
      ctxt->inst = cur;
2912
2913
0
            if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
2914
0
    goto error;
2915
            /*
2916
             * Add extra namespaces inherited from the current template
2917
             * if we are in the first level children and this is a
2918
       * "real" template.
2919
             */
2920
0
            if ((templ != NULL) && (oldInsert == insert) &&
2921
0
                (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
2922
0
                int i;
2923
0
                xmlNsPtr ns, ret;
2924
2925
0
                for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
2926
0
        const xmlChar *URI = NULL;
2927
0
        xsltStylesheetPtr style;
2928
0
                    ns = ctxt->templ->inheritedNs[i];
2929
2930
        /* Note that the XSLT namespace was already excluded
2931
        * in xsltGetInheritedNsList().
2932
        */
2933
#if 0
2934
        if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2935
      continue;
2936
#endif
2937
0
        style = ctxt->style;
2938
0
        while (style != NULL) {
2939
0
      if (style->nsAliases != NULL)
2940
0
          URI = (const xmlChar *)
2941
0
        xmlHashLookup(style->nsAliases, ns->href);
2942
0
      if (URI != NULL)
2943
0
          break;
2944
2945
0
      style = xsltNextImport(style);
2946
0
        }
2947
0
        if (URI == UNDEFINED_DEFAULT_NS)
2948
0
      continue;
2949
0
        if (URI == NULL)
2950
0
      URI = ns->href;
2951
        /*
2952
        * TODO: The following will still be buggy for the
2953
        * non-refactored code.
2954
        */
2955
0
        ret = xmlSearchNs(copy->doc, copy, ns->prefix);
2956
0
        if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
2957
0
        {
2958
0
      xmlNewNs(copy, URI, ns->prefix);
2959
0
        }
2960
0
                }
2961
0
    if (copy->ns != NULL) {
2962
        /*
2963
         * Fix the node namespace if needed
2964
         */
2965
0
        copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
2966
0
    }
2967
0
            }
2968
      /*
2969
             * all the attributes are directly inherited
2970
             */
2971
0
            if (cur->properties != NULL) {
2972
0
                xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2973
0
            }
2974
0
      ctxt->inst = oldCurInst;
2975
0
        }
2976
0
#endif /* else of XSLT_REFACTORED */
2977
2978
        /*
2979
         * Descend into content in document order.
2980
         */
2981
0
        if (cur->children != NULL) {
2982
0
            if (cur->children->type != XML_ENTITY_DECL) {
2983
0
                cur = cur->children;
2984
0
    level++;
2985
0
                if (copy != NULL)
2986
0
                    insert = copy;
2987
0
                continue;
2988
0
            }
2989
0
        }
2990
2991
0
skip_children:
2992
  /*
2993
  * If xslt:message was just processed, we might have hit a
2994
  * terminate='yes'; if so, then break the loop and clean up.
2995
  * TODO: Do we need to check this also before trying to descend
2996
  *  into the content?
2997
  */
2998
0
  if (ctxt->state == XSLT_STATE_STOPPED)
2999
0
      break;
3000
0
        if (cur->next != NULL) {
3001
0
            cur = cur->next;
3002
0
            continue;
3003
0
        }
3004
3005
0
        do {
3006
0
            cur = cur->parent;
3007
0
      level--;
3008
      /*
3009
      * Pop variables/params (xsl:variable and xsl:param).
3010
      */
3011
0
      if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
3012
0
    xsltLocalVariablePop(ctxt, oldVarsNr, level);
3013
0
      }
3014
3015
0
            insert = insert->parent;
3016
0
            if (cur == NULL)
3017
0
                break;
3018
0
            if (cur == list->parent) {
3019
0
                cur = NULL;
3020
0
                break;
3021
0
            }
3022
0
            if (cur->next != NULL) {
3023
0
                cur = cur->next;
3024
0
                break;
3025
0
            }
3026
0
        } while (cur != NULL);
3027
0
    }
3028
3029
0
error:
3030
    /*
3031
    * In case of errors: pop remaining variables.
3032
    */
3033
0
    if (ctxt->varsNr > oldVarsNr)
3034
0
  xsltLocalVariablePop(ctxt, oldVarsNr, -1);
3035
3036
0
    ctxt->node = oldContextNode;
3037
0
    ctxt->inst = oldInst;
3038
0
    ctxt->insert = oldInsert;
3039
3040
0
    ctxt->depth--;
3041
3042
#ifdef WITH_DEBUGGER
3043
    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3044
        xslDropCall();
3045
    }
3046
#endif
3047
0
}
3048
3049
/*
3050
* xsltApplyXSLTTemplate:
3051
* @ctxt:  a XSLT transformation context
3052
* @contextNode:  the node in the source tree.
3053
* @list:  the nodes of a sequence constructor;
3054
*         (plus leading xsl:param elements)
3055
* @templ: the compiled xsl:template declaration;
3056
*         NULL if a sequence constructor
3057
* @withParams:  a set of caller-parameters (xsl:with-param) or NULL
3058
*
3059
* Called by:
3060
* - xsltApplyImports()
3061
* - xsltCallTemplate()
3062
* - xsltDefaultProcessOneNode()
3063
* - xsltProcessOneNode()
3064
*/
3065
static void
3066
xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
3067
          xmlNodePtr contextNode,
3068
          xmlNodePtr list,
3069
          xsltTemplatePtr templ,
3070
          xsltStackElemPtr withParams)
3071
0
{
3072
0
    int oldVarsBase = 0;
3073
0
    xmlNodePtr cur;
3074
0
    xsltStackElemPtr tmpParam = NULL;
3075
0
    xmlDocPtr oldUserFragmentTop;
3076
#ifdef WITH_PROFILER
3077
    long start = 0;
3078
#endif
3079
3080
#ifdef XSLT_REFACTORED
3081
    xsltStyleItemParamPtr iparam;
3082
#else
3083
0
    xsltStylePreCompPtr iparam;
3084
0
#endif
3085
3086
#ifdef WITH_DEBUGGER
3087
    int addCallResult = 0;
3088
#endif
3089
3090
0
    if (ctxt == NULL)
3091
0
  return;
3092
0
    if (templ == NULL) {
3093
0
  xsltTransformError(ctxt, NULL, list,
3094
0
      "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3095
0
  return;
3096
0
    }
3097
3098
#ifdef WITH_DEBUGGER
3099
    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
3100
  if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
3101
    list, templ, &addCallResult) == NULL)
3102
      return;
3103
    }
3104
#endif
3105
3106
0
    if (list == NULL)
3107
0
        return;
3108
0
    CHECK_STOPPED;
3109
3110
0
    if (ctxt->varsNr >= ctxt->maxTemplateVars)
3111
0
  {
3112
0
        xsltTransformError(ctxt, NULL, list,
3113
0
      "xsltApplyXSLTTemplate: A potential infinite template recursion "
3114
0
      "was detected.\n"
3115
0
      "You can adjust maxTemplateVars (--maxvars) in order to "
3116
0
      "raise the maximum number of variables/params (currently set to %d).\n",
3117
0
      ctxt->maxTemplateVars);
3118
0
        xsltDebug(ctxt, contextNode, list, NULL);
3119
0
  ctxt->state = XSLT_STATE_STOPPED;
3120
0
        return;
3121
0
  }
3122
3123
0
    oldUserFragmentTop = ctxt->tmpRVT;
3124
0
    ctxt->tmpRVT = NULL;
3125
3126
    /*
3127
    * Initiate a distinct scope of local params/variables.
3128
    */
3129
0
    oldVarsBase = ctxt->varsBase;
3130
0
    ctxt->varsBase = ctxt->varsNr;
3131
3132
0
    ctxt->node = contextNode;
3133
3134
#ifdef WITH_PROFILER
3135
    if (ctxt->profile) {
3136
  templ->nbCalls++;
3137
  start = xsltTimestamp();
3138
  profPush(ctxt, 0);
3139
  profCallgraphAdd(templ, ctxt->templ);
3140
    }
3141
#endif
3142
3143
    /*
3144
    * Push the xsl:template declaration onto the stack.
3145
    */
3146
0
    templPush(ctxt, templ);
3147
3148
#ifdef WITH_XSLT_DEBUG_PROCESS
3149
    if (templ->name != NULL)
3150
  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
3151
  "applying xsl:template '%s'\n", templ->name));
3152
#endif
3153
    /*
3154
    * Process xsl:param instructions and skip those elements for
3155
    * further processing.
3156
    */
3157
0
    cur = list;
3158
0
    do {
3159
0
  if (cur->type == XML_TEXT_NODE) {
3160
0
      cur = cur->next;
3161
0
      continue;
3162
0
  }
3163
0
  if ((cur->type != XML_ELEMENT_NODE) ||
3164
0
      (cur->name[0] != 'p') ||
3165
0
      (cur->psvi == NULL) ||
3166
0
      (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
3167
0
      (! IS_XSLT_ELEM(cur)))
3168
0
  {
3169
0
      break;
3170
0
  }
3171
3172
0
  list = cur->next;
3173
3174
#ifdef XSLT_REFACTORED
3175
  iparam = (xsltStyleItemParamPtr) cur->psvi;
3176
#else
3177
0
  iparam = (xsltStylePreCompPtr) cur->psvi;
3178
0
#endif
3179
3180
  /*
3181
  * Substitute xsl:param for a given xsl:with-param.
3182
  * Since the XPath expression will reference the params/vars
3183
  * by index, we need to slot the xsl:with-params in the
3184
  * order of encountered xsl:params to keep the sequence of
3185
  * params/variables in the stack exactly as it was at
3186
  * compile time,
3187
  */
3188
0
  tmpParam = NULL;
3189
0
  if (withParams) {
3190
0
      tmpParam = withParams;
3191
0
      do {
3192
0
    if ((tmpParam->name == (iparam->name)) &&
3193
0
        (tmpParam->nameURI == (iparam->ns)))
3194
0
    {
3195
        /*
3196
        * Push the caller-parameter.
3197
        */
3198
0
        xsltLocalVariablePush(ctxt, tmpParam, -1);
3199
0
        break;
3200
0
    }
3201
0
    tmpParam = tmpParam->next;
3202
0
      } while (tmpParam != NULL);
3203
0
  }
3204
  /*
3205
  * Push the xsl:param.
3206
  */
3207
0
  if (tmpParam == NULL) {
3208
      /*
3209
      * Note that we must assume that the added parameter
3210
      * has a @depth of 0.
3211
      */
3212
0
      xsltParseStylesheetParam(ctxt, cur);
3213
0
  }
3214
0
  cur = cur->next;
3215
0
    } while (cur != NULL);
3216
    /*
3217
    * Process the sequence constructor.
3218
    */
3219
0
    xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3220
3221
    /*
3222
    * Remove remaining xsl:param and xsl:with-param items from
3223
    * the stack. Don't free xsl:with-param items.
3224
    */
3225
0
    if (ctxt->varsNr > ctxt->varsBase)
3226
0
  xsltTemplateParamsCleanup(ctxt);
3227
0
    ctxt->varsBase = oldVarsBase;
3228
3229
    /*
3230
    * Release user-created fragments stored in the scope
3231
    * of xsl:template. Note that this mechanism is deprecated:
3232
    * user code should now use xsltRegisterLocalRVT() instead
3233
    * of the obsolete xsltRegisterTmpRVT().
3234
    */
3235
0
    if (ctxt->tmpRVT) {
3236
0
  xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
3237
3238
0
  while (curdoc != NULL) {
3239
0
      tmp = curdoc;
3240
0
      curdoc = (xmlDocPtr) curdoc->next;
3241
0
      xsltReleaseRVT(ctxt, tmp);
3242
0
  }
3243
0
    }
3244
0
    ctxt->tmpRVT = oldUserFragmentTop;
3245
3246
    /*
3247
    * Pop the xsl:template declaration from the stack.
3248
    */
3249
0
    templPop(ctxt);
3250
3251
#ifdef WITH_PROFILER
3252
    if (ctxt->profile) {
3253
  long spent, child, total, end;
3254
3255
  end = xsltTimestamp();
3256
  child = profPop(ctxt);
3257
  total = end - start;
3258
  spent = total - child;
3259
  if (spent <= 0) {
3260
      /*
3261
      * Not possible unless the original calibration failed
3262
      * we can try to correct it on the fly.
3263
      */
3264
      xsltCalibrateAdjust(spent);
3265
      spent = 0;
3266
  }
3267
3268
  templ->time += spent;
3269
  if (ctxt->profNr > 0)
3270
      ctxt->profTab[ctxt->profNr - 1] += total;
3271
    }
3272
#endif
3273
3274
#ifdef WITH_DEBUGGER
3275
    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3276
        xslDropCall();
3277
    }
3278
#endif
3279
0
}
3280
3281
3282
/**
3283
 * xsltApplyOneTemplate:
3284
 * @ctxt:  a XSLT process context
3285
 * @contextNode:  the node in the source tree.
3286
 * @list:  the nodes of a sequence constructor
3287
 * @templ: not used
3288
 * @params:  a set of parameters (xsl:param) or NULL
3289
 *
3290
 * Processes a sequence constructor on the current node in the source tree.
3291
 *
3292
 * @params are the already computed variable stack items; this function
3293
 * pushes them on the variable stack, and pops them before exiting; it's
3294
 * left to the caller to free or reuse @params afterwards. The initial
3295
 * states of the variable stack will always be restored before this
3296
 * function exits.
3297
 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3298
 * variables already on the stack are visible to the process. The caller's
3299
 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3300
 *
3301
 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3302
 * provide a @templ); a non-NULL @templ might raise an error in the future.
3303
 *
3304
 * BIG NOTE: This function is not intended to process the content of an
3305
 * xsl:template; it does not expect xsl:param instructions in @list and
3306
 * will report errors if found.
3307
 *
3308
 * Called by:
3309
 *  - xsltEvalVariable() (variables.c)
3310
 *  - exsltFuncFunctionFunction() (libexsl/functions.c)
3311
 */
3312
void
3313
xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
3314
         xmlNodePtr contextNode,
3315
                     xmlNodePtr list,
3316
         xsltTemplatePtr templ ATTRIBUTE_UNUSED,
3317
                     xsltStackElemPtr params)
3318
0
{
3319
0
    if ((ctxt == NULL) || (list == NULL))
3320
0
  return;
3321
0
    CHECK_STOPPED;
3322
3323
0
    if (params) {
3324
  /*
3325
   * This code should be obsolete - was previously used
3326
   * by libexslt/functions.c, but due to bug 381319 the
3327
   * logic there was changed.
3328
   */
3329
0
  int oldVarsNr = ctxt->varsNr;
3330
3331
  /*
3332
  * Push the given xsl:param(s) onto the variable stack.
3333
  */
3334
0
  while (params != NULL) {
3335
0
      xsltLocalVariablePush(ctxt, params, -1);
3336
0
      params = params->next;
3337
0
  }
3338
0
  xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3339
  /*
3340
  * Pop the given xsl:param(s) from the stack but don't free them.
3341
  */
3342
0
  xsltLocalVariablePop(ctxt, oldVarsNr, -2);
3343
0
    } else
3344
0
  xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3345
0
}
3346
3347
/************************************************************************
3348
 *                  *
3349
 *        XSLT-1.1 extensions         *
3350
 *                  *
3351
 ************************************************************************/
3352
3353
/**
3354
 * xsltDocumentElem:
3355
 * @ctxt:  an XSLT processing context
3356
 * @node:  The current node
3357
 * @inst:  the instruction in the stylesheet
3358
 * @castedComp:  precomputed information
3359
 *
3360
 * Process an EXSLT/XSLT-1.1 document element
3361
 */
3362
void
3363
xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
3364
                 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3365
0
{
3366
#ifdef XSLT_REFACTORED
3367
    xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
3368
#else
3369
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3370
0
#endif
3371
0
    xsltStylesheetPtr style = NULL;
3372
0
    int ret;
3373
0
    xmlChar *filename = NULL, *prop, *elements;
3374
0
    xmlChar *element, *end;
3375
0
    xmlDocPtr res = NULL;
3376
0
    xmlDocPtr oldOutput;
3377
0
    xmlNodePtr oldInsert, root;
3378
0
    const char *oldOutputFile;
3379
0
    xsltOutputType oldType;
3380
0
    xmlChar *URL = NULL;
3381
0
    const xmlChar *method;
3382
0
    const xmlChar *doctypePublic;
3383
0
    const xmlChar *doctypeSystem;
3384
0
    const xmlChar *version;
3385
0
    const xmlChar *encoding;
3386
0
    int redirect_write_append = 0;
3387
3388
0
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
3389
0
        return;
3390
3391
0
    if (comp->filename == NULL) {
3392
3393
0
        if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
3394
      /*
3395
      * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3396
      *   (http://icl.com/saxon)
3397
      * The @file is in no namespace.
3398
      */
3399
#ifdef WITH_XSLT_DEBUG_EXTRA
3400
            xsltGenericDebug(xsltGenericDebugContext,
3401
                             "Found saxon:output extension\n");
3402
#endif
3403
0
            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3404
0
                                                 (const xmlChar *) "file",
3405
0
                                                 XSLT_SAXON_NAMESPACE);
3406
3407
0
      if (URL == NULL)
3408
0
    URL = xsltEvalAttrValueTemplate(ctxt, inst,
3409
0
                                                 (const xmlChar *) "href",
3410
0
                                                 XSLT_SAXON_NAMESPACE);
3411
0
        } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
3412
#ifdef WITH_XSLT_DEBUG_EXTRA
3413
            xsltGenericDebug(xsltGenericDebugContext,
3414
                             "Found xalan:write extension\n");
3415
#endif
3416
0
            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3417
0
                                                 (const xmlChar *)
3418
0
                                                 "select",
3419
0
                                                 XSLT_XALAN_NAMESPACE);
3420
0
      if (URL != NULL) {
3421
0
    xmlXPathCompExprPtr cmp;
3422
0
    xmlChar *val;
3423
3424
    /*
3425
     * Trying to handle bug #59212
3426
     * The value of the "select" attribute is an
3427
     * XPath expression.
3428
     * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3429
     */
3430
0
    cmp = xmlXPathCtxtCompile(ctxt->xpathCtxt, URL);
3431
0
                val = xsltEvalXPathString(ctxt, cmp);
3432
0
    xmlXPathFreeCompExpr(cmp);
3433
0
    xmlFree(URL);
3434
0
    URL = val;
3435
0
      }
3436
0
      if (URL == NULL)
3437
0
    URL = xsltEvalAttrValueTemplate(ctxt, inst,
3438
0
                 (const xmlChar *)
3439
0
                 "file",
3440
0
                 XSLT_XALAN_NAMESPACE);
3441
0
      if (URL == NULL)
3442
0
    URL = xsltEvalAttrValueTemplate(ctxt, inst,
3443
0
                 (const xmlChar *)
3444
0
                 "href",
3445
0
                 XSLT_XALAN_NAMESPACE);
3446
0
        } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
3447
0
            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3448
0
                                                 (const xmlChar *) "href",
3449
0
                                                 NULL);
3450
0
        }
3451
3452
0
    } else {
3453
0
        URL = xmlStrdup(comp->filename);
3454
0
    }
3455
3456
0
    if (URL == NULL) {
3457
0
  xsltTransformError(ctxt, NULL, inst,
3458
0
             "xsltDocumentElem: href/URI-Reference not found\n");
3459
0
  return;
3460
0
    }
3461
3462
    /*
3463
     * If the computation failed, it's likely that the URL wasn't escaped
3464
     */
3465
0
    filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
3466
0
    if (filename == NULL) {
3467
0
  xmlChar *escURL;
3468
3469
0
  escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
3470
0
  if (escURL != NULL) {
3471
0
      filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
3472
0
      xmlFree(escURL);
3473
0
  }
3474
0
    }
3475
3476
0
    if (filename == NULL) {
3477
0
  xsltTransformError(ctxt, NULL, inst,
3478
0
             "xsltDocumentElem: URL computation failed for %s\n",
3479
0
       URL);
3480
0
  xmlFree(URL);
3481
0
  return;
3482
0
    }
3483
3484
    /*
3485
     * Security checking: can we write to this resource
3486
     */
3487
0
    if (ctxt->sec != NULL) {
3488
0
  ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
3489
0
  if (ret <= 0) {
3490
0
            if (ret == 0)
3491
0
                xsltTransformError(ctxt, NULL, inst,
3492
0
                     "xsltDocumentElem: write rights for %s denied\n",
3493
0
                                 filename);
3494
0
      xmlFree(URL);
3495
0
      xmlFree(filename);
3496
0
      return;
3497
0
  }
3498
0
    }
3499
3500
0
    oldOutputFile = ctxt->outputFile;
3501
0
    oldOutput = ctxt->output;
3502
0
    oldInsert = ctxt->insert;
3503
0
    oldType = ctxt->type;
3504
0
    ctxt->outputFile = (const char *) filename;
3505
3506
0
    style = xsltNewStylesheet();
3507
0
    if (style == NULL) {
3508
0
  xsltTransformError(ctxt, NULL, inst,
3509
0
                         "xsltDocumentElem: out of memory\n");
3510
0
        goto error;
3511
0
    }
3512
3513
    /*
3514
     * Version described in 1.1 draft allows full parameterization
3515
     * of the output.
3516
     */
3517
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3518
0
             (const xmlChar *) "version",
3519
0
             NULL);
3520
0
    if (prop != NULL) {
3521
0
  if (style->version != NULL)
3522
0
      xmlFree(style->version);
3523
0
  style->version = prop;
3524
0
    }
3525
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3526
0
             (const xmlChar *) "encoding",
3527
0
             NULL);
3528
0
    if (prop != NULL) {
3529
0
  if (style->encoding != NULL)
3530
0
      xmlFree(style->encoding);
3531
0
  style->encoding = prop;
3532
0
    }
3533
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3534
0
             (const xmlChar *) "method",
3535
0
             NULL);
3536
0
    if (prop != NULL) {
3537
0
  const xmlChar *URI;
3538
3539
0
  if (style->method != NULL)
3540
0
      xmlFree(style->method);
3541
0
  style->method = NULL;
3542
0
  if (style->methodURI != NULL)
3543
0
      xmlFree(style->methodURI);
3544
0
  style->methodURI = NULL;
3545
3546
0
  URI = xsltGetQNameURI(inst, &prop);
3547
0
  if (prop == NULL) {
3548
0
      if (style != NULL) style->errors++;
3549
0
  } else if (URI == NULL) {
3550
0
      if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
3551
0
    (xmlStrEqual(prop, (const xmlChar *) "html")) ||
3552
0
    (xmlStrEqual(prop, (const xmlChar *) "text"))) {
3553
0
    style->method = prop;
3554
0
      } else {
3555
0
    xsltTransformError(ctxt, NULL, inst,
3556
0
         "invalid value for method: %s\n", prop);
3557
0
    if (style != NULL) style->warnings++;
3558
0
      }
3559
0
  } else {
3560
0
      style->method = prop;
3561
0
      style->methodURI = xmlStrdup(URI);
3562
0
  }
3563
0
    }
3564
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3565
0
             (const xmlChar *)
3566
0
             "doctype-system", NULL);
3567
0
    if (prop != NULL) {
3568
0
  if (style->doctypeSystem != NULL)
3569
0
      xmlFree(style->doctypeSystem);
3570
0
  style->doctypeSystem = prop;
3571
0
    }
3572
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3573
0
             (const xmlChar *)
3574
0
             "doctype-public", NULL);
3575
0
    if (prop != NULL) {
3576
0
  if (style->doctypePublic != NULL)
3577
0
      xmlFree(style->doctypePublic);
3578
0
  style->doctypePublic = prop;
3579
0
    }
3580
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3581
0
             (const xmlChar *) "standalone",
3582
0
             NULL);
3583
0
    if (prop != NULL) {
3584
0
  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3585
0
      style->standalone = 1;
3586
0
  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3587
0
      style->standalone = 0;
3588
0
  } else {
3589
0
      xsltTransformError(ctxt, NULL, inst,
3590
0
           "invalid value for standalone: %s\n",
3591
0
           prop);
3592
0
      if (style != NULL) style->warnings++;
3593
0
  }
3594
0
  xmlFree(prop);
3595
0
    }
3596
3597
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3598
0
             (const xmlChar *) "indent",
3599
0
             NULL);
3600
0
    if (prop != NULL) {
3601
0
  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3602
0
      style->indent = 1;
3603
0
  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3604
0
      style->indent = 0;
3605
0
  } else {
3606
0
      xsltTransformError(ctxt, NULL, inst,
3607
0
           "invalid value for indent: %s\n", prop);
3608
0
      if (style != NULL) style->warnings++;
3609
0
  }
3610
0
  xmlFree(prop);
3611
0
    }
3612
3613
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3614
0
             (const xmlChar *)
3615
0
             "omit-xml-declaration",
3616
0
             NULL);
3617
0
    if (prop != NULL) {
3618
0
  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3619
0
      style->omitXmlDeclaration = 1;
3620
0
  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3621
0
      style->omitXmlDeclaration = 0;
3622
0
  } else {
3623
0
      xsltTransformError(ctxt, NULL, inst,
3624
0
           "invalid value for omit-xml-declaration: %s\n",
3625
0
           prop);
3626
0
      if (style != NULL) style->warnings++;
3627
0
  }
3628
0
  xmlFree(prop);
3629
0
    }
3630
3631
0
    elements = xsltEvalAttrValueTemplate(ctxt, inst,
3632
0
           (const xmlChar *)
3633
0
           "cdata-section-elements",
3634
0
           NULL);
3635
0
    if (elements != NULL) {
3636
0
  if (style->stripSpaces == NULL)
3637
0
      style->stripSpaces = xmlHashCreate(10);
3638
0
  if (style->stripSpaces == NULL) {
3639
0
      xmlFree(elements);
3640
0
      return;
3641
0
  }
3642
3643
0
  element = elements;
3644
0
  while (*element != 0) {
3645
0
      while (xmlIsBlank_ch(*element))
3646
0
    element++;
3647
0
      if (*element == 0)
3648
0
    break;
3649
0
      end = element;
3650
0
      while ((*end != 0) && (!xmlIsBlank_ch(*end)))
3651
0
    end++;
3652
0
      element = xmlStrndup(element, end - element);
3653
0
      if (element) {
3654
0
    const xmlChar *URI;
3655
3656
#ifdef WITH_XSLT_DEBUG_PARSING
3657
    xsltGenericDebug(xsltGenericDebugContext,
3658
         "add cdata section output element %s\n",
3659
         element);
3660
#endif
3661
0
                URI = xsltGetQNameURI(inst, &element);
3662
3663
0
    xmlHashAddEntry2(style->stripSpaces, element, URI,
3664
0
              (xmlChar *) "cdata");
3665
0
    xmlFree(element);
3666
0
      }
3667
0
      element = end;
3668
0
  }
3669
0
  xmlFree(elements);
3670
0
    }
3671
3672
    /*
3673
     * Create a new document tree and process the element template
3674
     */
3675
0
    XSLT_GET_IMPORT_PTR(method, style, method)
3676
0
    XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3677
0
    XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3678
0
    XSLT_GET_IMPORT_PTR(version, style, version)
3679
0
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
3680
3681
0
    if ((method != NULL) &&
3682
0
  (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
3683
0
  if (xmlStrEqual(method, (const xmlChar *) "html")) {
3684
0
      ctxt->type = XSLT_OUTPUT_HTML;
3685
0
      if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3686
0
    res = htmlNewDoc(doctypeSystem, doctypePublic);
3687
0
      else {
3688
0
    if (version != NULL) {
3689
0
#ifdef XSLT_GENERATE_HTML_DOCTYPE
3690
0
        xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3691
0
#endif
3692
0
                }
3693
0
    res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3694
0
      }
3695
0
      if (res == NULL)
3696
0
    goto error;
3697
0
      res->dict = ctxt->dict;
3698
0
      xmlDictReference(res->dict);
3699
0
  } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
3700
0
      xsltTransformError(ctxt, NULL, inst,
3701
0
       "xsltDocumentElem: unsupported method xhtml\n");
3702
0
      ctxt->type = XSLT_OUTPUT_HTML;
3703
0
      res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3704
0
      if (res == NULL)
3705
0
    goto error;
3706
0
      res->dict = ctxt->dict;
3707
0
      xmlDictReference(res->dict);
3708
0
  } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
3709
0
      ctxt->type = XSLT_OUTPUT_TEXT;
3710
0
      res = xmlNewDoc(style->version);
3711
0
      if (res == NULL)
3712
0
    goto error;
3713
0
      res->dict = ctxt->dict;
3714
0
      xmlDictReference(res->dict);
3715
#ifdef WITH_XSLT_DEBUG
3716
      xsltGenericDebug(xsltGenericDebugContext,
3717
                     "reusing transformation dict for output\n");
3718
#endif
3719
0
  } else {
3720
0
      xsltTransformError(ctxt, NULL, inst,
3721
0
           "xsltDocumentElem: unsupported method (%s)\n",
3722
0
                 method);
3723
0
      goto error;
3724
0
  }
3725
0
    } else {
3726
0
  ctxt->type = XSLT_OUTPUT_XML;
3727
0
  res = xmlNewDoc(style->version);
3728
0
  if (res == NULL)
3729
0
      goto error;
3730
0
  res->dict = ctxt->dict;
3731
0
  xmlDictReference(res->dict);
3732
#ifdef WITH_XSLT_DEBUG
3733
  xsltGenericDebug(xsltGenericDebugContext,
3734
                     "reusing transformation dict for output\n");
3735
#endif
3736
0
    }
3737
0
    res->charset = XML_CHAR_ENCODING_UTF8;
3738
0
    if (encoding != NULL)
3739
0
  res->encoding = xmlStrdup(encoding);
3740
0
    ctxt->output = res;
3741
0
    ctxt->insert = (xmlNodePtr) res;
3742
0
    xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
3743
3744
    /*
3745
     * Do some post processing work depending on the generated output
3746
     */
3747
0
    root = xmlDocGetRootElement(res);
3748
0
    if (root != NULL) {
3749
0
        const xmlChar *doctype = NULL;
3750
3751
0
        if ((root->ns != NULL) && (root->ns->prefix != NULL))
3752
0
      doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
3753
0
  if (doctype == NULL)
3754
0
      doctype = root->name;
3755
3756
        /*
3757
         * Apply the default selection of the method
3758
         */
3759
0
        if ((method == NULL) &&
3760
0
            (root->ns == NULL) &&
3761
0
            (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3762
0
            xmlNodePtr tmp;
3763
3764
0
            tmp = res->children;
3765
0
            while ((tmp != NULL) && (tmp != root)) {
3766
0
                if (tmp->type == XML_ELEMENT_NODE)
3767
0
                    break;
3768
0
                if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3769
0
                    break;
3770
0
    tmp = tmp->next;
3771
0
            }
3772
0
            if (tmp == root) {
3773
0
                ctxt->type = XSLT_OUTPUT_HTML;
3774
0
                res->type = XML_HTML_DOCUMENT_NODE;
3775
0
                if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
3776
0
                    res->intSubset = xmlCreateIntSubset(res, doctype,
3777
0
                                                        doctypePublic,
3778
0
                                                        doctypeSystem);
3779
0
#ifdef XSLT_GENERATE_HTML_DOCTYPE
3780
0
    } else if (version != NULL) {
3781
0
                    xsltGetHTMLIDs(version, &doctypePublic,
3782
0
                                   &doctypeSystem);
3783
0
                    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3784
0
                        res->intSubset =
3785
0
                            xmlCreateIntSubset(res, doctype,
3786
0
                                               doctypePublic,
3787
0
                                               doctypeSystem);
3788
0
#endif
3789
0
                }
3790
0
            }
3791
3792
0
        }
3793
0
        if (ctxt->type == XSLT_OUTPUT_XML) {
3794
0
            XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3795
0
                XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3796
0
                if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3797
0
                res->intSubset = xmlCreateIntSubset(res, doctype,
3798
0
                                                    doctypePublic,
3799
0
                                                    doctypeSystem);
3800
0
        }
3801
0
    }
3802
3803
    /*
3804
     * Calls to redirect:write also take an optional attribute append.
3805
     * Attribute append="true|yes" which will attempt to simply append
3806
     * to an existing file instead of always opening a new file. The
3807
     * default behavior of always overwriting the file still happens
3808
     * if we do not specify append.
3809
     * Note that append use will forbid use of remote URI target.
3810
     */
3811
0
    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append",
3812
0
             NULL);
3813
0
    if (prop != NULL) {
3814
0
  if (xmlStrEqual(prop, (const xmlChar *) "true") ||
3815
0
      xmlStrEqual(prop, (const xmlChar *) "yes")) {
3816
0
      style->omitXmlDeclaration = 1;
3817
0
      redirect_write_append = 1;
3818
0
  } else
3819
0
      style->omitXmlDeclaration = 0;
3820
0
  xmlFree(prop);
3821
0
    }
3822
3823
0
    if (redirect_write_append) {
3824
0
        FILE *f;
3825
3826
0
  f = fopen((const char *) filename, "ab");
3827
0
  if (f == NULL) {
3828
0
      ret = -1;
3829
0
  } else {
3830
0
      ret = xsltSaveResultToFile(f, res, style);
3831
0
      fclose(f);
3832
0
  }
3833
0
    } else {
3834
0
  ret = xsltSaveResultToFilename((const char *) filename, res, style, 0);
3835
0
    }
3836
0
    if (ret < 0) {
3837
0
  xsltTransformError(ctxt, NULL, inst,
3838
0
                         "xsltDocumentElem: unable to save to %s\n",
3839
0
                         filename);
3840
#ifdef WITH_XSLT_DEBUG_EXTRA
3841
    } else {
3842
        xsltGenericDebug(xsltGenericDebugContext,
3843
                         "Wrote %d bytes to %s\n", ret, filename);
3844
#endif
3845
0
    }
3846
3847
0
  error:
3848
0
    ctxt->output = oldOutput;
3849
0
    ctxt->insert = oldInsert;
3850
0
    ctxt->type = oldType;
3851
0
    ctxt->outputFile = oldOutputFile;
3852
0
    if (URL != NULL)
3853
0
        xmlFree(URL);
3854
0
    if (filename != NULL)
3855
0
        xmlFree(filename);
3856
0
    if (style != NULL)
3857
0
        xsltFreeStylesheet(style);
3858
0
    if (res != NULL)
3859
0
        xmlFreeDoc(res);
3860
0
}
3861
3862
/************************************************************************
3863
 *                  *
3864
 *    Most of the XSLT-1.0 transformations      *
3865
 *                  *
3866
 ************************************************************************/
3867
3868
/**
3869
 * xsltSort:
3870
 * @ctxt:  a XSLT process context
3871
 * @node:  the node in the source tree.
3872
 * @inst:  the xslt sort node
3873
 * @comp:  precomputed information
3874
 *
3875
 * function attached to xsl:sort nodes, but this should not be
3876
 * called directly
3877
 */
3878
void
3879
xsltSort(xsltTransformContextPtr ctxt,
3880
  xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
3881
0
  xsltElemPreCompPtr comp) {
3882
0
    if (comp == NULL) {
3883
0
  xsltTransformError(ctxt, NULL, inst,
3884
0
       "xsl:sort : compilation failed\n");
3885
0
  return;
3886
0
    }
3887
0
    xsltTransformError(ctxt, NULL, inst,
3888
0
   "xsl:sort : improper use this should not be reached\n");
3889
0
}
3890
3891
/**
3892
 * xsltCopy:
3893
 * @ctxt:  an XSLT process context
3894
 * @node:  the node in the source tree
3895
 * @inst:  the element node of the XSLT-copy instruction
3896
 * @castedComp:  computed information of the XSLT-copy instruction
3897
 *
3898
 * Execute the XSLT-copy instruction on the source node.
3899
 */
3900
void
3901
xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
3902
   xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3903
0
{
3904
#ifdef XSLT_REFACTORED
3905
    xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
3906
#else
3907
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3908
0
#endif
3909
0
    xmlNodePtr copy, oldInsert;
3910
3911
0
    oldInsert = ctxt->insert;
3912
0
    if (ctxt->insert != NULL) {
3913
0
  switch (node->type) {
3914
0
      case XML_TEXT_NODE:
3915
0
      case XML_CDATA_SECTION_NODE:
3916
    /*
3917
     * This text comes from the stylesheet
3918
     * For stylesheets, the set of whitespace-preserving
3919
     * element names consists of just xsl:text.
3920
     */
3921
#ifdef WITH_XSLT_DEBUG_PROCESS
3922
    if (node->type == XML_CDATA_SECTION_NODE) {
3923
        XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3924
       "xsltCopy: CDATA text %s\n", node->content));
3925
    } else {
3926
        XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3927
       "xsltCopy: text %s\n", node->content));
3928
                }
3929
#endif
3930
0
    xsltCopyText(ctxt, ctxt->insert, node, 0);
3931
0
    break;
3932
0
      case XML_DOCUMENT_NODE:
3933
0
      case XML_HTML_DOCUMENT_NODE:
3934
0
    break;
3935
0
      case XML_ELEMENT_NODE:
3936
    /*
3937
    * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3938
    * REMOVED:
3939
    *   if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3940
    *    return;
3941
    */
3942
3943
#ifdef WITH_XSLT_DEBUG_PROCESS
3944
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3945
         "xsltCopy: node %s\n", node->name));
3946
#endif
3947
0
    copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
3948
0
    ctxt->insert = copy;
3949
0
    if (comp->use != NULL) {
3950
0
        xsltApplyAttributeSet(ctxt, node, inst, comp->use);
3951
0
    }
3952
0
    break;
3953
0
      case XML_ATTRIBUTE_NODE: {
3954
#ifdef WITH_XSLT_DEBUG_PROCESS
3955
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3956
         "xsltCopy: attribute %s\n", node->name));
3957
#endif
3958
    /*
3959
    * REVISIT: We could also raise an error if the parent is not
3960
    * an element node.
3961
    * OPTIMIZE TODO: Can we set the value/children of the
3962
    * attribute without an intermediate copy of the string value?
3963
    */
3964
0
    xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
3965
0
    break;
3966
0
      }
3967
0
      case XML_PI_NODE:
3968
#ifdef WITH_XSLT_DEBUG_PROCESS
3969
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3970
         "xsltCopy: PI %s\n", node->name));
3971
#endif
3972
0
    copy = xmlNewDocPI(ctxt->insert->doc, node->name,
3973
0
                       node->content);
3974
0
    copy = xsltAddChild(ctxt->insert, copy);
3975
0
    break;
3976
0
      case XML_COMMENT_NODE:
3977
#ifdef WITH_XSLT_DEBUG_PROCESS
3978
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3979
         "xsltCopy: comment\n"));
3980
#endif
3981
0
    copy = xmlNewComment(node->content);
3982
0
    copy = xsltAddChild(ctxt->insert, copy);
3983
0
    break;
3984
0
      case XML_NAMESPACE_DECL:
3985
#ifdef WITH_XSLT_DEBUG_PROCESS
3986
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3987
         "xsltCopy: namespace declaration\n"));
3988
#endif
3989
0
    xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
3990
0
    break;
3991
0
      default:
3992
0
    break;
3993
3994
0
  }
3995
0
    }
3996
3997
0
    switch (node->type) {
3998
0
  case XML_DOCUMENT_NODE:
3999
0
  case XML_HTML_DOCUMENT_NODE:
4000
0
  case XML_ELEMENT_NODE:
4001
0
      xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4002
0
    NULL);
4003
0
      break;
4004
0
  default:
4005
0
      break;
4006
0
    }
4007
0
    ctxt->insert = oldInsert;
4008
0
}
4009
4010
/**
4011
 * xsltText:
4012
 * @ctxt:  a XSLT process context
4013
 * @node:  the node in the source tree.
4014
 * @inst:  the xslt text node
4015
 * @comp:  precomputed information
4016
 *
4017
 * Process the xslt text node on the source node
4018
 */
4019
void
4020
xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
4021
0
      xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
4022
0
    if ((inst->children != NULL) && (comp != NULL)) {
4023
0
  xmlNodePtr text = inst->children;
4024
0
  xmlNodePtr copy;
4025
4026
0
  while (text != NULL) {
4027
0
      if ((text->type != XML_TEXT_NODE) &&
4028
0
           (text->type != XML_CDATA_SECTION_NODE)) {
4029
0
    xsltTransformError(ctxt, NULL, inst,
4030
0
         "xsl:text content problem\n");
4031
0
    break;
4032
0
      }
4033
0
      copy = xmlNewDocText(ctxt->output, text->content);
4034
0
      if (text->type != XML_CDATA_SECTION_NODE) {
4035
#ifdef WITH_XSLT_DEBUG_PARSING
4036
    xsltGenericDebug(xsltGenericDebugContext,
4037
         "Disable escaping: %s\n", text->content);
4038
#endif
4039
0
    copy->name = xmlStringTextNoenc;
4040
0
      }
4041
0
      copy = xsltAddChild(ctxt->insert, copy);
4042
0
      text = text->next;
4043
0
  }
4044
0
    }
4045
0
}
4046
4047
/**
4048
 * xsltElement:
4049
 * @ctxt:  a XSLT process context
4050
 * @node:  the node in the source tree.
4051
 * @inst:  the xslt element node
4052
 * @castedComp:  precomputed information
4053
 *
4054
 * Process the xslt element node on the source node
4055
 */
4056
void
4057
xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
4058
0
      xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4059
#ifdef XSLT_REFACTORED
4060
    xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
4061
#else
4062
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4063
0
#endif
4064
0
    xmlChar *prop = NULL;
4065
0
    const xmlChar *name, *prefix = NULL, *nsName = NULL;
4066
0
    xmlNodePtr copy;
4067
0
    xmlNodePtr oldInsert;
4068
4069
0
    if (ctxt->insert == NULL)
4070
0
  return;
4071
4072
    /*
4073
    * A comp->has_name == 0 indicates that we need to skip this instruction,
4074
    * since it was evaluated to be invalid already during compilation.
4075
    */
4076
0
    if (!comp->has_name)
4077
0
        return;
4078
4079
    /*
4080
     * stack and saves
4081
     */
4082
0
    oldInsert = ctxt->insert;
4083
4084
0
    if (comp->name == NULL) {
4085
  /* TODO: fix attr acquisition wrt to the XSLT namespace */
4086
0
        prop = xsltEvalAttrValueTemplate(ctxt, inst,
4087
0
      (const xmlChar *) "name", XSLT_NAMESPACE);
4088
0
        if (prop == NULL) {
4089
0
            xsltTransformError(ctxt, NULL, inst,
4090
0
    "xsl:element: The attribute 'name' is missing.\n");
4091
0
            goto error;
4092
0
        }
4093
0
  if (xmlValidateQName(prop, 0)) {
4094
0
      xsltTransformError(ctxt, NULL, inst,
4095
0
    "xsl:element: The effective name '%s' is not a "
4096
0
    "valid QName.\n", prop);
4097
      /* we fall through to catch any further errors, if possible */
4098
0
  }
4099
0
  name = xsltSplitQName(ctxt->dict, prop, &prefix);
4100
0
  xmlFree(prop);
4101
0
    } else {
4102
  /*
4103
  * The "name" value was static.
4104
  */
4105
#ifdef XSLT_REFACTORED
4106
  prefix = comp->nsPrefix;
4107
  name = comp->name;
4108
#else
4109
0
  name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
4110
0
#endif
4111
0
    }
4112
4113
    /*
4114
     * Create the new element
4115
     */
4116
0
    if (ctxt->output->dict == ctxt->dict) {
4117
0
  copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
4118
0
    } else {
4119
0
  copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
4120
0
    }
4121
0
    if (copy == NULL) {
4122
0
  xsltTransformError(ctxt, NULL, inst,
4123
0
      "xsl:element : creation of %s failed\n", name);
4124
0
  return;
4125
0
    }
4126
0
    copy = xsltAddChild(ctxt->insert, copy);
4127
0
    if (copy == NULL) {
4128
0
        xsltTransformError(ctxt, NULL, inst,
4129
0
            "xsl:element : xsltAddChild failed\n");
4130
0
        return;
4131
0
    }
4132
4133
    /*
4134
    * Namespace
4135
    * ---------
4136
    */
4137
0
    if (comp->has_ns) {
4138
0
  if (comp->ns != NULL) {
4139
      /*
4140
      * No AVT; just plain text for the namespace name.
4141
      */
4142
0
      if (comp->ns[0] != 0)
4143
0
    nsName = comp->ns;
4144
0
  } else {
4145
0
      xmlChar *tmpNsName;
4146
      /*
4147
      * Eval the AVT.
4148
      */
4149
      /* TODO: check attr acquisition wrt to the XSLT namespace */
4150
0
      tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
4151
0
    (const xmlChar *) "namespace", XSLT_NAMESPACE);
4152
      /*
4153
      * SPEC XSLT 1.0:
4154
      *  "If the string is empty, then the expanded-name of the
4155
      *  attribute has a null namespace URI."
4156
      */
4157
0
      if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
4158
0
    nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
4159
0
      xmlFree(tmpNsName);
4160
0
  }
4161
4162
0
        if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
4163
0
            xsltTransformError(ctxt, NULL, inst,
4164
0
                "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4165
0
                "forbidden.\n");
4166
0
            goto error;
4167
0
        }
4168
0
        if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
4169
0
            prefix = BAD_CAST "xml";
4170
0
        } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
4171
0
            prefix = NULL;
4172
0
        }
4173
0
    } else {
4174
0
  xmlNsPtr ns;
4175
  /*
4176
  * SPEC XSLT 1.0:
4177
  *  "If the namespace attribute is not present, then the QName is
4178
  *  expanded into an expanded-name using the namespace declarations
4179
  *  in effect for the xsl:element element, including any default
4180
  *  namespace declaration.
4181
  */
4182
0
  ns = xmlSearchNs(inst->doc, inst, prefix);
4183
0
  if (ns == NULL) {
4184
      /*
4185
      * TODO: Check this in the compilation layer in case it's a
4186
      * static value.
4187
      */
4188
0
            if (prefix != NULL) {
4189
0
                xsltTransformError(ctxt, NULL, inst,
4190
0
                    "xsl:element: The QName '%s:%s' has no "
4191
0
                    "namespace binding in scope in the stylesheet; "
4192
0
                    "this is an error, since the namespace was not "
4193
0
                    "specified by the instruction itself.\n", prefix, name);
4194
0
            }
4195
0
  } else
4196
0
      nsName = ns->href;
4197
0
    }
4198
    /*
4199
    * Find/create a matching ns-decl in the result tree.
4200
    */
4201
0
    if (nsName != NULL) {
4202
0
  if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
4203
            /* Don't use a prefix of "xmlns" */
4204
0
      xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
4205
4206
0
      copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy);
4207
4208
0
      xmlFree(pref);
4209
0
  } else {
4210
0
      copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
4211
0
    copy);
4212
0
  }
4213
0
    } else if ((copy->parent != NULL) &&
4214
0
  (copy->parent->type == XML_ELEMENT_NODE) &&
4215
0
  (copy->parent->ns != NULL))
4216
0
    {
4217
  /*
4218
  * "Undeclare" the default namespace.
4219
  */
4220
0
  xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
4221
0
    }
4222
4223
0
    ctxt->insert = copy;
4224
4225
0
    if (comp->has_use) {
4226
0
  if (comp->use != NULL) {
4227
0
      xsltApplyAttributeSet(ctxt, node, inst, comp->use);
4228
0
  } else {
4229
0
      xmlChar *attrSets = NULL;
4230
      /*
4231
      * BUG TODO: use-attribute-sets is not a value template.
4232
      *  use-attribute-sets = qnames
4233
      */
4234
0
      attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
4235
0
    (const xmlChar *)"use-attribute-sets", NULL);
4236
0
      if (attrSets != NULL) {
4237
0
    xsltApplyAttributeSet(ctxt, node, inst, attrSets);
4238
0
    xmlFree(attrSets);
4239
0
      }
4240
0
  }
4241
0
    }
4242
    /*
4243
    * Instantiate the sequence constructor.
4244
    */
4245
0
    if (inst->children != NULL)
4246
0
  xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4247
0
      NULL);
4248
4249
0
error:
4250
0
    ctxt->insert = oldInsert;
4251
0
    return;
4252
0
}
4253
4254
4255
/**
4256
 * xsltComment:
4257
 * @ctxt:  a XSLT process context
4258
 * @node:  the node in the source tree.
4259
 * @inst:  the xslt comment node
4260
 * @comp:  precomputed information
4261
 *
4262
 * Process the xslt comment node on the source node
4263
 */
4264
void
4265
xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
4266
0
             xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
4267
0
    xmlChar *value = NULL;
4268
0
    xmlNodePtr commentNode;
4269
0
    int len;
4270
4271
0
    value = xsltEvalTemplateString(ctxt, node, inst);
4272
    /* TODO: use or generate the compiled form */
4273
0
    len = xmlStrlen(value);
4274
0
    if (len > 0) {
4275
0
        if ((value[len-1] == '-') ||
4276
0
      (xmlStrstr(value, BAD_CAST "--"))) {
4277
0
      xsltTransformError(ctxt, NULL, inst,
4278
0
        "xsl:comment : '--' or ending '-' not allowed in comment\n");
4279
      /* fall through to try to catch further errors */
4280
0
  }
4281
0
    }
4282
#ifdef WITH_XSLT_DEBUG_PROCESS
4283
    if (value == NULL) {
4284
  XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4285
       "xsltComment: empty\n"));
4286
    } else {
4287
  XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4288
       "xsltComment: content %s\n", value));
4289
    }
4290
#endif
4291
4292
0
    commentNode = xmlNewComment(value);
4293
0
    commentNode = xsltAddChild(ctxt->insert, commentNode);
4294
4295
0
    if (value != NULL)
4296
0
  xmlFree(value);
4297
0
}
4298
4299
/**
4300
 * xsltProcessingInstruction:
4301
 * @ctxt:  a XSLT process context
4302
 * @node:  the node in the source tree.
4303
 * @inst:  the xslt processing-instruction node
4304
 * @castedComp:  precomputed information
4305
 *
4306
 * Process the xslt processing-instruction node on the source node
4307
 */
4308
void
4309
xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
4310
0
             xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4311
#ifdef XSLT_REFACTORED
4312
    xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
4313
#else
4314
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4315
0
#endif
4316
0
    const xmlChar *name;
4317
0
    xmlChar *value = NULL;
4318
0
    xmlNodePtr pi;
4319
4320
4321
0
    if (ctxt->insert == NULL)
4322
0
  return;
4323
0
    if (comp->has_name == 0)
4324
0
  return;
4325
0
    if (comp->name == NULL) {
4326
0
  name = xsltEvalAttrValueTemplate(ctxt, inst,
4327
0
          (const xmlChar *)"name", NULL);
4328
0
  if (name == NULL) {
4329
0
      xsltTransformError(ctxt, NULL, inst,
4330
0
     "xsl:processing-instruction : name is missing\n");
4331
0
      goto error;
4332
0
  }
4333
0
    } else {
4334
0
  name = comp->name;
4335
0
    }
4336
    /* TODO: check that it's both an an NCName and a PITarget. */
4337
4338
4339
0
    value = xsltEvalTemplateString(ctxt, node, inst);
4340
0
    if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
4341
0
  xsltTransformError(ctxt, NULL, inst,
4342
0
       "xsl:processing-instruction: '?>' not allowed within PI content\n");
4343
0
  goto error;
4344
0
    }
4345
#ifdef WITH_XSLT_DEBUG_PROCESS
4346
    if (value == NULL) {
4347
  XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4348
       "xsltProcessingInstruction: %s empty\n", name));
4349
    } else {
4350
  XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4351
       "xsltProcessingInstruction: %s content %s\n", name, value));
4352
    }
4353
#endif
4354
4355
0
    pi = xmlNewDocPI(ctxt->insert->doc, name, value);
4356
0
    pi = xsltAddChild(ctxt->insert, pi);
4357
4358
0
error:
4359
0
    if ((name != NULL) && (name != comp->name))
4360
0
        xmlFree((xmlChar *) name);
4361
0
    if (value != NULL)
4362
0
  xmlFree(value);
4363
0
}
4364
4365
/**
4366
 * xsltCopyOf:
4367
 * @ctxt:  an XSLT transformation context
4368
 * @node:  the current node in the source tree
4369
 * @inst:  the element node of the XSLT copy-of instruction
4370
 * @castedComp:  precomputed information of the XSLT copy-of instruction
4371
 *
4372
 * Process the XSLT copy-of instruction.
4373
 */
4374
void
4375
xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4376
0
             xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4377
#ifdef XSLT_REFACTORED
4378
    xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
4379
#else
4380
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4381
0
#endif
4382
0
    xmlXPathObjectPtr res = NULL;
4383
0
    xmlNodeSetPtr list = NULL;
4384
0
    int i;
4385
4386
0
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4387
0
  return;
4388
0
    if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4389
0
  xsltTransformError(ctxt, NULL, inst,
4390
0
       "xsl:copy-of : compilation failed\n");
4391
0
  return;
4392
0
    }
4393
4394
     /*
4395
    * SPEC XSLT 1.0:
4396
    *  "The xsl:copy-of element can be used to insert a result tree
4397
    *  fragment into the result tree, without first converting it to
4398
    *  a string as xsl:value-of does (see [7.6.1 Generating Text with
4399
    *  xsl:value-of]). The required select attribute contains an
4400
    *  expression. When the result of evaluating the expression is a
4401
    *  result tree fragment, the complete fragment is copied into the
4402
    *  result tree. When the result is a node-set, all the nodes in the
4403
    *  set are copied in document order into the result tree; copying
4404
    *  an element node copies the attribute nodes, namespace nodes and
4405
    *  children of the element node as well as the element node itself;
4406
    *  a root node is copied by copying its children. When the result
4407
    *  is neither a node-set nor a result tree fragment, the result is
4408
    *  converted to a string and then inserted into the result tree,
4409
    *  as with xsl:value-of.
4410
    */
4411
4412
#ifdef WITH_XSLT_DEBUG_PROCESS
4413
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4414
   "xsltCopyOf: select %s\n", comp->select));
4415
#endif
4416
4417
    /*
4418
    * Evaluate the "select" expression.
4419
    */
4420
0
    res = xsltPreCompEval(ctxt, node, comp);
4421
4422
0
    if (res != NULL) {
4423
0
  if (res->type == XPATH_NODESET) {
4424
      /*
4425
      * Node-set
4426
      * --------
4427
      */
4428
#ifdef WITH_XSLT_DEBUG_PROCESS
4429
      XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4430
     "xsltCopyOf: result is a node set\n"));
4431
#endif
4432
0
      list = res->nodesetval;
4433
0
      if (list != NULL) {
4434
0
    xmlNodePtr cur;
4435
    /*
4436
    * The list is already sorted in document order by XPath.
4437
    * Append everything in this order under ctxt->insert.
4438
    */
4439
0
    for (i = 0;i < list->nodeNr;i++) {
4440
0
        cur = list->nodeTab[i];
4441
0
        if (cur == NULL)
4442
0
      continue;
4443
0
        if ((cur->type == XML_DOCUMENT_NODE) ||
4444
0
      (cur->type == XML_HTML_DOCUMENT_NODE))
4445
0
        {
4446
0
      xsltCopyTreeList(ctxt, inst,
4447
0
          cur->children, ctxt->insert, 0, 0);
4448
0
        } else if (cur->type == XML_ATTRIBUTE_NODE) {
4449
0
      xsltShallowCopyAttr(ctxt, inst,
4450
0
          ctxt->insert, (xmlAttrPtr) cur);
4451
0
        } else {
4452
0
      xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
4453
0
        }
4454
0
    }
4455
0
      }
4456
0
  } else if (res->type == XPATH_XSLT_TREE) {
4457
      /*
4458
      * Result tree fragment
4459
      * --------------------
4460
      * E.g. via <xsl:variable ...><foo/></xsl:variable>
4461
      * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4462
      */
4463
#ifdef WITH_XSLT_DEBUG_PROCESS
4464
      XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4465
     "xsltCopyOf: result is a result tree fragment\n"));
4466
#endif
4467
0
      list = res->nodesetval;
4468
0
      if ((list != NULL) && (list->nodeTab != NULL) &&
4469
0
    (list->nodeTab[0] != NULL) &&
4470
0
    (IS_XSLT_REAL_NODE(list->nodeTab[0])))
4471
0
      {
4472
0
    xsltCopyTreeList(ctxt, inst,
4473
0
        list->nodeTab[0]->children, ctxt->insert, 0, 0);
4474
0
      }
4475
0
  } else {
4476
0
      xmlChar *value = NULL;
4477
      /*
4478
      * Convert to a string.
4479
      */
4480
0
      value = xmlXPathCastToString(res);
4481
0
      if (value == NULL) {
4482
0
    xsltTransformError(ctxt, NULL, inst,
4483
0
        "Internal error in xsltCopyOf(): "
4484
0
        "failed to cast an XPath object to string.\n");
4485
0
    ctxt->state = XSLT_STATE_STOPPED;
4486
0
      } else {
4487
0
    if (value[0] != 0) {
4488
        /*
4489
        * Append content as text node.
4490
        */
4491
0
        xsltCopyTextString(ctxt, ctxt->insert, value, 0);
4492
0
    }
4493
0
    xmlFree(value);
4494
4495
#ifdef WITH_XSLT_DEBUG_PROCESS
4496
    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4497
        "xsltCopyOf: result %s\n", res->stringval));
4498
#endif
4499
0
      }
4500
0
  }
4501
0
    } else {
4502
0
  ctxt->state = XSLT_STATE_STOPPED;
4503
0
    }
4504
4505
0
    if (res != NULL)
4506
0
  xmlXPathFreeObject(res);
4507
0
}
4508
4509
/**
4510
 * xsltValueOf:
4511
 * @ctxt:  a XSLT process context
4512
 * @node:  the node in the source tree.
4513
 * @inst:  the xslt value-of node
4514
 * @castedComp:  precomputed information
4515
 *
4516
 * Process the xslt value-of node on the source node
4517
 */
4518
void
4519
xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4520
             xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4521
0
{
4522
#ifdef XSLT_REFACTORED
4523
    xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
4524
#else
4525
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4526
0
#endif
4527
0
    xmlXPathObjectPtr res = NULL;
4528
0
    xmlChar *value = NULL;
4529
4530
0
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4531
0
  return;
4532
4533
0
    if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4534
0
  xsltTransformError(ctxt, NULL, inst,
4535
0
      "Internal error in xsltValueOf(): "
4536
0
      "The XSLT 'value-of' instruction was not compiled.\n");
4537
0
  return;
4538
0
    }
4539
4540
#ifdef WITH_XSLT_DEBUG_PROCESS
4541
    XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4542
   "xsltValueOf: select %s\n", comp->select));
4543
#endif
4544
4545
0
    res = xsltPreCompEval(ctxt, node, comp);
4546
4547
    /*
4548
    * Cast the XPath object to string.
4549
    */
4550
0
    if (res != NULL) {
4551
0
  value = xmlXPathCastToString(res);
4552
0
  if (value == NULL) {
4553
0
      xsltTransformError(ctxt, NULL, inst,
4554
0
    "Internal error in xsltValueOf(): "
4555
0
    "failed to cast an XPath object to string.\n");
4556
0
      ctxt->state = XSLT_STATE_STOPPED;
4557
0
      goto error;
4558
0
  }
4559
0
  if (value[0] != 0) {
4560
0
      xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape);
4561
0
  }
4562
0
    } else {
4563
0
  xsltTransformError(ctxt, NULL, inst,
4564
0
      "XPath evaluation returned no result.\n");
4565
0
  ctxt->state = XSLT_STATE_STOPPED;
4566
0
  goto error;
4567
0
    }
4568
4569
#ifdef WITH_XSLT_DEBUG_PROCESS
4570
    if (value) {
4571
  XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4572
       "xsltValueOf: result '%s'\n", value));
4573
    }
4574
#endif
4575
4576
0
error:
4577
0
    if (value != NULL)
4578
0
  xmlFree(value);
4579
0
    if (res != NULL)
4580
0
  xmlXPathFreeObject(res);
4581
0
}
4582
4583
/**
4584
 * xsltNumber:
4585
 * @ctxt:  a XSLT process context
4586
 * @node:  the node in the source tree.
4587
 * @inst:  the xslt number node
4588
 * @castedComp:  precomputed information
4589
 *
4590
 * Process the xslt number node on the source node
4591
 */
4592
void
4593
xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
4594
     xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4595
0
{
4596
#ifdef XSLT_REFACTORED
4597
    xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
4598
#else
4599
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4600
0
#endif
4601
0
    xmlXPathContextPtr xpctxt;
4602
0
    xmlNsPtr *oldXPNamespaces;
4603
0
    int oldXPNsNr;
4604
4605
0
    if (comp == NULL) {
4606
0
  xsltTransformError(ctxt, NULL, inst,
4607
0
       "xsl:number : compilation failed\n");
4608
0
  return;
4609
0
    }
4610
4611
0
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4612
0
  return;
4613
4614
0
    comp->numdata.doc = inst->doc;
4615
0
    comp->numdata.node = inst;
4616
4617
0
    xpctxt = ctxt->xpathCtxt;
4618
0
    oldXPNsNr = xpctxt->nsNr;
4619
0
    oldXPNamespaces = xpctxt->namespaces;
4620
4621
#ifdef XSLT_REFACTORED
4622
    if (comp->inScopeNs != NULL) {
4623
        xpctxt->namespaces = comp->inScopeNs->list;
4624
        xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4625
    } else {
4626
        xpctxt->namespaces = NULL;
4627
        xpctxt->nsNr = 0;
4628
    }
4629
#else
4630
0
    xpctxt->namespaces = comp->nsList;
4631
0
    xpctxt->nsNr = comp->nsNr;
4632
0
#endif
4633
4634
0
    xsltNumberFormat(ctxt, &comp->numdata, node);
4635
4636
0
    xpctxt->nsNr = oldXPNsNr;
4637
0
    xpctxt->namespaces = oldXPNamespaces;
4638
0
}
4639
4640
/**
4641
 * xsltApplyImports:
4642
 * @ctxt:  an XSLT transformation context
4643
 * @contextNode:  the current node in the source tree.
4644
 * @inst:  the element node of the XSLT 'apply-imports' instruction
4645
 * @comp:  the compiled instruction
4646
 *
4647
 * Process the XSLT apply-imports element.
4648
 */
4649
void
4650
xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
4651
           xmlNodePtr inst,
4652
     xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
4653
0
{
4654
0
    xsltTemplatePtr templ;
4655
4656
0
    if ((ctxt == NULL) || (inst == NULL))
4657
0
  return;
4658
4659
0
    if (comp == NULL) {
4660
0
  xsltTransformError(ctxt, NULL, inst,
4661
0
      "Internal error in xsltApplyImports(): "
4662
0
      "The XSLT 'apply-imports' instruction was not compiled.\n");
4663
0
  return;
4664
0
    }
4665
    /*
4666
    * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4667
    * same; the former is the "Current Template Rule" as defined by the
4668
    * XSLT spec, the latter is simply the template struct being
4669
    * currently processed.
4670
    */
4671
0
    if (ctxt->currentTemplateRule == NULL) {
4672
  /*
4673
  * SPEC XSLT 2.0:
4674
  * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4675
  *  xsl:apply-imports or xsl:next-match is evaluated when the
4676
  *  current template rule is null."
4677
  */
4678
0
  xsltTransformError(ctxt, NULL, inst,
4679
0
       "It is an error to call 'apply-imports' "
4680
0
       "when there's no current template rule.\n");
4681
0
  return;
4682
0
    }
4683
    /*
4684
    * TODO: Check if this is correct.
4685
    */
4686
0
    templ = xsltGetTemplate(ctxt, contextNode,
4687
0
  ctxt->currentTemplateRule->style);
4688
4689
0
    if (templ != NULL) {
4690
0
  xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
4691
  /*
4692
  * Set the current template rule.
4693
  */
4694
0
  ctxt->currentTemplateRule = templ;
4695
  /*
4696
  * URGENT TODO: Need xsl:with-param be handled somehow here?
4697
  */
4698
0
  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
4699
0
      templ, NULL);
4700
4701
0
  ctxt->currentTemplateRule = oldCurTemplRule;
4702
0
    }
4703
0
    else {
4704
        /* Use built-in templates. */
4705
0
        xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
4706
0
    }
4707
0
}
4708
4709
/**
4710
 * xsltCallTemplate:
4711
 * @ctxt:  a XSLT transformation context
4712
 * @node:  the "current node" in the source tree
4713
 * @inst:  the XSLT 'call-template' instruction
4714
 * @castedComp:  the compiled information of the instruction
4715
 *
4716
 * Processes the XSLT call-template instruction on the source node.
4717
 */
4718
void
4719
xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
4720
             xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4721
0
{
4722
#ifdef XSLT_REFACTORED
4723
    xsltStyleItemCallTemplatePtr comp =
4724
  (xsltStyleItemCallTemplatePtr) castedComp;
4725
#else
4726
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4727
0
#endif
4728
0
    xsltStackElemPtr withParams = NULL;
4729
4730
0
    if (ctxt->insert == NULL)
4731
0
  return;
4732
0
    if (comp == NULL) {
4733
0
  xsltTransformError(ctxt, NULL, inst,
4734
0
       "The XSLT 'call-template' instruction was not compiled.\n");
4735
0
  return;
4736
0
    }
4737
4738
    /*
4739
     * The template must have been precomputed
4740
     */
4741
0
    if (comp->templ == NULL) {
4742
0
  comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
4743
0
  if (comp->templ == NULL) {
4744
0
      if (comp->ns != NULL) {
4745
0
          xsltTransformError(ctxt, NULL, inst,
4746
0
      "The called template '{%s}%s' was not found.\n",
4747
0
      comp->ns, comp->name);
4748
0
      } else {
4749
0
          xsltTransformError(ctxt, NULL, inst,
4750
0
      "The called template '%s' was not found.\n",
4751
0
      comp->name);
4752
0
      }
4753
0
      return;
4754
0
  }
4755
0
    }
4756
4757
#ifdef WITH_XSLT_DEBUG_PROCESS
4758
    if ((comp != NULL) && (comp->name != NULL))
4759
  XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4760
       "call-template: name %s\n", comp->name));
4761
#endif
4762
4763
0
    if (inst->children) {
4764
0
  xmlNodePtr cur;
4765
0
  xsltStackElemPtr param;
4766
4767
0
  cur = inst->children;
4768
0
  while (cur != NULL) {
4769
#ifdef WITH_DEBUGGER
4770
      if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4771
    xslHandleDebugger(cur, node, comp->templ, ctxt);
4772
#endif
4773
0
      if (ctxt->state == XSLT_STATE_STOPPED) break;
4774
      /*
4775
      * TODO: The "with-param"s could be part of the "call-template"
4776
      *   structure. Avoid to "search" for params dynamically
4777
      *   in the XML tree every time.
4778
      */
4779
0
      if (IS_XSLT_ELEM(cur)) {
4780
0
    if (IS_XSLT_NAME(cur, "with-param")) {
4781
0
        param = xsltParseStylesheetCallerParam(ctxt, cur);
4782
0
        if (param != NULL) {
4783
0
      param->next = withParams;
4784
0
      withParams = param;
4785
0
        }
4786
0
    } else {
4787
0
        xsltGenericError(xsltGenericErrorContext,
4788
0
      "xsl:call-template: misplaced xsl:%s\n", cur->name);
4789
0
    }
4790
0
      } else {
4791
0
    xsltGenericError(xsltGenericErrorContext,
4792
0
        "xsl:call-template: misplaced %s element\n", cur->name);
4793
0
      }
4794
0
      cur = cur->next;
4795
0
  }
4796
0
    }
4797
    /*
4798
     * Create a new frame using the params first
4799
     */
4800
0
    xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
4801
0
  withParams);
4802
0
    if (withParams != NULL)
4803
0
  xsltFreeStackElemList(withParams);
4804
4805
#ifdef WITH_XSLT_DEBUG_PROCESS
4806
    if ((comp != NULL) && (comp->name != NULL))
4807
  XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4808
       "call-template returned: name %s\n", comp->name));
4809
#endif
4810
0
}
4811
4812
/**
4813
 * xsltApplyTemplates:
4814
 * @ctxt:  a XSLT transformation context
4815
 * @node:  the 'current node' in the source tree
4816
 * @inst:  the element node of an XSLT 'apply-templates' instruction
4817
 * @castedComp:  the compiled instruction
4818
 *
4819
 * Processes the XSLT 'apply-templates' instruction on the current node.
4820
 */
4821
void
4822
xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
4823
             xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4824
0
{
4825
#ifdef XSLT_REFACTORED
4826
    xsltStyleItemApplyTemplatesPtr comp =
4827
  (xsltStyleItemApplyTemplatesPtr) castedComp;
4828
#else
4829
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4830
0
#endif
4831
0
    int i;
4832
0
    xmlNodePtr cur, oldContextNode;
4833
0
    xmlNodeSetPtr list = NULL, oldList;
4834
0
    xsltStackElemPtr withParams = NULL;
4835
0
    int oldXPProximityPosition, oldXPContextSize;
4836
0
    const xmlChar *oldMode, *oldModeURI;
4837
0
    xmlDocPtr oldXPDoc;
4838
0
    xsltDocumentPtr oldDocInfo;
4839
0
    xmlXPathContextPtr xpctxt;
4840
4841
0
    if (comp == NULL) {
4842
0
  xsltTransformError(ctxt, NULL, inst,
4843
0
       "xsl:apply-templates : compilation failed\n");
4844
0
  return;
4845
0
    }
4846
0
    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4847
0
  return;
4848
4849
#ifdef WITH_XSLT_DEBUG_PROCESS
4850
    if ((node != NULL) && (node->name != NULL))
4851
  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4852
       "xsltApplyTemplates: node: '%s'\n", node->name));
4853
#endif
4854
4855
0
    xpctxt = ctxt->xpathCtxt;
4856
    /*
4857
    * Save context states.
4858
    */
4859
0
    oldContextNode = ctxt->node;
4860
0
    oldMode = ctxt->mode;
4861
0
    oldModeURI = ctxt->modeURI;
4862
0
    oldDocInfo = ctxt->document;
4863
0
    oldList = ctxt->nodeList;
4864
4865
    /*
4866
     * The xpath context size and proximity position, as
4867
     * well as the xpath and context documents, may be changed
4868
     * so we save their initial state and will restore on exit
4869
     */
4870
0
    oldXPContextSize = xpctxt->contextSize;
4871
0
    oldXPProximityPosition = xpctxt->proximityPosition;
4872
0
    oldXPDoc = xpctxt->doc;
4873
4874
    /*
4875
    * Set up contexts.
4876
    */
4877
0
    ctxt->mode = comp->mode;
4878
0
    ctxt->modeURI = comp->modeURI;
4879
4880
0
    if (comp->select != NULL) {
4881
0
  xmlXPathObjectPtr res = NULL;
4882
4883
0
  if (comp->comp == NULL) {
4884
0
      xsltTransformError(ctxt, NULL, inst,
4885
0
     "xsl:apply-templates : compilation failed\n");
4886
0
      goto error;
4887
0
  }
4888
#ifdef WITH_XSLT_DEBUG_PROCESS
4889
  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4890
       "xsltApplyTemplates: select %s\n", comp->select));
4891
#endif
4892
4893
0
  res = xsltPreCompEval(ctxt, node, comp);
4894
4895
0
  if (res != NULL) {
4896
0
      if (res->type == XPATH_NODESET) {
4897
0
    list = res->nodesetval; /* consume the node set */
4898
0
    res->nodesetval = NULL;
4899
0
      } else {
4900
0
    xsltTransformError(ctxt, NULL, inst,
4901
0
        "The 'select' expression did not evaluate to a "
4902
0
        "node set.\n");
4903
0
    ctxt->state = XSLT_STATE_STOPPED;
4904
0
    xmlXPathFreeObject(res);
4905
0
    goto error;
4906
0
      }
4907
0
      xmlXPathFreeObject(res);
4908
      /*
4909
      * Note: An xsl:apply-templates with a 'select' attribute,
4910
      * can change the current source doc.
4911
      */
4912
0
  } else {
4913
0
      xsltTransformError(ctxt, NULL, inst,
4914
0
    "Failed to evaluate the 'select' expression.\n");
4915
0
      ctxt->state = XSLT_STATE_STOPPED;
4916
0
      goto error;
4917
0
  }
4918
0
  if (list == NULL) {
4919
#ifdef WITH_XSLT_DEBUG_PROCESS
4920
      XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4921
    "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4922
#endif
4923
0
      goto exit;
4924
0
  }
4925
  /*
4926
  *
4927
  * NOTE: Previously a document info (xsltDocument) was
4928
  * created and attached to the Result Tree Fragment.
4929
  * But such a document info is created on demand in
4930
  * xsltKeyFunction() (functions.c), so we need to create
4931
  * it here beforehand.
4932
  * In order to take care of potential keys we need to
4933
  * do some extra work for the case when a Result Tree Fragment
4934
  * is converted into a nodeset (e.g. exslt:node-set()) :
4935
  * We attach a "pseudo-doc" (xsltDocument) to _private.
4936
  * This xsltDocument, together with the keyset, will be freed
4937
  * when the Result Tree Fragment is freed.
4938
  *
4939
  */
4940
#if 0
4941
  if ((ctxt->nbKeys > 0) &&
4942
      (list->nodeNr != 0) &&
4943
      (list->nodeTab[0]->doc != NULL) &&
4944
      XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
4945
  {
4946
      /*
4947
      * NOTE that it's also OK if @effectiveDocInfo will be
4948
      * set to NULL.
4949
      */
4950
      isRTF = 1;
4951
      effectiveDocInfo = list->nodeTab[0]->doc->_private;
4952
  }
4953
#endif
4954
0
    } else {
4955
  /*
4956
   * Build an XPath node set with the children
4957
   */
4958
0
  list = xmlXPathNodeSetCreate(NULL);
4959
0
  if (list == NULL)
4960
0
      goto error;
4961
0
  if (node->type != XML_NAMESPACE_DECL)
4962
0
      cur = node->children;
4963
0
  else
4964
0
      cur = NULL;
4965
0
  while (cur != NULL) {
4966
0
            if (IS_XSLT_REAL_NODE(cur))
4967
0
    xmlXPathNodeSetAddUnique(list, cur);
4968
0
      cur = cur->next;
4969
0
  }
4970
0
    }
4971
4972
#ifdef WITH_XSLT_DEBUG_PROCESS
4973
    if (list != NULL)
4974
    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4975
  "xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
4976
#endif
4977
4978
0
    if ((list == NULL) || (list->nodeNr == 0))
4979
0
  goto exit;
4980
4981
    /*
4982
    * Set the context's node set and size; this is also needed for
4983
    * for xsltDoSortFunction().
4984
    */
4985
0
    ctxt->nodeList = list;
4986
    /*
4987
    * Process xsl:with-param and xsl:sort instructions.
4988
    * (The code became so verbose just to avoid the
4989
    *  xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
4990
    * BUG TODO: We are not using namespaced potentially defined on the
4991
    * xsl:sort or xsl:with-param elements; XPath expression might fail.
4992
    */
4993
0
    if (inst->children) {
4994
0
  xsltStackElemPtr param;
4995
4996
0
  cur = inst->children;
4997
0
  while (cur) {
4998
4999
#ifdef WITH_DEBUGGER
5000
      if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5001
    xslHandleDebugger(cur, node, NULL, ctxt);
5002
#endif
5003
0
      if (ctxt->state == XSLT_STATE_STOPPED)
5004
0
    break;
5005
0
      if (cur->type == XML_TEXT_NODE) {
5006
0
    cur = cur->next;
5007
0
    continue;
5008
0
      }
5009
0
      if (! IS_XSLT_ELEM(cur))
5010
0
    break;
5011
0
      if (IS_XSLT_NAME(cur, "with-param")) {
5012
0
    param = xsltParseStylesheetCallerParam(ctxt, cur);
5013
0
    if (param != NULL) {
5014
0
        param->next = withParams;
5015
0
        withParams = param;
5016
0
    }
5017
0
      }
5018
0
      if (IS_XSLT_NAME(cur, "sort")) {
5019
0
    xsltTemplatePtr oldCurTempRule =
5020
0
        ctxt->currentTemplateRule;
5021
0
    int nbsorts = 0;
5022
0
    xmlNodePtr sorts[XSLT_MAX_SORT];
5023
5024
0
    sorts[nbsorts++] = cur;
5025
0
    cur = cur->next;
5026
5027
0
    while (cur) {
5028
5029
#ifdef WITH_DEBUGGER
5030
        if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5031
      xslHandleDebugger(cur, node, NULL, ctxt);
5032
#endif
5033
0
        if (ctxt->state == XSLT_STATE_STOPPED)
5034
0
      break;
5035
5036
0
        if (cur->type == XML_TEXT_NODE) {
5037
0
      cur = cur->next;
5038
0
      continue;
5039
0
        }
5040
5041
0
        if (! IS_XSLT_ELEM(cur))
5042
0
      break;
5043
0
        if (IS_XSLT_NAME(cur, "with-param")) {
5044
0
      param = xsltParseStylesheetCallerParam(ctxt, cur);
5045
0
      if (param != NULL) {
5046
0
          param->next = withParams;
5047
0
          withParams = param;
5048
0
      }
5049
0
        }
5050
0
        if (IS_XSLT_NAME(cur, "sort")) {
5051
0
      if (nbsorts >= XSLT_MAX_SORT) {
5052
0
          xsltTransformError(ctxt, NULL, cur,
5053
0
        "The number (%d) of xsl:sort instructions exceeds the "
5054
0
        "maximum allowed by this processor's settings.\n",
5055
0
        nbsorts);
5056
0
          ctxt->state = XSLT_STATE_STOPPED;
5057
0
          break;
5058
0
      } else {
5059
0
          sorts[nbsorts++] = cur;
5060
0
      }
5061
0
        }
5062
0
        cur = cur->next;
5063
0
    }
5064
    /*
5065
    * The "current template rule" is cleared for xsl:sort.
5066
    */
5067
0
    ctxt->currentTemplateRule = NULL;
5068
    /*
5069
    * Sort.
5070
    */
5071
0
    xsltDoSortFunction(ctxt, sorts, nbsorts);
5072
0
    ctxt->currentTemplateRule = oldCurTempRule;
5073
0
    break;
5074
0
      }
5075
0
      cur = cur->next;
5076
0
  }
5077
0
    }
5078
0
    xpctxt->contextSize = list->nodeNr;
5079
    /*
5080
    * Apply templates for all selected source nodes.
5081
    */
5082
0
    for (i = 0; i < list->nodeNr; i++) {
5083
0
  cur = list->nodeTab[i];
5084
  /*
5085
  * The node becomes the "current node".
5086
  */
5087
0
  ctxt->node = cur;
5088
  /*
5089
  * An xsl:apply-templates can change the current context doc.
5090
  * OPTIMIZE TODO: Get rid of the need to set the context doc.
5091
  */
5092
0
  if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5093
0
      xpctxt->doc = cur->doc;
5094
5095
0
  xpctxt->proximityPosition = i + 1;
5096
  /*
5097
  * Find and apply a template for this node.
5098
  */
5099
0
  xsltProcessOneNode(ctxt, cur, withParams);
5100
0
    }
5101
5102
0
exit:
5103
0
error:
5104
    /*
5105
    * Free the parameter list.
5106
    */
5107
0
    if (withParams != NULL)
5108
0
  xsltFreeStackElemList(withParams);
5109
0
    if (list != NULL)
5110
0
  xmlXPathFreeNodeSet(list);
5111
    /*
5112
    * Restore context states.
5113
    */
5114
0
    xpctxt->doc = oldXPDoc;
5115
0
    xpctxt->contextSize = oldXPContextSize;
5116
0
    xpctxt->proximityPosition = oldXPProximityPosition;
5117
5118
0
    ctxt->document = oldDocInfo;
5119
0
    ctxt->nodeList = oldList;
5120
0
    ctxt->node = oldContextNode;
5121
0
    ctxt->mode = oldMode;
5122
0
    ctxt->modeURI = oldModeURI;
5123
0
}
5124
5125
5126
/**
5127
 * xsltChoose:
5128
 * @ctxt:  a XSLT process context
5129
 * @contextNode:  the current node in the source tree
5130
 * @inst:  the xsl:choose instruction
5131
 * @comp:  compiled information of the instruction
5132
 *
5133
 * Processes the xsl:choose instruction on the source node.
5134
 */
5135
void
5136
xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5137
     xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
5138
0
{
5139
0
    xmlNodePtr cur;
5140
5141
0
    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5142
0
  return;
5143
5144
    /*
5145
    * TODO: Content model checks should be done only at compilation
5146
    * time.
5147
    */
5148
0
    cur = inst->children;
5149
0
    if (cur == NULL) {
5150
0
  xsltTransformError(ctxt, NULL, inst,
5151
0
      "xsl:choose: The instruction has no content.\n");
5152
0
  return;
5153
0
    }
5154
5155
#ifdef XSLT_REFACTORED
5156
    /*
5157
    * We don't check the content model during transformation.
5158
    */
5159
#else
5160
0
    if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
5161
0
  xsltTransformError(ctxt, NULL, inst,
5162
0
       "xsl:choose: xsl:when expected first\n");
5163
0
  return;
5164
0
    }
5165
0
#endif
5166
5167
0
    {
5168
0
  int testRes = 0, res = 0;
5169
5170
#ifdef XSLT_REFACTORED
5171
  xsltStyleItemWhenPtr wcomp = NULL;
5172
#else
5173
0
  xsltStylePreCompPtr wcomp = NULL;
5174
0
#endif
5175
5176
  /*
5177
  * Process xsl:when ---------------------------------------------------
5178
  */
5179
0
  while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
5180
0
      wcomp = cur->psvi;
5181
5182
0
      if ((wcomp == NULL) || (wcomp->test == NULL) ||
5183
0
    (wcomp->comp == NULL))
5184
0
      {
5185
0
    xsltTransformError(ctxt, NULL, cur,
5186
0
        "Internal error in xsltChoose(): "
5187
0
        "The XSLT 'when' instruction was not compiled.\n");
5188
0
    goto error;
5189
0
      }
5190
5191
5192
#ifdef WITH_DEBUGGER
5193
      if (xslDebugStatus != XSLT_DEBUG_NONE) {
5194
    /*
5195
    * TODO: Isn't comp->templ always NULL for xsl:choose?
5196
    */
5197
    xslHandleDebugger(cur, contextNode, NULL, ctxt);
5198
      }
5199
#endif
5200
#ifdef WITH_XSLT_DEBUG_PROCESS
5201
      XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5202
    "xsltChoose: test %s\n", wcomp->test));
5203
#endif
5204
5205
0
#ifdef XSLT_FAST_IF
5206
0
      res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp);
5207
5208
0
      if (res == -1) {
5209
0
    ctxt->state = XSLT_STATE_STOPPED;
5210
0
    goto error;
5211
0
      }
5212
0
      testRes = (res == 1) ? 1 : 0;
5213
5214
#else /* XSLT_FAST_IF */
5215
5216
      res = xsltPreCompEval(ctxt, cotextNode, wcomp);
5217
5218
      if (res != NULL) {
5219
    if (res->type != XPATH_BOOLEAN)
5220
        res = xmlXPathConvertBoolean(res);
5221
    if (res->type == XPATH_BOOLEAN)
5222
        testRes = res->boolval;
5223
    else {
5224
#ifdef WITH_XSLT_DEBUG_PROCESS
5225
        XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5226
      "xsltChoose: test didn't evaluate to a boolean\n"));
5227
#endif
5228
        goto error;
5229
    }
5230
    xmlXPathFreeObject(res);
5231
    res = NULL;
5232
      } else {
5233
    ctxt->state = XSLT_STATE_STOPPED;
5234
    goto error;
5235
      }
5236
5237
#endif /* else of XSLT_FAST_IF */
5238
5239
#ifdef WITH_XSLT_DEBUG_PROCESS
5240
      XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5241
    "xsltChoose: test evaluate to %d\n", testRes));
5242
#endif
5243
0
      if (testRes)
5244
0
    goto test_is_true;
5245
5246
0
      cur = cur->next;
5247
0
  }
5248
5249
  /*
5250
  * Process xsl:otherwise ----------------------------------------------
5251
  */
5252
0
  if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
5253
5254
#ifdef WITH_DEBUGGER
5255
      if (xslDebugStatus != XSLT_DEBUG_NONE)
5256
    xslHandleDebugger(cur, contextNode, NULL, ctxt);
5257
#endif
5258
5259
#ifdef WITH_XSLT_DEBUG_PROCESS
5260
      XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5261
    "evaluating xsl:otherwise\n"));
5262
#endif
5263
0
      goto test_is_true;
5264
0
  }
5265
0
  goto exit;
5266
5267
0
test_is_true:
5268
5269
0
  goto process_sequence;
5270
0
    }
5271
5272
0
process_sequence:
5273
5274
    /*
5275
    * Instantiate the sequence constructor.
5276
    */
5277
0
    xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
5278
0
  NULL);
5279
5280
0
exit:
5281
0
error:
5282
0
    return;
5283
0
}
5284
5285
/**
5286
 * xsltIf:
5287
 * @ctxt:  a XSLT process context
5288
 * @contextNode:  the current node in the source tree
5289
 * @inst:  the xsl:if instruction
5290
 * @castedComp:  compiled information of the instruction
5291
 *
5292
 * Processes the xsl:if instruction on the source node.
5293
 */
5294
void
5295
xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5296
             xmlNodePtr inst, xsltElemPreCompPtr castedComp)
5297
0
{
5298
0
    int res = 0;
5299
5300
#ifdef XSLT_REFACTORED
5301
    xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
5302
#else
5303
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
5304
0
#endif
5305
5306
0
    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5307
0
  return;
5308
0
    if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
5309
0
  xsltTransformError(ctxt, NULL, inst,
5310
0
      "Internal error in xsltIf(): "
5311
0
      "The XSLT 'if' instruction was not compiled.\n");
5312
0
  return;
5313
0
    }
5314
5315
#ifdef WITH_XSLT_DEBUG_PROCESS
5316
    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5317
   "xsltIf: test %s\n", comp->test));
5318
#endif
5319
5320
0
#ifdef XSLT_FAST_IF
5321
0
    {
5322
0
  xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
5323
5324
0
  res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp);
5325
5326
  /*
5327
  * Cleanup fragments created during evaluation of the
5328
  * "select" expression.
5329
  */
5330
0
  if (oldLocalFragmentTop != ctxt->localRVT)
5331
0
      xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
5332
0
    }
5333
5334
#ifdef WITH_XSLT_DEBUG_PROCESS
5335
    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5336
  "xsltIf: test evaluate to %d\n", res));
5337
#endif
5338
5339
0
    if (res == -1) {
5340
0
  ctxt->state = XSLT_STATE_STOPPED;
5341
0
  goto error;
5342
0
    }
5343
0
    if (res == 1) {
5344
  /*
5345
  * Instantiate the sequence constructor of xsl:if.
5346
  */
5347
0
  xsltApplySequenceConstructor(ctxt,
5348
0
      contextNode, inst->children, NULL);
5349
0
    }
5350
5351
#else /* XSLT_FAST_IF */
5352
    {
5353
  /*
5354
  * OLD CODE:
5355
  */
5356
  xmlXPathObjectPtr xpobj = xsltPreCompEval(ctxt, contextNode, comp);
5357
  if (xpobj != NULL) {
5358
      if (xpobj->type != XPATH_BOOLEAN)
5359
    xpobj = xmlXPathConvertBoolean(xpobj);
5360
      if (xpobj->type == XPATH_BOOLEAN) {
5361
    res = xpobj->boolval;
5362
5363
#ifdef WITH_XSLT_DEBUG_PROCESS
5364
    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5365
        "xsltIf: test evaluate to %d\n", res));
5366
#endif
5367
    if (res) {
5368
        xsltApplySequenceConstructor(ctxt,
5369
      contextNode, inst->children, NULL);
5370
    }
5371
      } else {
5372
5373
#ifdef WITH_XSLT_DEBUG_PROCESS
5374
    XSLT_TRACE(ctxt, XSLT_TRACE_IF,
5375
        xsltGenericDebug(xsltGenericDebugContext,
5376
        "xsltIf: test didn't evaluate to a boolean\n"));
5377
#endif
5378
    ctxt->state = XSLT_STATE_STOPPED;
5379
      }
5380
      xmlXPathFreeObject(xpobj);
5381
  } else {
5382
      ctxt->state = XSLT_STATE_STOPPED;
5383
  }
5384
    }
5385
#endif /* else of XSLT_FAST_IF */
5386
5387
0
error:
5388
0
    return;
5389
0
}
5390
5391
/**
5392
 * xsltForEach:
5393
 * @ctxt:  an XSLT transformation context
5394
 * @contextNode:  the "current node" in the source tree
5395
 * @inst:  the element node of the xsl:for-each instruction
5396
 * @castedComp:  the compiled information of the instruction
5397
 *
5398
 * Process the xslt for-each node on the source node
5399
 */
5400
void
5401
xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5402
      xmlNodePtr inst, xsltElemPreCompPtr castedComp)
5403
0
{
5404
#ifdef XSLT_REFACTORED
5405
    xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
5406
#else
5407
0
    xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
5408
0
#endif
5409
0
    int i;
5410
0
    xmlXPathObjectPtr res = NULL;
5411
0
    xmlNodePtr cur, curInst;
5412
0
    xmlNodeSetPtr list = NULL;
5413
0
    xmlNodeSetPtr oldList;
5414
0
    int oldXPProximityPosition, oldXPContextSize;
5415
0
    xmlNodePtr oldContextNode;
5416
0
    xsltTemplatePtr oldCurTemplRule;
5417
0
    xmlDocPtr oldXPDoc;
5418
0
    xsltDocumentPtr oldDocInfo;
5419
0
    xmlXPathContextPtr xpctxt;
5420
5421
0
    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
5422
0
  xsltGenericError(xsltGenericErrorContext,
5423
0
      "xsltForEach(): Bad arguments.\n");
5424
0
  return;
5425
0
    }
5426
5427
0
    if (comp == NULL) {
5428
0
        xsltTransformError(ctxt, NULL, inst,
5429
0
      "Internal error in xsltForEach(): "
5430
0
      "The XSLT 'for-each' instruction was not compiled.\n");
5431
0
        return;
5432
0
    }
5433
0
    if ((comp->select == NULL) || (comp->comp == NULL)) {
5434
0
  xsltTransformError(ctxt, NULL, inst,
5435
0
      "Internal error in xsltForEach(): "
5436
0
      "The selecting expression of the XSLT 'for-each' "
5437
0
      "instruction was not compiled correctly.\n");
5438
0
  return;
5439
0
    }
5440
0
    xpctxt = ctxt->xpathCtxt;
5441
5442
#ifdef WITH_XSLT_DEBUG_PROCESS
5443
    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5444
   "xsltForEach: select %s\n", comp->select));
5445
#endif
5446
5447
    /*
5448
    * Save context states.
5449
    */
5450
0
    oldDocInfo = ctxt->document;
5451
0
    oldList = ctxt->nodeList;
5452
0
    oldContextNode = ctxt->node;
5453
    /*
5454
    * The "current template rule" is cleared for the instantiation of
5455
    * xsl:for-each.
5456
    */
5457
0
    oldCurTemplRule = ctxt->currentTemplateRule;
5458
0
    ctxt->currentTemplateRule = NULL;
5459
5460
0
    oldXPDoc = xpctxt->doc;
5461
0
    oldXPProximityPosition = xpctxt->proximityPosition;
5462
0
    oldXPContextSize = xpctxt->contextSize;
5463
5464
    /*
5465
    * Evaluate the 'select' expression.
5466
    */
5467
0
    res = xsltPreCompEval(ctxt, contextNode, comp);
5468
5469
0
    if (res != NULL) {
5470
0
  if (res->type == XPATH_NODESET)
5471
0
      list = res->nodesetval;
5472
0
  else {
5473
0
      xsltTransformError(ctxt, NULL, inst,
5474
0
    "The 'select' expression does not evaluate to a node set.\n");
5475
5476
#ifdef WITH_XSLT_DEBUG_PROCESS
5477
      XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5478
    "xsltForEach: select didn't evaluate to a node list\n"));
5479
#endif
5480
0
      goto error;
5481
0
  }
5482
0
    } else {
5483
0
  xsltTransformError(ctxt, NULL, inst,
5484
0
      "Failed to evaluate the 'select' expression.\n");
5485
0
  ctxt->state = XSLT_STATE_STOPPED;
5486
0
  goto error;
5487
0
    }
5488
5489
0
    if ((list == NULL) || (list->nodeNr <= 0))
5490
0
  goto exit;
5491
5492
#ifdef WITH_XSLT_DEBUG_PROCESS
5493
    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5494
  "xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
5495
#endif
5496
5497
    /*
5498
    * Set the list; this has to be done already here for xsltDoSortFunction().
5499
    */
5500
0
    ctxt->nodeList = list;
5501
    /*
5502
    * Handle xsl:sort instructions and skip them for further processing.
5503
    * BUG TODO: We are not using namespaced potentially defined on the
5504
    * xsl:sort element; XPath expression might fail.
5505
    */
5506
0
    curInst = inst->children;
5507
0
    if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5508
0
  int nbsorts = 0;
5509
0
  xmlNodePtr sorts[XSLT_MAX_SORT];
5510
5511
0
  sorts[nbsorts++] = curInst;
5512
5513
#ifdef WITH_DEBUGGER
5514
  if (xslDebugStatus != XSLT_DEBUG_NONE)
5515
      xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5516
#endif
5517
5518
0
  curInst = curInst->next;
5519
0
  while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5520
0
      if (nbsorts >= XSLT_MAX_SORT) {
5521
0
    xsltTransformError(ctxt, NULL, curInst,
5522
0
        "The number of xsl:sort instructions exceeds the "
5523
0
        "maximum (%d) allowed by this processor.\n",
5524
0
        XSLT_MAX_SORT);
5525
0
    goto error;
5526
0
      } else {
5527
0
    sorts[nbsorts++] = curInst;
5528
0
      }
5529
5530
#ifdef WITH_DEBUGGER
5531
      if (xslDebugStatus != XSLT_DEBUG_NONE)
5532
    xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5533
#endif
5534
0
      curInst = curInst->next;
5535
0
  }
5536
0
  xsltDoSortFunction(ctxt, sorts, nbsorts);
5537
0
    }
5538
0
    xpctxt->contextSize = list->nodeNr;
5539
    /*
5540
    * Instantiate the sequence constructor for each selected node.
5541
    */
5542
0
    for (i = 0; i < list->nodeNr; i++) {
5543
0
  cur = list->nodeTab[i];
5544
  /*
5545
  * The selected node becomes the "current node".
5546
  */
5547
0
  ctxt->node = cur;
5548
  /*
5549
  * An xsl:for-each can change the current context doc.
5550
  * OPTIMIZE TODO: Get rid of the need to set the context doc.
5551
  */
5552
0
  if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5553
0
      xpctxt->doc = cur->doc;
5554
5555
0
  xpctxt->proximityPosition = i + 1;
5556
5557
0
  xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
5558
0
    }
5559
5560
0
exit:
5561
0
error:
5562
0
    if (res != NULL)
5563
0
  xmlXPathFreeObject(res);
5564
    /*
5565
    * Restore old states.
5566
    */
5567
0
    ctxt->document = oldDocInfo;
5568
0
    ctxt->nodeList = oldList;
5569
0
    ctxt->node = oldContextNode;
5570
0
    ctxt->currentTemplateRule = oldCurTemplRule;
5571
5572
0
    xpctxt->doc = oldXPDoc;
5573
0
    xpctxt->contextSize = oldXPContextSize;
5574
0
    xpctxt->proximityPosition = oldXPProximityPosition;
5575
0
}
5576
5577
/************************************************************************
5578
 *                  *
5579
 *      Generic interface       *
5580
 *                  *
5581
 ************************************************************************/
5582
5583
#ifdef XSLT_GENERATE_HTML_DOCTYPE
5584
typedef struct xsltHTMLVersion {
5585
    const char *version;
5586
    const char *public;
5587
    const char *system;
5588
} xsltHTMLVersion;
5589
5590
static xsltHTMLVersion xsltHTMLVersions[] = {
5591
    { "5", NULL, "about:legacy-compat" },
5592
    { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5593
      "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5594
    { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5595
      "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5596
    { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5597
      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5598
    { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5599
      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5600
    { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5601
      "http://www.w3.org/TR/html4/strict.dtd"},
5602
    { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5603
      "http://www.w3.org/TR/html4/loose.dtd"},
5604
    { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5605
      "http://www.w3.org/TR/html4/frameset.dtd"},
5606
    { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5607
      "http://www.w3.org/TR/html4/loose.dtd"},
5608
    { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
5609
};
5610
5611
/**
5612
 * xsltGetHTMLIDs:
5613
 * @version:  the version string
5614
 * @publicID:  used to return the public ID
5615
 * @systemID:  used to return the system ID
5616
 *
5617
 * Returns -1 if not found, 0 otherwise and the system and public
5618
 *         Identifier for this given verion of HTML
5619
 */
5620
static int
5621
xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
5622
0
              const xmlChar **systemID) {
5623
0
    unsigned int i;
5624
0
    if (version == NULL)
5625
0
  return(-1);
5626
0
    for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
5627
0
   i++) {
5628
0
  if (!xmlStrcasecmp(version,
5629
0
               (const xmlChar *) xsltHTMLVersions[i].version)) {
5630
0
      if (publicID != NULL)
5631
0
    *publicID = (const xmlChar *) xsltHTMLVersions[i].public;
5632
0
      if (systemID != NULL)
5633
0
    *systemID = (const xmlChar *) xsltHTMLVersions[i].system;
5634
0
      return(0);
5635
0
  }
5636
0
    }
5637
0
    return(-1);
5638
0
}
5639
#endif
5640
5641
/**
5642
 * xsltApplyStripSpaces:
5643
 * @ctxt:  a XSLT process context
5644
 * @node:  the root of the XML tree
5645
 *
5646
 * Strip the unwanted ignorable spaces from the input tree
5647
 */
5648
void
5649
0
xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
5650
0
    xmlNodePtr current;
5651
#ifdef WITH_XSLT_DEBUG_PROCESS
5652
    int nb = 0;
5653
#endif
5654
5655
5656
0
    current = node;
5657
0
    while (current != NULL) {
5658
  /*
5659
   * Cleanup children empty nodes if asked for
5660
   */
5661
0
  if ((IS_XSLT_REAL_NODE(current)) &&
5662
0
      (current->children != NULL) &&
5663
0
      (xsltFindElemSpaceHandling(ctxt, current))) {
5664
0
      xmlNodePtr delete = NULL, cur = current->children;
5665
5666
0
      while (cur != NULL) {
5667
0
    if (IS_BLANK_NODE(cur))
5668
0
        delete = cur;
5669
5670
0
    cur = cur->next;
5671
0
    if (delete != NULL) {
5672
0
        xmlUnlinkNode(delete);
5673
0
        xmlFreeNode(delete);
5674
0
        delete = NULL;
5675
#ifdef WITH_XSLT_DEBUG_PROCESS
5676
        nb++;
5677
#endif
5678
0
    }
5679
0
      }
5680
0
  }
5681
5682
  /*
5683
   * Skip to next node in document order.
5684
   */
5685
0
  if (node->type == XML_ENTITY_REF_NODE) {
5686
      /* process deep in entities */
5687
0
      xsltApplyStripSpaces(ctxt, node->children);
5688
0
  }
5689
0
  if ((current->children != NULL) &&
5690
0
            (current->type != XML_ENTITY_REF_NODE)) {
5691
0
      current = current->children;
5692
0
  } else if (current->next != NULL) {
5693
0
      current = current->next;
5694
0
  } else {
5695
0
      do {
5696
0
    current = current->parent;
5697
0
    if (current == NULL)
5698
0
        break;
5699
0
    if (current == node)
5700
0
        goto done;
5701
0
    if (current->next != NULL) {
5702
0
        current = current->next;
5703
0
        break;
5704
0
    }
5705
0
      } while (current != NULL);
5706
0
  }
5707
0
    }
5708
5709
0
done:
5710
#ifdef WITH_XSLT_DEBUG_PROCESS
5711
    XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,
5712
       "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
5713
#endif
5714
0
    return;
5715
0
}
5716
5717
static int
5718
xsltCountKeys(xsltTransformContextPtr ctxt)
5719
0
{
5720
0
    xsltStylesheetPtr style;
5721
0
    xsltKeyDefPtr keyd;
5722
5723
0
    if (ctxt == NULL)
5724
0
  return(-1);
5725
5726
    /*
5727
    * Do we have those nastly templates with a key() in the match pattern?
5728
    */
5729
0
    ctxt->hasTemplKeyPatterns = 0;
5730
0
    style = ctxt->style;
5731
0
    while (style != NULL) {
5732
0
  if (style->keyMatch != NULL) {
5733
0
      ctxt->hasTemplKeyPatterns = 1;
5734
0
      break;
5735
0
  }
5736
0
  style = xsltNextImport(style);
5737
0
    }
5738
    /*
5739
    * Count number of key declarations.
5740
    */
5741
0
    ctxt->nbKeys = 0;
5742
0
    style = ctxt->style;
5743
0
    while (style != NULL) {
5744
0
  keyd = style->keys;
5745
0
  while (keyd) {
5746
0
      ctxt->nbKeys++;
5747
0
      keyd = keyd->next;
5748
0
  }
5749
0
  style = xsltNextImport(style);
5750
0
    }
5751
0
    return(ctxt->nbKeys);
5752
0
}
5753
5754
/**
5755
 * xsltCleanupSourceDoc:
5756
 * @doc:  Document
5757
 *
5758
 * Resets source node flags and ids stored in 'psvi' member.
5759
 */
5760
static void
5761
0
xsltCleanupSourceDoc(xmlDocPtr doc) {
5762
0
    xmlNodePtr cur = (xmlNodePtr) doc;
5763
0
    void **psviPtr;
5764
5765
0
    while (1) {
5766
0
        xsltClearSourceNodeFlags(cur, XSLT_SOURCE_NODE_MASK);
5767
0
        psviPtr = xsltGetPSVIPtr(cur);
5768
0
        if (psviPtr)
5769
0
            *psviPtr = NULL;
5770
5771
0
        if (cur->type == XML_ELEMENT_NODE) {
5772
0
            xmlAttrPtr prop = cur->properties;
5773
5774
0
            while (prop) {
5775
0
                prop->atype &= ~(XSLT_SOURCE_NODE_MASK << 27);
5776
0
                prop->psvi = NULL;
5777
0
                prop = prop->next;
5778
0
            }
5779
0
        }
5780
5781
0
        if (cur->children != NULL && cur->type != XML_ENTITY_REF_NODE) {
5782
0
            cur = cur->children;
5783
0
        } else {
5784
0
            while (cur->next == NULL) {
5785
0
                cur = cur->parent;
5786
0
                if (cur == (xmlNodePtr) doc)
5787
0
                    return;
5788
0
            }
5789
5790
0
            cur = cur->next;
5791
0
        }
5792
0
    }
5793
0
}
5794
5795
/**
5796
 * xsltApplyStylesheetInternal:
5797
 * @style:  a parsed XSLT stylesheet
5798
 * @doc:  a parsed XML document
5799
 * @params:  a NULL terminated array of parameters names/values tuples
5800
 * @output:  the targetted output
5801
 * @profile:  profile FILE * output or NULL
5802
 * @user:  user provided parameter
5803
 *
5804
 * Apply the stylesheet to the document
5805
 * NOTE: This may lead to a non-wellformed output XML wise !
5806
 *
5807
 * Returns the result document or NULL in case of error
5808
 */
5809
static xmlDocPtr
5810
xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
5811
                            const char **params, const char *output,
5812
                            FILE * profile, xsltTransformContextPtr userCtxt)
5813
0
{
5814
0
    xmlDocPtr res = NULL;
5815
0
    xsltTransformContextPtr ctxt = NULL;
5816
0
    xmlNodePtr root, node;
5817
0
    const xmlChar *method;
5818
0
    const xmlChar *doctypePublic;
5819
0
    const xmlChar *doctypeSystem;
5820
0
    const xmlChar *version;
5821
0
    const xmlChar *encoding;
5822
0
    xsltStackElemPtr variables;
5823
0
    xsltStackElemPtr vptr;
5824
5825
0
    xsltInitGlobals();
5826
5827
0
    if ((style == NULL) || (doc == NULL))
5828
0
        return (NULL);
5829
5830
0
    if (style->internalized == 0) {
5831
#ifdef WITH_XSLT_DEBUG
5832
  xsltGenericDebug(xsltGenericDebugContext,
5833
       "Stylesheet was not fully internalized !\n");
5834
#endif
5835
0
    }
5836
0
    if (doc->intSubset != NULL) {
5837
  /*
5838
   * Avoid hitting the DTD when scanning nodes
5839
   * but keep it linked as doc->intSubset
5840
   */
5841
0
  xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
5842
0
  if (cur->next != NULL)
5843
0
      cur->next->prev = cur->prev;
5844
0
  if (cur->prev != NULL)
5845
0
      cur->prev->next = cur->next;
5846
0
  if (doc->children == cur)
5847
0
      doc->children = cur->next;
5848
0
  if (doc->last == cur)
5849
0
      doc->last = cur->prev;
5850
0
  cur->prev = cur->next = NULL;
5851
0
    }
5852
5853
    /*
5854
     * Check for XPath document order availability
5855
     */
5856
0
    root = xmlDocGetRootElement(doc);
5857
0
    if (root != NULL) {
5858
0
  if (((ptrdiff_t) root->content >= 0) &&
5859
0
            (xslDebugStatus == XSLT_DEBUG_NONE))
5860
0
      xmlXPathOrderDocElems(doc);
5861
0
    }
5862
5863
0
    if (userCtxt != NULL)
5864
0
  ctxt = userCtxt;
5865
0
    else
5866
0
  ctxt = xsltNewTransformContext(style, doc);
5867
5868
0
    if (ctxt == NULL)
5869
0
        return (NULL);
5870
5871
0
    ctxt->initialContextDoc = doc;
5872
0
    ctxt->initialContextNode = (xmlNodePtr) doc;
5873
5874
0
    if (profile != NULL) {
5875
#ifdef WITH_PROFILER
5876
        ctxt->profile = 1;
5877
#else
5878
0
        xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5879
0
                "xsltApplyStylesheetInternal: "
5880
0
                "libxslt compiled without profiler\n");
5881
0
        goto error;
5882
0
#endif
5883
0
    }
5884
5885
0
    if (output != NULL)
5886
0
        ctxt->outputFile = output;
5887
0
    else
5888
0
        ctxt->outputFile = NULL;
5889
5890
    /*
5891
     * internalize the modes if needed
5892
     */
5893
0
    if (ctxt->dict != NULL) {
5894
0
        if (ctxt->mode != NULL)
5895
0
      ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
5896
0
        if (ctxt->modeURI != NULL)
5897
0
      ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
5898
0
    }
5899
5900
0
    XSLT_GET_IMPORT_PTR(method, style, method)
5901
0
    XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
5902
0
    XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
5903
0
    XSLT_GET_IMPORT_PTR(version, style, version)
5904
0
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
5905
5906
0
    if ((method != NULL) &&
5907
0
  (!xmlStrEqual(method, (const xmlChar *) "xml")))
5908
0
    {
5909
0
        if (xmlStrEqual(method, (const xmlChar *) "html")) {
5910
0
            ctxt->type = XSLT_OUTPUT_HTML;
5911
0
            if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
5912
0
                res = htmlNewDoc(doctypeSystem, doctypePublic);
5913
0
      } else {
5914
0
                if (version == NULL) {
5915
0
        xmlDtdPtr dtd;
5916
5917
0
        res = htmlNewDoc(NULL, NULL);
5918
        /*
5919
        * Make sure no DTD node is generated in this case
5920
        */
5921
0
        if (res != NULL) {
5922
0
      dtd = xmlGetIntSubset(res);
5923
0
      if (dtd != NULL) {
5924
0
          xmlUnlinkNode((xmlNodePtr) dtd);
5925
0
          xmlFreeDtd(dtd);
5926
0
      }
5927
0
      res->intSubset = NULL;
5928
0
      res->extSubset = NULL;
5929
0
        }
5930
0
    } else {
5931
5932
0
#ifdef XSLT_GENERATE_HTML_DOCTYPE
5933
0
        xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
5934
0
#endif
5935
0
        res = htmlNewDoc(doctypeSystem, doctypePublic);
5936
0
    }
5937
0
            }
5938
0
            if (res == NULL)
5939
0
                goto error;
5940
0
      res->dict = ctxt->dict;
5941
0
      xmlDictReference(res->dict);
5942
5943
#ifdef WITH_XSLT_DEBUG
5944
      xsltGenericDebug(xsltGenericDebugContext,
5945
    "reusing transformation dict for output\n");
5946
#endif
5947
0
        } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
5948
0
      xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5949
0
    "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
5950
0
            ctxt->type = XSLT_OUTPUT_HTML;
5951
0
            res = htmlNewDoc(doctypeSystem, doctypePublic);
5952
0
            if (res == NULL)
5953
0
                goto error;
5954
0
      res->dict = ctxt->dict;
5955
0
      xmlDictReference(res->dict);
5956
5957
#ifdef WITH_XSLT_DEBUG
5958
      xsltGenericDebug(xsltGenericDebugContext,
5959
    "reusing transformation dict for output\n");
5960
#endif
5961
0
        } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
5962
0
            ctxt->type = XSLT_OUTPUT_TEXT;
5963
0
            res = xmlNewDoc(style->version);
5964
0
            if (res == NULL)
5965
0
                goto error;
5966
0
      res->dict = ctxt->dict;
5967
0
      xmlDictReference(res->dict);
5968
5969
#ifdef WITH_XSLT_DEBUG
5970
      xsltGenericDebug(xsltGenericDebugContext,
5971
    "reusing transformation dict for output\n");
5972
#endif
5973
0
        } else {
5974
0
      xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5975
0
    "xsltApplyStylesheetInternal: unsupported method (%s)\n",
5976
0
    method);
5977
0
            goto error;
5978
0
        }
5979
0
    } else {
5980
0
        ctxt->type = XSLT_OUTPUT_XML;
5981
0
        res = xmlNewDoc(style->version);
5982
0
        if (res == NULL)
5983
0
            goto error;
5984
0
  res->dict = ctxt->dict;
5985
0
  xmlDictReference(ctxt->dict);
5986
#ifdef WITH_XSLT_DEBUG
5987
  xsltGenericDebug(xsltGenericDebugContext,
5988
       "reusing transformation dict for output\n");
5989
#endif
5990
0
    }
5991
0
    res->charset = XML_CHAR_ENCODING_UTF8;
5992
0
    if (encoding != NULL)
5993
0
        res->encoding = xmlStrdup(encoding);
5994
0
    variables = style->variables;
5995
5996
0
    ctxt->node = (xmlNodePtr) doc;
5997
0
    ctxt->output = res;
5998
5999
0
    ctxt->xpathCtxt->contextSize = 1;
6000
0
    ctxt->xpathCtxt->proximityPosition = 1;
6001
0
    ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
6002
6003
    /*
6004
     * Start the evaluation, evaluate the params, the stylesheets globals
6005
     * and start by processing the top node.
6006
     */
6007
0
    if (xsltNeedElemSpaceHandling(ctxt))
6008
0
  xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
6009
    /*
6010
    * Evaluate global params and user-provided params.
6011
    */
6012
0
    if (ctxt->globalVars == NULL)
6013
0
  ctxt->globalVars = xmlHashCreate(20);
6014
0
    if (params != NULL) {
6015
0
        xsltEvalUserParams(ctxt, params);
6016
0
    }
6017
6018
    /* need to be called before evaluating global variables */
6019
0
    xsltCountKeys(ctxt);
6020
6021
0
    xsltEvalGlobalVariables(ctxt);
6022
6023
    /* Clean up any unused RVTs. */
6024
0
    xsltReleaseLocalRVTs(ctxt, NULL);
6025
6026
0
    ctxt->insert = (xmlNodePtr) res;
6027
0
    ctxt->varsBase = ctxt->varsNr - 1;
6028
6029
    /*
6030
    * Start processing the source tree -----------------------------------
6031
    */
6032
0
    xsltProcessOneNode(ctxt, ctxt->node, NULL);
6033
    /*
6034
    * Remove all remaining vars from the stack.
6035
    */
6036
0
    xsltLocalVariablePop(ctxt, 0, -2);
6037
0
    xsltShutdownCtxtExts(ctxt);
6038
6039
0
    xsltCleanupTemplates(style); /* TODO: <- style should be read only */
6040
6041
    /*
6042
     * Now cleanup our variables so stylesheet can be re-used
6043
     *
6044
     * TODO: this is not needed anymore global variables are copied
6045
     *       and not evaluated directly anymore, keep this as a check
6046
     */
6047
0
    if (style->variables != variables) {
6048
0
        vptr = style->variables;
6049
0
        while (vptr->next != variables)
6050
0
            vptr = vptr->next;
6051
0
        vptr->next = NULL;
6052
0
        xsltFreeStackElemList(style->variables);
6053
0
        style->variables = variables;
6054
0
    }
6055
0
    vptr = style->variables;
6056
0
    while (vptr != NULL) {
6057
0
        if (vptr->computed) {
6058
0
            if (vptr->value != NULL) {
6059
0
                xmlXPathFreeObject(vptr->value);
6060
0
                vptr->value = NULL;
6061
0
                vptr->computed = 0;
6062
0
            }
6063
0
        }
6064
0
        vptr = vptr->next;
6065
0
    }
6066
#if 0
6067
    /*
6068
     * code disabled by wmb; awaiting kb's review
6069
     * problem is that global variable(s) may contain xpath objects
6070
     * from doc associated with RVT, so can't be freed at this point.
6071
     * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6072
     * I assume this shouldn't be required at this point.
6073
     */
6074
    /*
6075
    * Free all remaining tree fragments.
6076
    */
6077
    xsltFreeRVTs(ctxt);
6078
#endif
6079
    /*
6080
     * Do some post processing work depending on the generated output
6081
     */
6082
0
    root = xmlDocGetRootElement(res);
6083
0
    if (root != NULL) {
6084
0
        const xmlChar *doctype = NULL;
6085
6086
0
        if ((root->ns != NULL) && (root->ns->prefix != NULL))
6087
0
      doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
6088
0
  if (doctype == NULL)
6089
0
      doctype = root->name;
6090
6091
        /*
6092
         * Apply the default selection of the method
6093
         */
6094
0
        if ((method == NULL) &&
6095
0
            (root->ns == NULL) &&
6096
0
            (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
6097
0
            xmlNodePtr tmp;
6098
6099
0
            tmp = res->children;
6100
0
            while ((tmp != NULL) && (tmp != root)) {
6101
0
                if (tmp->type == XML_ELEMENT_NODE)
6102
0
                    break;
6103
0
                if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
6104
0
                    break;
6105
0
    tmp = tmp->next;
6106
0
            }
6107
0
            if (tmp == root) {
6108
0
                ctxt->type = XSLT_OUTPUT_HTML;
6109
    /*
6110
    * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6111
    *  transformation on the doc, but functions like
6112
    */
6113
0
                res->type = XML_HTML_DOCUMENT_NODE;
6114
0
                if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6115
0
                    res->intSubset = xmlCreateIntSubset(res, doctype,
6116
0
                                                        doctypePublic,
6117
0
                                                        doctypeSystem);
6118
0
#ifdef XSLT_GENERATE_HTML_DOCTYPE
6119
0
    } else if (version != NULL) {
6120
0
                    xsltGetHTMLIDs(version, &doctypePublic,
6121
0
                                   &doctypeSystem);
6122
0
                    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
6123
0
                        res->intSubset =
6124
0
                            xmlCreateIntSubset(res, doctype,
6125
0
                                               doctypePublic,
6126
0
                                               doctypeSystem);
6127
0
#endif
6128
0
                }
6129
0
            }
6130
6131
0
        }
6132
0
        if (ctxt->type == XSLT_OUTPUT_XML) {
6133
0
            XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
6134
0
            XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
6135
0
            if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6136
0
          xmlNodePtr last;
6137
    /* Need a small "hack" here to assure DTD comes before
6138
       possible comment nodes */
6139
0
    node = res->children;
6140
0
    last = res->last;
6141
0
    res->children = NULL;
6142
0
    res->last = NULL;
6143
0
                res->intSubset = xmlCreateIntSubset(res, doctype,
6144
0
                                                    doctypePublic,
6145
0
                                                    doctypeSystem);
6146
0
    if (res->children != NULL) {
6147
0
        res->children->next = node;
6148
0
        node->prev = res->children;
6149
0
        res->last = last;
6150
0
    } else {
6151
0
        res->children = node;
6152
0
        res->last = last;
6153
0
    }
6154
0
      }
6155
0
        }
6156
0
    }
6157
0
    xmlXPathFreeNodeSet(ctxt->nodeList);
6158
6159
#ifdef WITH_PROFILER
6160
    if (profile != NULL) {
6161
        xsltSaveProfiling(ctxt, profile);
6162
    }
6163
#endif
6164
6165
    /*
6166
     * Be pedantic.
6167
     */
6168
0
    if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) {
6169
0
  xmlFreeDoc(res);
6170
0
  res = NULL;
6171
0
    }
6172
0
    if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
6173
0
  int ret;
6174
6175
0
  ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
6176
0
  if (ret == 0) {
6177
0
      xsltTransformError(ctxt, NULL, NULL,
6178
0
         "xsltApplyStylesheet: forbidden to save to %s\n",
6179
0
             output);
6180
0
  } else if (ret < 0) {
6181
0
      xsltTransformError(ctxt, NULL, NULL,
6182
0
         "xsltApplyStylesheet: saving to %s may not be possible\n",
6183
0
             output);
6184
0
  }
6185
0
    }
6186
6187
#ifdef XSLT_DEBUG_PROFILE_CACHE
6188
    printf("# Cache:\n");
6189
    printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6190
    printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
6191
#endif
6192
6193
0
    if (ctxt->sourceDocDirty)
6194
0
        xsltCleanupSourceDoc(doc);
6195
6196
0
    if ((ctxt != NULL) && (userCtxt == NULL))
6197
0
  xsltFreeTransformContext(ctxt);
6198
6199
0
    return (res);
6200
6201
0
error:
6202
0
    if (res != NULL)
6203
0
        xmlFreeDoc(res);
6204
6205
#ifdef XSLT_DEBUG_PROFILE_CACHE
6206
    printf("# Cache:\n");
6207
    printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6208
    printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
6209
#endif
6210
6211
0
    if ((ctxt != NULL) && (userCtxt == NULL))
6212
0
        xsltFreeTransformContext(ctxt);
6213
0
    return (NULL);
6214
0
}
6215
6216
/**
6217
 * xsltApplyStylesheet:
6218
 * @style:  a parsed XSLT stylesheet
6219
 * @doc:  a parsed XML document
6220
 * @params:  a NULL terminated arry of parameters names/values tuples
6221
 *
6222
 * Apply the stylesheet to the document
6223
 * NOTE: This may lead to a non-wellformed output XML wise !
6224
 *
6225
 * Returns the result document or NULL in case of error
6226
 */
6227
xmlDocPtr
6228
xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6229
                    const char **params)
6230
0
{
6231
0
    return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
6232
0
}
6233
6234
/**
6235
 * xsltProfileStylesheet:
6236
 * @style:  a parsed XSLT stylesheet
6237
 * @doc:  a parsed XML document
6238
 * @params:  a NULL terminated arry of parameters names/values tuples
6239
 * @output:  a FILE * for the profiling output
6240
 *
6241
 * Apply the stylesheet to the document and dump the profiling to
6242
 * the given output.
6243
 *
6244
 * Returns the result document or NULL in case of error
6245
 */
6246
xmlDocPtr
6247
xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6248
                      const char **params, FILE * output)
6249
0
{
6250
0
    xmlDocPtr res;
6251
6252
0
    res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
6253
0
    return (res);
6254
0
}
6255
6256
/**
6257
 * xsltApplyStylesheetUser:
6258
 * @style:  a parsed XSLT stylesheet
6259
 * @doc:  a parsed XML document
6260
 * @params:  a NULL terminated array of parameters names/values tuples
6261
 * @output:  the targetted output
6262
 * @profile:  profile FILE * output or NULL
6263
 * @userCtxt:  user provided transform context
6264
 *
6265
 * Apply the stylesheet to the document and allow the user to provide
6266
 * its own transformation context.
6267
 *
6268
 * Returns the result document or NULL in case of error
6269
 */
6270
xmlDocPtr
6271
xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6272
                            const char **params, const char *output,
6273
                            FILE * profile, xsltTransformContextPtr userCtxt)
6274
0
{
6275
0
    xmlDocPtr res;
6276
6277
0
    res = xsltApplyStylesheetInternal(style, doc, params, output,
6278
0
                                profile, userCtxt);
6279
0
    return (res);
6280
0
}
6281
6282
/**
6283
 * xsltRunStylesheetUser:
6284
 * @style:  a parsed XSLT stylesheet
6285
 * @doc:  a parsed XML document
6286
 * @params:  a NULL terminated array of parameters names/values tuples
6287
 * @output:  the URL/filename ot the generated resource if available
6288
 * @SAX:  a SAX handler for progressive callback output (not implemented yet)
6289
 * @IObuf:  an output buffer for progressive output (not implemented yet)
6290
 * @profile:  profile FILE * output or NULL
6291
 * @userCtxt:  user provided transform context
6292
 *
6293
 * Apply the stylesheet to the document and generate the output according
6294
 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6295
 *
6296
 * NOTE: This may lead to a non-wellformed output XML wise !
6297
 * NOTE: This may also result in multiple files being generated
6298
 * NOTE: using IObuf, the result encoding used will be the one used for
6299
 *       creating the output buffer, use the following macro to read it
6300
 *       from the stylesheet
6301
 *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6302
 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6303
 *       since the interface uses only UTF8
6304
 *
6305
 * Returns the number of by written to the main resource or -1 in case of
6306
 *         error.
6307
 */
6308
int
6309
xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6310
                  const char **params, const char *output,
6311
                  xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
6312
      FILE * profile, xsltTransformContextPtr userCtxt)
6313
0
{
6314
0
    xmlDocPtr tmp;
6315
0
    int ret;
6316
6317
0
    if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
6318
0
        return (-1);
6319
0
    if ((SAX != NULL) && (IObuf != NULL))
6320
0
        return (-1);
6321
6322
    /* unsupported yet */
6323
0
    if (SAX != NULL) {
6324
        XSLT_TODO   /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6325
0
  return (-1);
6326
0
    }
6327
6328
0
    tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
6329
0
                                userCtxt);
6330
0
    if (tmp == NULL) {
6331
0
  xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
6332
0
                         "xsltRunStylesheet : run failed\n");
6333
0
        return (-1);
6334
0
    }
6335
0
    if (IObuf != NULL) {
6336
        /* TODO: incomplete, IObuf output not progressive */
6337
0
        ret = xsltSaveResultTo(IObuf, tmp, style);
6338
0
    } else {
6339
0
        ret = xsltSaveResultToFilename(output, tmp, style, 0);
6340
0
    }
6341
0
    xmlFreeDoc(tmp);
6342
0
    return (ret);
6343
0
}
6344
6345
/**
6346
 * xsltRunStylesheet:
6347
 * @style:  a parsed XSLT stylesheet
6348
 * @doc:  a parsed XML document
6349
 * @params:  a NULL terminated array of parameters names/values tuples
6350
 * @output:  the URL/filename ot the generated resource if available
6351
 * @SAX:  a SAX handler for progressive callback output (not implemented yet)
6352
 * @IObuf:  an output buffer for progressive output (not implemented yet)
6353
 *
6354
 * Apply the stylesheet to the document and generate the output according
6355
 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6356
 *
6357
 * NOTE: This may lead to a non-wellformed output XML wise !
6358
 * NOTE: This may also result in multiple files being generated
6359
 * NOTE: using IObuf, the result encoding used will be the one used for
6360
 *       creating the output buffer, use the following macro to read it
6361
 *       from the stylesheet
6362
 *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6363
 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6364
 *       since the interface uses only UTF8
6365
 *
6366
 * Returns the number of bytes written to the main resource or -1 in case of
6367
 *         error.
6368
 */
6369
int
6370
xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6371
                  const char **params, const char *output,
6372
                  xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
6373
0
{
6374
0
    return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
6375
0
                     NULL, NULL));
6376
0
}
6377
6378
static void
6379
xsltMessageWrapper(xsltTransformContextPtr ctxt, xmlNodePtr node,
6380
0
                   xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
6381
0
    xsltMessage(ctxt, node, inst);
6382
0
}
6383
6384
/**
6385
 * xsltRegisterAllElement:
6386
 * @ctxt:  the XPath context
6387
 *
6388
 * Registers all default XSLT elements in this context
6389
 */
6390
void
6391
xsltRegisterAllElement(xsltTransformContextPtr ctxt)
6392
3.69k
{
6393
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
6394
3.69k
                           XSLT_NAMESPACE,
6395
3.69k
         xsltApplyTemplates);
6396
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
6397
3.69k
                           XSLT_NAMESPACE,
6398
3.69k
         xsltApplyImports);
6399
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
6400
3.69k
                           XSLT_NAMESPACE,
6401
3.69k
         xsltCallTemplate);
6402
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
6403
3.69k
                           XSLT_NAMESPACE,
6404
3.69k
         xsltElement);
6405
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
6406
3.69k
                           XSLT_NAMESPACE,
6407
3.69k
         xsltAttribute);
6408
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
6409
3.69k
                           XSLT_NAMESPACE,
6410
3.69k
         xsltText);
6411
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
6412
3.69k
                           XSLT_NAMESPACE,
6413
3.69k
         xsltProcessingInstruction);
6414
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
6415
3.69k
                           XSLT_NAMESPACE,
6416
3.69k
         xsltComment);
6417
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
6418
3.69k
                           XSLT_NAMESPACE,
6419
3.69k
         xsltCopy);
6420
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
6421
3.69k
                           XSLT_NAMESPACE,
6422
3.69k
         xsltValueOf);
6423
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
6424
3.69k
                           XSLT_NAMESPACE,
6425
3.69k
         xsltNumber);
6426
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
6427
3.69k
                           XSLT_NAMESPACE,
6428
3.69k
         xsltForEach);
6429
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
6430
3.69k
                           XSLT_NAMESPACE,
6431
3.69k
         xsltIf);
6432
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
6433
3.69k
                           XSLT_NAMESPACE,
6434
3.69k
         xsltChoose);
6435
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
6436
3.69k
                           XSLT_NAMESPACE,
6437
3.69k
         xsltSort);
6438
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
6439
3.69k
                           XSLT_NAMESPACE,
6440
3.69k
         xsltCopyOf);
6441
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
6442
3.69k
                           XSLT_NAMESPACE,
6443
3.69k
         xsltMessageWrapper);
6444
6445
    /*
6446
     * Those don't have callable entry points but are registered anyway
6447
     */
6448
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
6449
3.69k
                           XSLT_NAMESPACE,
6450
3.69k
         xsltDebug);
6451
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
6452
3.69k
                           XSLT_NAMESPACE,
6453
3.69k
         xsltDebug);
6454
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
6455
3.69k
                           XSLT_NAMESPACE,
6456
3.69k
         xsltDebug);
6457
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
6458
3.69k
                           XSLT_NAMESPACE,
6459
3.69k
         xsltDebug);
6460
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
6461
3.69k
                           XSLT_NAMESPACE,
6462
3.69k
         xsltDebug);
6463
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
6464
3.69k
                           XSLT_NAMESPACE,
6465
3.69k
         xsltDebug);
6466
3.69k
    xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
6467
3.69k
                           XSLT_NAMESPACE,
6468
3.69k
         xsltDebug);
6469
6470
3.69k
}