Coverage Report

Created: 2024-07-23 06:17

/src/libxslt/libxslt/xslt.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xslt.c: Implemetation of an XSL Transformation 1.0 engine
3
 *
4
 * Reference:
5
 *   XSLT specification
6
 *   http://www.w3.org/TR/1999/REC-xslt-19991116
7
 *
8
 *   Associating Style Sheets with XML documents
9
 *   http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
10
 *
11
 * See Copyright for the status of this software.
12
 *
13
 * daniel@veillard.com
14
 */
15
16
#define IN_LIBXSLT
17
#include "libxslt.h"
18
19
#include <string.h>
20
21
#include <libxml/xmlmemory.h>
22
#include <libxml/parser.h>
23
#include <libxml/tree.h>
24
#include <libxml/valid.h>
25
#include <libxml/hash.h>
26
#include <libxml/uri.h>
27
#include <libxml/xmlerror.h>
28
#include <libxml/parserInternals.h>
29
#include <libxml/xpathInternals.h>
30
#include <libxml/xpath.h>
31
#include "xslt.h"
32
#include "xsltInternals.h"
33
#include "pattern.h"
34
#include "variables.h"
35
#include "namespaces.h"
36
#include "attributes.h"
37
#include "xsltutils.h"
38
#include "imports.h"
39
#include "keys.h"
40
#include "documents.h"
41
#include "extensions.h"
42
#include "preproc.h"
43
#include "extra.h"
44
#include "security.h"
45
#include "xsltlocale.h"
46
47
#ifdef WITH_XSLT_DEBUG
48
#define WITH_XSLT_DEBUG_PARSING
49
/* #define WITH_XSLT_DEBUG_BLANKS */
50
#endif
51
52
const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
53
const int xsltLibxsltVersion = LIBXSLT_VERSION;
54
const int xsltLibxmlVersion = LIBXML_VERSION;
55
56
#ifdef XSLT_REFACTORED
57
58
const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
59
60
#define XSLT_ELEMENT_CATEGORY_XSLT 0
61
#define XSLT_ELEMENT_CATEGORY_EXTENSION 1
62
#define XSLT_ELEMENT_CATEGORY_LRE 2
63
64
/*
65
* xsltLiteralResultMarker:
66
* Marker for Literal result elements, in order to avoid multiple attempts
67
* to recognize such elements in the stylesheet's tree.
68
* This marker is set on node->psvi during the initial traversal
69
* of a stylesheet's node tree.
70
*
71
const xmlChar *xsltLiteralResultMarker =
72
    (const xmlChar *) "Literal Result Element";
73
*/
74
75
/*
76
* xsltXSLTTextMarker:
77
* Marker for xsl:text elements. Used to recognize xsl:text elements
78
* for post-processing of the stylesheet's tree, where those
79
* elements are removed from the tree.
80
*/
81
const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
82
83
/*
84
* xsltXSLTAttrMarker:
85
* Marker for XSLT attribute on Literal Result Elements.
86
*/
87
const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
88
89
#endif
90
91
#ifdef XSLT_LOCALE_WINAPI
92
extern xmlRMutexPtr xsltLocaleMutex;
93
#endif
94
95
/*
96
 * Useful macros
97
 */
98
99
#ifdef  IS_BLANK
100
#undef  IS_BLANK
101
#endif
102
5.08M
#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
103
5.08M
                     ((c) == 0x0D))
104
105
#ifdef  IS_BLANK_NODE
106
#undef  IS_BLANK_NODE
107
#endif
108
#define IS_BLANK_NODE(n)            \
109
1.48M
    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
110
111
/**
112
 * xsltParseContentError:
113
 *
114
 * @style: the stylesheet
115
 * @node: the node where the error occured
116
 *
117
 * Compile-time error function.
118
 */
119
static void
120
xsltParseContentError(xsltStylesheetPtr style,
121
           xmlNodePtr node)
122
183
{
123
183
    if ((style == NULL) || (node == NULL))
124
0
  return;
125
126
183
    if (IS_XSLT_ELEM(node))
127
0
  xsltTransformError(NULL, style, node,
128
0
      "The XSLT-element '%s' is not allowed at this position.\n",
129
0
      node->name);
130
183
    else
131
183
  xsltTransformError(NULL, style, node,
132
183
      "The element '%s' is not allowed at this position.\n",
133
183
      node->name);
134
183
    style->errors++;
135
183
}
136
137
#ifdef XSLT_REFACTORED
138
#else
139
/**
140
 * exclPrefixPush:
141
 * @style: the transformation stylesheet
142
 * @value:  the excluded namespace name to push on the stack
143
 *
144
 * Push an excluded namespace name on the stack
145
 *
146
 * Returns the new index in the stack or -1 if already present or
147
 * in case of error
148
 */
149
static int
150
exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
151
245
{
152
245
    int i;
153
154
    /* do not push duplicates */
155
245
    for (i = 0;i < style->exclPrefixNr;i++) {
156
216
        if (xmlStrEqual(style->exclPrefixTab[i], value))
157
216
      return(-1);
158
216
    }
159
29
    if (style->exclPrefixNr >= style->exclPrefixMax) {
160
29
        xmlChar **tmp;
161
29
        size_t max = style->exclPrefixMax ? style->exclPrefixMax * 2 : 4;
162
163
29
        tmp = xmlRealloc(style->exclPrefixTab,
164
29
                         max * sizeof(style->exclPrefixTab[0]));
165
29
        if (tmp == NULL) {
166
0
            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
167
0
            return (-1);
168
0
        }
169
29
        style->exclPrefixTab = tmp;
170
29
        style->exclPrefixMax = max;
171
29
    }
172
29
    style->exclPrefixTab[style->exclPrefixNr] = value;
173
29
    style->exclPrefix = value;
174
29
    return (style->exclPrefixNr++);
175
29
}
176
/**
177
 * exclPrefixPop:
178
 * @style: the transformation stylesheet
179
 *
180
 * Pop an excluded prefix value from the stack
181
 *
182
 * Returns the stored excluded prefix value
183
 */
184
static xmlChar *
185
exclPrefixPop(xsltStylesheetPtr style)
186
0
{
187
0
    xmlChar *ret;
188
189
0
    if (style->exclPrefixNr <= 0)
190
0
        return (0);
191
0
    style->exclPrefixNr--;
192
0
    if (style->exclPrefixNr > 0)
193
0
        style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
194
0
    else
195
0
        style->exclPrefix = NULL;
196
0
    ret = style->exclPrefixTab[style->exclPrefixNr];
197
0
    style->exclPrefixTab[style->exclPrefixNr] = 0;
198
0
    return (ret);
199
0
}
200
#endif
201
202
/************************************************************************
203
 *                  *
204
 *      Helper functions        *
205
 *                  *
206
 ************************************************************************/
207
208
static int initialized = 0;
209
/**
210
 * xsltInit:
211
 *
212
 * Initializes the processor (e.g. registers built-in extensions,
213
 * etc.)
214
 */
215
void
216
7.39k
xsltInit (void) {
217
7.39k
    if (initialized == 0) {
218
4
  initialized = 1;
219
#ifdef XSLT_LOCALE_WINAPI
220
  xsltLocaleMutex = xmlNewRMutex();
221
#endif
222
4
        xsltRegisterAllExtras();
223
4
    }
224
7.39k
}
225
226
/**
227
 * xsltUninit:
228
 *
229
 * Uninitializes the processor.
230
 */
231
void
232
0
xsltUninit (void) {
233
#ifdef XSLT_LOCALE_WINAPI
234
    xmlFreeRMutex(xsltLocaleMutex);
235
    xsltLocaleMutex = NULL;
236
#endif
237
0
    initialized = 0;
238
0
}
239
240
/**
241
 * xsltIsBlank:
242
 * @str:  a string
243
 *
244
 * Check if a string is ignorable
245
 *
246
 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
247
 */
248
int
249
1.50M
xsltIsBlank(xmlChar *str) {
250
1.50M
    if (str == NULL)
251
0
  return(1);
252
5.46M
    while (*str != 0) {
253
4.99M
  if (!(IS_BLANK(*str))) return(0);
254
3.95M
  str++;
255
3.95M
    }
256
464k
    return(1);
257
1.50M
}
258
259
/************************************************************************
260
 *                  *
261
 *    Routines to handle XSLT data structures     *
262
 *                  *
263
 ************************************************************************/
264
static xsltDecimalFormatPtr
265
xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name)
266
7.39k
{
267
7.39k
    xsltDecimalFormatPtr self;
268
    /* UTF-8 for 0x2030 */
269
7.39k
    static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
270
271
7.39k
    self = xmlMalloc(sizeof(xsltDecimalFormat));
272
7.39k
    if (self != NULL) {
273
7.39k
  self->next = NULL;
274
7.39k
        self->nsUri = nsUri;
275
7.39k
  self->name = name;
276
277
  /* Default values */
278
7.39k
  self->digit = xmlStrdup(BAD_CAST("#"));
279
7.39k
  self->patternSeparator = xmlStrdup(BAD_CAST(";"));
280
7.39k
  self->decimalPoint = xmlStrdup(BAD_CAST("."));
281
7.39k
  self->grouping = xmlStrdup(BAD_CAST(","));
282
7.39k
  self->percent = xmlStrdup(BAD_CAST("%"));
283
7.39k
  self->permille = xmlStrdup(BAD_CAST(permille));
284
7.39k
  self->zeroDigit = xmlStrdup(BAD_CAST("0"));
285
7.39k
  self->minusSign = xmlStrdup(BAD_CAST("-"));
286
7.39k
  self->infinity = xmlStrdup(BAD_CAST("Infinity"));
287
7.39k
  self->noNumber = xmlStrdup(BAD_CAST("NaN"));
288
7.39k
    }
289
7.39k
    return self;
290
7.39k
}
291
292
static void
293
xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
294
7.39k
{
295
7.39k
    if (self != NULL) {
296
7.39k
  if (self->digit)
297
7.39k
      xmlFree(self->digit);
298
7.39k
  if (self->patternSeparator)
299
7.39k
      xmlFree(self->patternSeparator);
300
7.39k
  if (self->decimalPoint)
301
7.39k
      xmlFree(self->decimalPoint);
302
7.39k
  if (self->grouping)
303
7.39k
      xmlFree(self->grouping);
304
7.39k
  if (self->percent)
305
7.39k
      xmlFree(self->percent);
306
7.39k
  if (self->permille)
307
7.39k
      xmlFree(self->permille);
308
7.39k
  if (self->zeroDigit)
309
7.39k
      xmlFree(self->zeroDigit);
310
7.39k
  if (self->minusSign)
311
7.39k
      xmlFree(self->minusSign);
312
7.39k
  if (self->infinity)
313
7.39k
      xmlFree(self->infinity);
314
7.39k
  if (self->noNumber)
315
7.39k
      xmlFree(self->noNumber);
316
7.39k
  if (self->name)
317
1
      xmlFree(self->name);
318
7.39k
  xmlFree(self);
319
7.39k
    }
320
7.39k
}
321
322
static void
323
xsltFreeDecimalFormatList(xsltStylesheetPtr self)
324
7.39k
{
325
7.39k
    xsltDecimalFormatPtr iter;
326
7.39k
    xsltDecimalFormatPtr tmp;
327
328
7.39k
    if (self == NULL)
329
0
  return;
330
331
7.39k
    iter = self->decimalFormat;
332
14.7k
    while (iter != NULL) {
333
7.39k
  tmp = iter->next;
334
7.39k
  xsltFreeDecimalFormat(iter);
335
7.39k
  iter = tmp;
336
7.39k
    }
337
7.39k
}
338
339
/**
340
 * xsltDecimalFormatGetByName:
341
 * @style: the XSLT stylesheet
342
 * @name: the decimal-format name to find
343
 *
344
 * Find decimal-format by name
345
 *
346
 * Returns the xsltDecimalFormatPtr
347
 */
348
xsltDecimalFormatPtr
349
xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
350
0
{
351
0
    xsltDecimalFormatPtr result = NULL;
352
353
0
    if (name == NULL)
354
0
  return style->decimalFormat;
355
356
0
    while (style != NULL) {
357
0
  for (result = style->decimalFormat->next;
358
0
       result != NULL;
359
0
       result = result->next) {
360
0
      if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
361
0
    return result;
362
0
  }
363
0
  style = xsltNextImport(style);
364
0
    }
365
0
    return result;
366
0
}
367
368
/**
369
 * xsltDecimalFormatGetByQName:
370
 * @style: the XSLT stylesheet
371
 * @nsUri: the namespace URI of the QName
372
 * @name: the local part of the QName
373
 *
374
 * Find decimal-format by QName
375
 *
376
 * Returns the xsltDecimalFormatPtr
377
 */
378
xsltDecimalFormatPtr
379
xsltDecimalFormatGetByQName(xsltStylesheetPtr style, const xmlChar *nsUri,
380
                            const xmlChar *name)
381
5
{
382
5
    xsltDecimalFormatPtr result = NULL;
383
384
5
    if (name == NULL)
385
0
  return style->decimalFormat;
386
387
151
    while (style != NULL) {
388
150
  for (result = style->decimalFormat->next;
389
150
       result != NULL;
390
150
       result = result->next) {
391
4
      if (xmlStrEqual(nsUri, result->nsUri) &&
392
4
                xmlStrEqual(name, result->name))
393
4
    return result;
394
4
  }
395
146
  style = xsltNextImport(style);
396
146
    }
397
1
    return result;
398
5
}
399
400
401
/**
402
 * xsltNewTemplate:
403
 *
404
 * Create a new XSLT Template
405
 *
406
 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
407
 */
408
static xsltTemplatePtr
409
2.79k
xsltNewTemplate(void) {
410
2.79k
    xsltTemplatePtr cur;
411
412
2.79k
    cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
413
2.79k
    if (cur == NULL) {
414
1
  xsltTransformError(NULL, NULL, NULL,
415
1
    "xsltNewTemplate : malloc failed\n");
416
1
  return(NULL);
417
1
    }
418
2.79k
    memset(cur, 0, sizeof(xsltTemplate));
419
2.79k
    cur->priority = XSLT_PAT_NO_PRIORITY;
420
2.79k
    return(cur);
421
2.79k
}
422
423
/**
424
 * xsltFreeTemplate:
425
 * @template:  an XSLT template
426
 *
427
 * Free up the memory allocated by @template
428
 */
429
static void
430
2.79k
xsltFreeTemplate(xsltTemplatePtr template) {
431
2.79k
    if (template == NULL)
432
0
  return;
433
2.79k
    if (template->match) xmlFree(template->match);
434
/*
435
*   NOTE: @name and @nameURI are put into the string dict now.
436
*   if (template->name) xmlFree(template->name);
437
*   if (template->nameURI) xmlFree(template->nameURI);
438
*/
439
/*
440
    if (template->mode) xmlFree(template->mode);
441
    if (template->modeURI) xmlFree(template->modeURI);
442
 */
443
2.79k
    if (template->inheritedNs) xmlFree(template->inheritedNs);
444
445
    /* free profiling data */
446
2.79k
    if (template->templCalledTab) xmlFree(template->templCalledTab);
447
2.79k
    if (template->templCountTab) xmlFree(template->templCountTab);
448
449
2.79k
    memset(template, -1, sizeof(xsltTemplate));
450
2.79k
    xmlFree(template);
451
2.79k
}
452
453
/**
454
 * xsltFreeTemplateList:
455
 * @template:  an XSLT template list
456
 *
457
 * Free up the memory allocated by all the elements of @template
458
 */
459
static void
460
7.39k
xsltFreeTemplateList(xsltTemplatePtr template) {
461
7.39k
    xsltTemplatePtr cur;
462
463
10.1k
    while (template != NULL) {
464
2.79k
  cur = template;
465
2.79k
  template = template->next;
466
2.79k
  xsltFreeTemplate(cur);
467
2.79k
    }
468
7.39k
}
469
470
#ifdef XSLT_REFACTORED
471
472
static void
473
xsltFreeNsAliasList(xsltNsAliasPtr item)
474
{
475
    xsltNsAliasPtr tmp;
476
477
    while (item) {
478
  tmp = item;
479
  item = item->next;
480
  xmlFree(tmp);
481
    }
482
    return;
483
}
484
485
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
486
static void
487
xsltFreeNamespaceMap(xsltNsMapPtr item)
488
{
489
    xsltNsMapPtr tmp;
490
491
    while (item) {
492
  tmp = item;
493
  item = item->next;
494
  xmlFree(tmp);
495
    }
496
    return;
497
}
498
499
static xsltNsMapPtr
500
xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
501
      xmlDocPtr doc,
502
      xmlNsPtr ns,
503
      xmlNodePtr elem)
504
{
505
    xsltNsMapPtr ret;
506
507
    if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
508
  return(NULL);
509
510
    ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
511
    if (ret == NULL) {
512
  xsltTransformError(NULL, cctxt->style, elem,
513
      "Internal error: (xsltNewNamespaceMapItem) "
514
      "memory allocation failed.\n");
515
  return(NULL);
516
    }
517
    memset(ret, 0, sizeof(xsltNsMap));
518
    ret->doc = doc;
519
    ret->ns = ns;
520
    ret->origNsName = ns->href;
521
    /*
522
    * Store the item at current stylesheet-level.
523
    */
524
    if (cctxt->psData->nsMap != NULL)
525
  ret->next = cctxt->psData->nsMap;
526
    cctxt->psData->nsMap = ret;
527
528
    return(ret);
529
}
530
#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
531
532
/**
533
 * xsltCompilerVarInfoFree:
534
 * @cctxt: the compilation context
535
 *
536
 * Frees the list of information for vars/params.
537
 */
538
static void
539
xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
540
{
541
    xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
542
543
    while (ivar) {
544
  ivartmp = ivar;
545
  ivar = ivar->next;
546
  xmlFree(ivartmp);
547
    }
548
}
549
550
/**
551
 * xsltCompilerCtxtFree:
552
 *
553
 * Free an XSLT compiler context.
554
 */
555
static void
556
xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
557
{
558
    if (cctxt == NULL)
559
  return;
560
#ifdef WITH_XSLT_DEBUG_PARSING
561
    xsltGenericDebug(xsltGenericDebugContext,
562
  "Freeing compilation context\n");
563
    xsltGenericDebug(xsltGenericDebugContext,
564
  "### Max inodes: %d\n", cctxt->maxNodeInfos);
565
    xsltGenericDebug(xsltGenericDebugContext,
566
  "### Max LREs  : %d\n", cctxt->maxLREs);
567
#endif
568
    /*
569
    * Free node-infos.
570
    */
571
    if (cctxt->inodeList != NULL) {
572
  xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
573
  while (cur != NULL) {
574
      tmp = cur;
575
      cur = cur->next;
576
      xmlFree(tmp);
577
  }
578
    }
579
    if (cctxt->tmpList != NULL)
580
  xsltPointerListFree(cctxt->tmpList);
581
    if (cctxt->nsAliases != NULL)
582
  xsltFreeNsAliasList(cctxt->nsAliases);
583
584
    if (cctxt->ivars)
585
  xsltCompilerVarInfoFree(cctxt);
586
587
    xmlFree(cctxt);
588
}
589
590
/**
591
 * xsltCompilerCreate:
592
 *
593
 * Creates an XSLT compiler context.
594
 *
595
 * Returns the pointer to the created xsltCompilerCtxt or
596
 *         NULL in case of an internal error.
597
 */
598
static xsltCompilerCtxtPtr
599
xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
600
    xsltCompilerCtxtPtr ret;
601
602
    ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
603
    if (ret == NULL) {
604
  xsltTransformError(NULL, style, NULL,
605
      "xsltCompilerCreate: allocation of compiler "
606
      "context failed.\n");
607
  return(NULL);
608
    }
609
    memset(ret, 0, sizeof(xsltCompilerCtxt));
610
611
    ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
612
    ret->tmpList = xsltPointerListCreate(20);
613
    if (ret->tmpList == NULL) {
614
  goto internal_err;
615
    }
616
617
    return(ret);
618
619
internal_err:
620
    xsltCompilationCtxtFree(ret);
621
    return(NULL);
622
}
623
624
static void
625
xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
626
{
627
    xsltEffectiveNsPtr tmp;
628
629
    while (first != NULL) {
630
  tmp = first;
631
  first = first->nextInStore;
632
  xmlFree(tmp);
633
    }
634
}
635
636
static void
637
xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
638
{
639
    if (data == NULL)
640
  return;
641
642
    if (data->inScopeNamespaces != NULL) {
643
  int i;
644
  xsltNsListContainerPtr nsi;
645
  xsltPointerListPtr list =
646
      (xsltPointerListPtr) data->inScopeNamespaces;
647
648
  for (i = 0; i < list->number; i++) {
649
      /*
650
      * REVISIT TODO: Free info of in-scope namespaces.
651
      */
652
      nsi = (xsltNsListContainerPtr) list->items[i];
653
      if (nsi->list != NULL)
654
    xmlFree(nsi->list);
655
      xmlFree(nsi);
656
  }
657
  xsltPointerListFree(list);
658
  data->inScopeNamespaces = NULL;
659
    }
660
661
    if (data->exclResultNamespaces != NULL) {
662
  int i;
663
  xsltPointerListPtr list = (xsltPointerListPtr)
664
      data->exclResultNamespaces;
665
666
  for (i = 0; i < list->number; i++)
667
      xsltPointerListFree((xsltPointerListPtr) list->items[i]);
668
669
  xsltPointerListFree(list);
670
  data->exclResultNamespaces = NULL;
671
    }
672
673
    if (data->extElemNamespaces != NULL) {
674
  xsltPointerListPtr list = (xsltPointerListPtr)
675
      data->extElemNamespaces;
676
  int i;
677
678
  for (i = 0; i < list->number; i++)
679
      xsltPointerListFree((xsltPointerListPtr) list->items[i]);
680
681
  xsltPointerListFree(list);
682
  data->extElemNamespaces = NULL;
683
    }
684
    if (data->effectiveNs) {
685
  xsltLREEffectiveNsNodesFree(data->effectiveNs);
686
  data->effectiveNs = NULL;
687
    }
688
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
689
    xsltFreeNamespaceMap(data->nsMap);
690
#endif
691
    xmlFree(data);
692
}
693
694
static xsltPrincipalStylesheetDataPtr
695
xsltNewPrincipalStylesheetData(void)
696
{
697
    xsltPrincipalStylesheetDataPtr ret;
698
699
    ret = (xsltPrincipalStylesheetDataPtr)
700
  xmlMalloc(sizeof(xsltPrincipalStylesheetData));
701
    if (ret == NULL) {
702
  xsltTransformError(NULL, NULL, NULL,
703
      "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
704
  return(NULL);
705
    }
706
    memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
707
708
    /*
709
    * Global list of in-scope namespaces.
710
    */
711
    ret->inScopeNamespaces = xsltPointerListCreate(-1);
712
    if (ret->inScopeNamespaces == NULL)
713
  goto internal_err;
714
    /*
715
    * Global list of excluded result ns-decls.
716
    */
717
    ret->exclResultNamespaces = xsltPointerListCreate(-1);
718
    if (ret->exclResultNamespaces == NULL)
719
  goto internal_err;
720
    /*
721
    * Global list of extension instruction namespace names.
722
    */
723
    ret->extElemNamespaces = xsltPointerListCreate(-1);
724
    if (ret->extElemNamespaces == NULL)
725
  goto internal_err;
726
727
    return(ret);
728
729
internal_err:
730
731
    return(NULL);
732
}
733
734
#endif
735
736
/**
737
 * xsltNewStylesheetInternal:
738
 * @parent:  the parent stylesheet or NULL
739
 *
740
 * Create a new XSLT Stylesheet
741
 *
742
 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
743
 */
744
static xsltStylesheetPtr
745
7.39k
xsltNewStylesheetInternal(xsltStylesheetPtr parent) {
746
7.39k
    xsltStylesheetPtr ret = NULL;
747
748
7.39k
    ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
749
7.39k
    if (ret == NULL) {
750
0
  xsltTransformError(NULL, NULL, NULL,
751
0
    "xsltNewStylesheet : malloc failed\n");
752
0
  goto internal_err;
753
0
    }
754
7.39k
    memset(ret, 0, sizeof(xsltStylesheet));
755
756
7.39k
    ret->parent = parent;
757
7.39k
    ret->omitXmlDeclaration = -1;
758
7.39k
    ret->standalone = -1;
759
7.39k
    ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
760
7.39k
    ret->indent = -1;
761
7.39k
    ret->errors = 0;
762
7.39k
    ret->warnings = 0;
763
7.39k
    ret->exclPrefixNr = 0;
764
7.39k
    ret->exclPrefixMax = 0;
765
7.39k
    ret->exclPrefixTab = NULL;
766
7.39k
    ret->extInfos = NULL;
767
7.39k
    ret->extrasNr = 0;
768
7.39k
    ret->internalized = 1;
769
7.39k
    ret->literal_result = 0;
770
7.39k
    ret->forwards_compatible = 0;
771
7.39k
    ret->dict = xmlDictCreate();
772
#ifdef WITH_XSLT_DEBUG
773
    xsltGenericDebug(xsltGenericDebugContext,
774
  "creating dictionary for stylesheet\n");
775
#endif
776
777
7.39k
    if (parent == NULL) {
778
597
        ret->principal = ret;
779
780
597
        ret->xpathCtxt = xmlXPathNewContext(NULL);
781
597
        if (ret->xpathCtxt == NULL) {
782
0
            xsltTransformError(NULL, NULL, NULL,
783
0
                    "xsltNewStylesheet: xmlXPathNewContext failed\n");
784
0
            goto internal_err;
785
0
        }
786
597
        if (xmlXPathContextSetCache(ret->xpathCtxt, 1, -1, 0) == -1)
787
0
            goto internal_err;
788
6.79k
    } else {
789
6.79k
        ret->principal = parent->principal;
790
6.79k
    }
791
792
7.39k
    xsltInit();
793
794
7.39k
    return(ret);
795
796
0
internal_err:
797
0
    if (ret != NULL)
798
0
  xsltFreeStylesheet(ret);
799
0
    return(NULL);
800
7.39k
}
801
802
/**
803
 * xsltNewStylesheet:
804
 *
805
 * Create a new XSLT Stylesheet
806
 *
807
 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
808
 */
809
xsltStylesheetPtr
810
597
xsltNewStylesheet(void) {
811
597
    return xsltNewStylesheetInternal(NULL);
812
597
}
813
814
/**
815
 * xsltAllocateExtra:
816
 * @style:  an XSLT stylesheet
817
 *
818
 * Allocate an extra runtime information slot statically while compiling
819
 * the stylesheet and return its number
820
 *
821
 * Returns the number of the slot
822
 */
823
int
824
xsltAllocateExtra(xsltStylesheetPtr style)
825
33.7k
{
826
33.7k
    return(style->extrasNr++);
827
33.7k
}
828
829
/**
830
 * xsltAllocateExtraCtxt:
831
 * @ctxt:  an XSLT transformation context
832
 *
833
 * Allocate an extra runtime information slot at run-time
834
 * and return its number
835
 * This make sure there is a slot ready in the transformation context
836
 *
837
 * Returns the number of the slot
838
 */
839
int
840
xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
841
0
{
842
0
    if (ctxt->extrasNr >= ctxt->extrasMax) {
843
0
  int i;
844
0
  if (ctxt->extrasNr == 0) {
845
0
      ctxt->extrasMax = 20;
846
0
      ctxt->extras = (xsltRuntimeExtraPtr)
847
0
    xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
848
0
      if (ctxt->extras == NULL) {
849
0
    xsltTransformError(ctxt, NULL, NULL,
850
0
      "xsltAllocateExtraCtxt: out of memory\n");
851
0
    return(0);
852
0
      }
853
0
      for (i = 0;i < ctxt->extrasMax;i++) {
854
0
    ctxt->extras[i].info = NULL;
855
0
    ctxt->extras[i].deallocate = NULL;
856
0
    ctxt->extras[i].val.ptr = NULL;
857
0
      }
858
859
0
  } else {
860
0
      xsltRuntimeExtraPtr tmp;
861
862
0
      ctxt->extrasMax += 100;
863
0
      tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
864
0
                ctxt->extrasMax * sizeof(xsltRuntimeExtra));
865
0
      if (tmp == NULL) {
866
0
    xsltTransformError(ctxt, NULL, NULL,
867
0
      "xsltAllocateExtraCtxt: out of memory\n");
868
0
    return(0);
869
0
      }
870
0
      ctxt->extras = tmp;
871
0
      for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
872
0
    ctxt->extras[i].info = NULL;
873
0
    ctxt->extras[i].deallocate = NULL;
874
0
    ctxt->extras[i].val.ptr = NULL;
875
0
      }
876
0
  }
877
0
    }
878
0
    return(ctxt->extrasNr++);
879
0
}
880
881
/**
882
 * xsltFreeStylesheetList:
883
 * @style:  an XSLT stylesheet list
884
 *
885
 * Free up the memory allocated by the list @style
886
 */
887
static void
888
423
xsltFreeStylesheetList(xsltStylesheetPtr style) {
889
423
    xsltStylesheetPtr next;
890
891
1.90k
    while (style != NULL) {
892
1.48k
  next = style->next;
893
1.48k
  xsltFreeStylesheet(style);
894
1.48k
  style = next;
895
1.48k
    }
896
423
}
897
898
/**
899
 * xsltCleanupStylesheetTree:
900
 *
901
 * @doc: the document-node
902
 * @node: the element where the stylesheet is rooted at
903
 *
904
 * Actually @node need not be the document-element, but
905
 * currently Libxslt does not support embedded stylesheets.
906
 *
907
 * Returns 0 if OK, -1 on API or internal errors.
908
 */
909
static int
910
xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
911
        xmlNodePtr rootElem ATTRIBUTE_UNUSED)
912
592
{
913
#if 0 /* TODO: Currently disabled, since probably not needed. */
914
    xmlNodePtr cur;
915
916
    if ((doc == NULL) || (rootElem == NULL) ||
917
  (rootElem->type != XML_ELEMENT_NODE) ||
918
  (doc != rootElem->doc))
919
  return(-1);
920
921
    /*
922
    * Cleanup was suggested by Aleksey Sanin:
923
    * Clear the PSVI field to avoid problems if the
924
    * node-tree of the stylesheet is intended to be used for
925
    * further processing by the user (e.g. for compiling it
926
    * once again - although not recommended).
927
    */
928
929
    cur = rootElem;
930
    while (cur != NULL) {
931
  if (cur->type == XML_ELEMENT_NODE) {
932
      /*
933
      * Clear the PSVI field.
934
      */
935
      cur->psvi = NULL;
936
      if (cur->children) {
937
    cur = cur->children;
938
    continue;
939
      }
940
  }
941
942
leave_node:
943
  if (cur == rootElem)
944
      break;
945
  if (cur->next != NULL)
946
      cur = cur->next;
947
  else {
948
      cur = cur->parent;
949
      if (cur == NULL)
950
    break;
951
      goto leave_node;
952
  }
953
    }
954
#endif /* #if 0 */
955
592
    return(0);
956
592
}
957
958
/**
959
 * xsltFreeStylesheet:
960
 * @style:  an XSLT stylesheet
961
 *
962
 * Free up the memory allocated by @style
963
 */
964
void
965
xsltFreeStylesheet(xsltStylesheetPtr style)
966
7.80k
{
967
7.80k
    if (style == NULL)
968
413
        return;
969
970
#ifdef XSLT_REFACTORED
971
    /*
972
    * Start with a cleanup of the main stylesheet's doc.
973
    */
974
    if ((style->principal == style) && (style->doc))
975
  xsltCleanupStylesheetTree(style->doc,
976
      xmlDocGetRootElement(style->doc));
977
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
978
    /*
979
    * Restore changed ns-decls before freeing the document.
980
    */
981
    if ((style->doc != NULL) &&
982
  XSLT_HAS_INTERNAL_NSMAP(style))
983
    {
984
  xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
985
      style->doc);
986
    }
987
#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
988
#else
989
    /*
990
    * Start with a cleanup of the main stylesheet's doc.
991
    */
992
7.39k
    if ((style->parent == NULL) && (style->doc))
993
395
  xsltCleanupStylesheetTree(style->doc,
994
395
      xmlDocGetRootElement(style->doc));
995
7.39k
#endif /* XSLT_REFACTORED */
996
997
7.39k
    xsltFreeKeys(style);
998
7.39k
    xsltFreeExts(style);
999
7.39k
    xsltFreeTemplateHashes(style);
1000
7.39k
    xsltFreeDecimalFormatList(style);
1001
7.39k
    xsltFreeTemplateList(style->templates);
1002
7.39k
    xsltFreeAttributeSetsHashes(style);
1003
7.39k
    xsltFreeNamespaceAliasHashes(style);
1004
7.39k
    xsltFreeStylePreComps(style);
1005
    /*
1006
    * Free documents of all included stylsheet modules of this
1007
    * stylesheet level.
1008
    */
1009
7.39k
    xsltFreeStyleDocuments(style);
1010
    /*
1011
    * TODO: Best time to shutdown extension stuff?
1012
    */
1013
7.39k
    xsltShutdownExts(style);
1014
1015
7.39k
    if (style->variables != NULL)
1016
181
        xsltFreeStackElemList(style->variables);
1017
7.39k
    if (style->cdataSection != NULL)
1018
345
        xmlHashFree(style->cdataSection, NULL);
1019
7.39k
    if (style->stripSpaces != NULL)
1020
528
        xmlHashFree(style->stripSpaces, NULL);
1021
7.39k
    if (style->nsHash != NULL)
1022
0
        xmlHashFree(style->nsHash, NULL);
1023
7.39k
    if (style->exclPrefixTab != NULL)
1024
29
        xmlFree(style->exclPrefixTab);
1025
7.39k
    if (style->method != NULL)
1026
275
        xmlFree(style->method);
1027
7.39k
    if (style->methodURI != NULL)
1028
0
        xmlFree(style->methodURI);
1029
7.39k
    if (style->version != NULL)
1030
0
        xmlFree(style->version);
1031
7.39k
    if (style->encoding != NULL)
1032
161
        xmlFree(style->encoding);
1033
7.39k
    if (style->doctypePublic != NULL)
1034
1
        xmlFree(style->doctypePublic);
1035
7.39k
    if (style->doctypeSystem != NULL)
1036
1
        xmlFree(style->doctypeSystem);
1037
7.39k
    if (style->mediaType != NULL)
1038
0
        xmlFree(style->mediaType);
1039
7.39k
    if (style->attVTs)
1040
87
        xsltFreeAVTList(style->attVTs);
1041
7.39k
    if (style->imports != NULL)
1042
423
        xsltFreeStylesheetList(style->imports);
1043
1044
#ifdef XSLT_REFACTORED
1045
    /*
1046
    * If this is the principal stylesheet, then
1047
    * free its internal data.
1048
    */
1049
    if (style->principal == style) {
1050
  if (style->principalData) {
1051
      xsltFreePrincipalStylesheetData(style->principalData);
1052
      style->principalData = NULL;
1053
  }
1054
    }
1055
#endif
1056
    /*
1057
    * Better to free the main document of this stylesheet level
1058
    * at the end - so here.
1059
    */
1060
7.39k
    if (style->doc != NULL) {
1061
1.87k
        xmlFreeDoc(style->doc);
1062
1.87k
    }
1063
1064
#ifdef WITH_XSLT_DEBUG
1065
    xsltGenericDebug(xsltGenericDebugContext,
1066
                     "freeing dictionary from stylesheet\n");
1067
#endif
1068
7.39k
    xmlDictFree(style->dict);
1069
1070
7.39k
    if (style->xpathCtxt != NULL)
1071
595
  xmlXPathFreeContext(style->xpathCtxt);
1072
1073
7.39k
    memset(style, -1, sizeof(xsltStylesheet));
1074
7.39k
    xmlFree(style);
1075
7.39k
}
1076
1077
/************************************************************************
1078
 *                  *
1079
 *    Parsing of an XSLT Stylesheet       *
1080
 *                  *
1081
 ************************************************************************/
1082
1083
#ifdef XSLT_REFACTORED
1084
    /*
1085
    * This is now performed in an optimized way in xsltParseXSLTTemplate.
1086
    */
1087
#else
1088
/**
1089
 * xsltGetInheritedNsList:
1090
 * @style:  the stylesheet
1091
 * @template: the template
1092
 * @node:  the current node
1093
 *
1094
 * Search all the namespace applying to a given element except the ones
1095
 * from excluded output prefixes currently in scope. Initialize the
1096
 * template inheritedNs list with it.
1097
 *
1098
 * Returns the number of entries found
1099
 */
1100
static int
1101
xsltGetInheritedNsList(xsltStylesheetPtr style,
1102
                 xsltTemplatePtr template,
1103
                 xmlNodePtr node)
1104
2.72k
{
1105
2.72k
    xmlNsPtr cur;
1106
2.72k
    xmlNsPtr *ret = NULL, *tmp;
1107
2.72k
    int nbns = 0;
1108
2.72k
    int maxns = 0;
1109
2.72k
    int i;
1110
1111
2.72k
    if ((style == NULL) || (template == NULL) || (node == NULL) ||
1112
2.72k
  (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
1113
0
  return(0);
1114
10.8k
    while (node != NULL) {
1115
8.16k
        if (node->type == XML_ELEMENT_NODE) {
1116
5.44k
            cur = node->nsDef;
1117
14.6k
            while (cur != NULL) {
1118
9.18k
    if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
1119
3.28k
        goto skip_ns;
1120
1121
5.90k
    if ((cur->prefix != NULL) &&
1122
5.90k
        (xsltCheckExtPrefix(style, cur->prefix)))
1123
283
        goto skip_ns;
1124
    /*
1125
    * Check if this namespace was excluded.
1126
    * Note that at this point only the exclusions defined
1127
    * on the topmost stylesheet element are in the exclusion-list.
1128
    */
1129
5.91k
    for (i = 0;i < style->exclPrefixNr;i++) {
1130
321
        if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
1131
28
      goto skip_ns;
1132
321
    }
1133
    /*
1134
    * Skip shadowed namespace bindings.
1135
    */
1136
22.7k
                for (i = 0; i < nbns; i++) {
1137
17.1k
                    if ((cur->prefix == ret[i]->prefix) ||
1138
17.1k
                        (xmlStrEqual(cur->prefix, ret[i]->prefix)))
1139
0
                        break;
1140
17.1k
                }
1141
5.59k
                if (i >= nbns) {
1142
5.59k
                    if (nbns >= maxns) {
1143
1.98k
                        maxns = (maxns == 0) ? 10 : 2 * maxns;
1144
1.98k
                        tmp = (xmlNsPtr *) xmlRealloc(ret,
1145
1.98k
                                (maxns + 1) * sizeof(xmlNsPtr));
1146
1.98k
                        if (tmp == NULL) {
1147
0
                            xmlGenericError(xmlGenericErrorContext,
1148
0
                                            "xsltGetInheritedNsList : realloc failed!\n");
1149
0
                            xmlFree(ret);
1150
0
                            return(0);
1151
0
                        }
1152
1.98k
                        ret = tmp;
1153
1.98k
                    }
1154
5.59k
                    ret[nbns++] = cur;
1155
5.59k
                    ret[nbns] = NULL;
1156
5.59k
                }
1157
9.18k
skip_ns:
1158
9.18k
                cur = cur->next;
1159
9.18k
            }
1160
5.44k
        }
1161
8.16k
        node = node->parent;
1162
8.16k
    }
1163
2.72k
    if (nbns != 0) {
1164
#ifdef WITH_XSLT_DEBUG_PARSING
1165
        xsltGenericDebug(xsltGenericDebugContext,
1166
                         "template has %d inherited namespaces\n", nbns);
1167
#endif
1168
1.91k
  template->inheritedNsNr = nbns;
1169
1.91k
  template->inheritedNs = ret;
1170
1.91k
    }
1171
2.72k
    return (nbns);
1172
2.72k
}
1173
#endif /* else of XSLT_REFACTORED */
1174
1175
/**
1176
 * xsltParseStylesheetOutput:
1177
 * @style:  the XSLT stylesheet
1178
 * @cur:  the "output" element
1179
 *
1180
 * parse an XSLT stylesheet output element and record
1181
 * information related to the stylesheet output
1182
 */
1183
1184
void
1185
xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
1186
1.17k
{
1187
1.17k
    xmlChar *elements,
1188
1.17k
     *prop;
1189
1.17k
    xmlChar *element,
1190
1.17k
     *end;
1191
1192
1.17k
    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1193
0
        return;
1194
1195
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
1196
1.17k
    if (prop != NULL) {
1197
0
        if (style->version != NULL)
1198
0
            xmlFree(style->version);
1199
0
        style->version = prop;
1200
0
    }
1201
1202
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
1203
1.17k
    if (prop != NULL) {
1204
423
        if (style->encoding != NULL)
1205
262
            xmlFree(style->encoding);
1206
423
        style->encoding = prop;
1207
423
    }
1208
1209
    /* relaxed to support xt:document
1210
    * TODO KB: What does "relaxed to support xt:document" mean?
1211
    */
1212
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
1213
1.17k
    if (prop != NULL) {
1214
522
        const xmlChar *URI;
1215
1216
522
        if (style->method != NULL)
1217
213
            xmlFree(style->method);
1218
522
        style->method = NULL;
1219
522
        if (style->methodURI != NULL)
1220
0
            xmlFree(style->methodURI);
1221
522
        style->methodURI = NULL;
1222
1223
  /*
1224
  * TODO: Don't use xsltGetQNameURI().
1225
  */
1226
522
  URI = xsltGetQNameURI(cur, &prop);
1227
522
  if (prop == NULL) {
1228
0
      if (style != NULL) style->errors++;
1229
522
  } else if (URI == NULL) {
1230
522
            if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1231
522
                (xmlStrEqual(prop, (const xmlChar *) "html")) ||
1232
522
                (xmlStrEqual(prop, (const xmlChar *) "text"))) {
1233
488
                style->method = prop;
1234
488
            } else {
1235
34
    xsltTransformError(NULL, style, cur,
1236
34
                                 "invalid value for method: %s\n", prop);
1237
34
                if (style != NULL) style->warnings++;
1238
34
                xmlFree(prop);
1239
34
            }
1240
522
  } else {
1241
0
      style->method = prop;
1242
0
      style->methodURI = xmlStrdup(URI);
1243
0
  }
1244
522
    }
1245
1246
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
1247
1.17k
    if (prop != NULL) {
1248
47
        if (style->doctypeSystem != NULL)
1249
46
            xmlFree(style->doctypeSystem);
1250
47
        style->doctypeSystem = prop;
1251
47
    }
1252
1253
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
1254
1.17k
    if (prop != NULL) {
1255
31
        if (style->doctypePublic != NULL)
1256
30
            xmlFree(style->doctypePublic);
1257
31
        style->doctypePublic = prop;
1258
31
    }
1259
1260
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
1261
1.17k
    if (prop != NULL) {
1262
255
        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1263
222
            style->standalone = 1;
1264
222
        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1265
0
            style->standalone = 0;
1266
33
        } else {
1267
33
      xsltTransformError(NULL, style, cur,
1268
33
                             "invalid value for standalone: %s\n", prop);
1269
33
            style->errors++;
1270
33
        }
1271
255
        xmlFree(prop);
1272
255
    }
1273
1274
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
1275
1.17k
    if (prop != NULL) {
1276
249
        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1277
249
            style->indent = 1;
1278
249
        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1279
0
            style->indent = 0;
1280
0
        } else {
1281
0
      xsltTransformError(NULL, style, cur,
1282
0
                             "invalid value for indent: %s\n", prop);
1283
0
            style->errors++;
1284
0
        }
1285
249
        xmlFree(prop);
1286
249
    }
1287
1288
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
1289
1.17k
    if (prop != NULL) {
1290
39
        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1291
39
            style->omitXmlDeclaration = 1;
1292
39
        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1293
0
            style->omitXmlDeclaration = 0;
1294
0
        } else {
1295
0
      xsltTransformError(NULL, style, cur,
1296
0
                             "invalid value for omit-xml-declaration: %s\n",
1297
0
                             prop);
1298
0
            style->errors++;
1299
0
        }
1300
39
        xmlFree(prop);
1301
39
    }
1302
1303
1.17k
    elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
1304
1.17k
  NULL);
1305
1.17k
    if (elements != NULL) {
1306
345
        if (style->cdataSection == NULL)
1307
345
            style->cdataSection = xmlHashCreate(10);
1308
345
        if (style->cdataSection == NULL) {
1309
0
            xmlFree(elements);
1310
0
            return;
1311
0
        }
1312
1313
345
        element = elements;
1314
690
        while (*element != 0) {
1315
345
            while (IS_BLANK(*element))
1316
0
                element++;
1317
345
            if (*element == 0)
1318
0
                break;
1319
345
            end = element;
1320
2.76k
            while ((*end != 0) && (!IS_BLANK(*end)))
1321
2.41k
                end++;
1322
345
            element = xmlStrndup(element, end - element);
1323
345
            if (element) {
1324
#ifdef WITH_XSLT_DEBUG_PARSING
1325
                xsltGenericDebug(xsltGenericDebugContext,
1326
                                 "add cdata section output element %s\n",
1327
                                 element);
1328
#endif
1329
345
    if (xmlValidateQName(BAD_CAST element, 0) != 0) {
1330
0
        xsltTransformError(NULL, style, cur,
1331
0
      "Attribute 'cdata-section-elements': The value "
1332
0
      "'%s' is not a valid QName.\n", element);
1333
0
        xmlFree(element);
1334
0
        style->errors++;
1335
345
    } else {
1336
345
        const xmlChar *URI;
1337
1338
        /*
1339
        * TODO: Don't use xsltGetQNameURI().
1340
        */
1341
345
        URI = xsltGetQNameURI(cur, &element);
1342
345
        if (element == NULL) {
1343
      /*
1344
      * TODO: We'll report additionally an error
1345
      *  via the stylesheet's error handling.
1346
      */
1347
0
      xsltTransformError(NULL, style, cur,
1348
0
          "Attribute 'cdata-section-elements': "
1349
0
          "Not a valid QName.\n");
1350
0
      style->errors++;
1351
345
        } else {
1352
345
      xmlNsPtr ns;
1353
1354
      /*
1355
      * XSLT-1.0 "Each QName is expanded into an
1356
      *  expanded-name using the namespace declarations in
1357
      *  effect on the xsl:output element in which the QName
1358
      *  occurs; if there is a default namespace, it is used
1359
      *  for QNames that do not have a prefix"
1360
      * NOTE: Fix of bug #339570.
1361
      */
1362
345
      if (URI == NULL) {
1363
345
          ns = xmlSearchNs(style->doc, cur, NULL);
1364
345
          if (ns != NULL)
1365
293
        URI = ns->href;
1366
345
      }
1367
345
      xmlHashAddEntry2(style->cdataSection, element, URI,
1368
345
          (void *) "cdata");
1369
345
      xmlFree(element);
1370
345
        }
1371
345
    }
1372
345
            }
1373
345
            element = end;
1374
345
        }
1375
345
        xmlFree(elements);
1376
345
    }
1377
1378
1.17k
    prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
1379
1.17k
    if (prop != NULL) {
1380
0
  if (style->mediaType)
1381
0
      xmlFree(style->mediaType);
1382
0
  style->mediaType = prop;
1383
0
    }
1384
1.17k
    if (cur->children != NULL) {
1385
183
  xsltParseContentError(style, cur->children);
1386
183
    }
1387
1.17k
}
1388
1389
/**
1390
 * xsltParseStylesheetDecimalFormat:
1391
 * @style:  the XSLT stylesheet
1392
 * @cur:  the "decimal-format" element
1393
 *
1394
 * <!-- Category: top-level-element -->
1395
 * <xsl:decimal-format
1396
 *   name = qname, decimal-separator = char, grouping-separator = char,
1397
 *   infinity = string, minus-sign = char, NaN = string, percent = char
1398
 *   per-mille = char, zero-digit = char, digit = char,
1399
 * pattern-separator = char />
1400
 *
1401
 * parse an XSLT stylesheet decimal-format element and
1402
 * and record the formatting characteristics
1403
 */
1404
static void
1405
xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
1406
7
{
1407
7
    xmlChar *prop;
1408
7
    xsltDecimalFormatPtr format;
1409
7
    xsltDecimalFormatPtr iter;
1410
1411
7
    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1412
0
  return;
1413
1414
7
    format = style->decimalFormat;
1415
1416
7
    prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
1417
7
    if (prop != NULL) {
1418
5
        const xmlChar *nsUri;
1419
1420
5
        if (xmlValidateQName(prop, 0) != 0) {
1421
0
            xsltTransformError(NULL, style, cur,
1422
0
                "xsl:decimal-format: Invalid QName '%s'.\n", prop);
1423
0
      style->warnings++;
1424
0
            xmlFree(prop);
1425
0
            return;
1426
0
        }
1427
        /*
1428
        * TODO: Don't use xsltGetQNameURI().
1429
        */
1430
5
        nsUri = xsltGetQNameURI(cur, &prop);
1431
5
        if (prop == NULL) {
1432
0
      style->warnings++;
1433
0
            return;
1434
0
        }
1435
5
  format = xsltDecimalFormatGetByQName(style, nsUri, prop);
1436
5
  if (format != NULL) {
1437
4
      xsltTransformError(NULL, style, cur,
1438
4
   "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
1439
4
      style->warnings++;
1440
4
            xmlFree(prop);
1441
4
      return;
1442
4
  }
1443
1
  format = xsltNewDecimalFormat(nsUri, prop);
1444
1
  if (format == NULL) {
1445
0
      xsltTransformError(NULL, style, cur,
1446
0
     "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1447
0
      style->errors++;
1448
0
            xmlFree(prop);
1449
0
      return;
1450
0
  }
1451
  /* Append new decimal-format structure */
1452
1
  for (iter = style->decimalFormat; iter->next; iter = iter->next)
1453
0
      ;
1454
1
  if (iter)
1455
1
      iter->next = format;
1456
1
    }
1457
1458
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
1459
3
    if (prop != NULL) {
1460
0
  if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
1461
0
  format->decimalPoint  = prop;
1462
0
    }
1463
1464
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
1465
3
    if (prop != NULL) {
1466
0
  if (format->grouping != NULL) xmlFree(format->grouping);
1467
0
  format->grouping  = prop;
1468
0
    }
1469
1470
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
1471
3
    if (prop != NULL) {
1472
0
  if (format->infinity != NULL) xmlFree(format->infinity);
1473
0
  format->infinity  = prop;
1474
0
    }
1475
1476
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
1477
3
    if (prop != NULL) {
1478
0
  if (format->minusSign != NULL) xmlFree(format->minusSign);
1479
0
  format->minusSign  = prop;
1480
0
    }
1481
1482
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
1483
3
    if (prop != NULL) {
1484
0
  if (format->noNumber != NULL) xmlFree(format->noNumber);
1485
0
  format->noNumber  = prop;
1486
0
    }
1487
1488
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
1489
3
    if (prop != NULL) {
1490
0
  if (format->percent != NULL) xmlFree(format->percent);
1491
0
  format->percent  = prop;
1492
0
    }
1493
1494
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
1495
3
    if (prop != NULL) {
1496
0
  if (format->permille != NULL) xmlFree(format->permille);
1497
0
  format->permille  = prop;
1498
0
    }
1499
1500
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
1501
3
    if (prop != NULL) {
1502
0
  if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
1503
0
  format->zeroDigit  = prop;
1504
0
    }
1505
1506
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
1507
3
    if (prop != NULL) {
1508
0
  if (format->digit != NULL) xmlFree(format->digit);
1509
0
  format->digit  = prop;
1510
0
    }
1511
1512
3
    prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
1513
3
    if (prop != NULL) {
1514
0
  if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
1515
0
  format->patternSeparator  = prop;
1516
0
    }
1517
3
    if (cur->children != NULL) {
1518
0
  xsltParseContentError(style, cur->children);
1519
0
    }
1520
3
}
1521
1522
/**
1523
 * xsltParseStylesheetPreserveSpace:
1524
 * @style:  the XSLT stylesheet
1525
 * @cur:  the "preserve-space" element
1526
 *
1527
 * parse an XSLT stylesheet preserve-space element and record
1528
 * elements needing preserving
1529
 */
1530
1531
static void
1532
134
xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1533
134
    xmlChar *elements;
1534
134
    xmlChar *element, *end;
1535
1536
134
    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1537
0
  return;
1538
1539
134
    elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1540
134
    if (elements == NULL) {
1541
0
  xsltTransformError(NULL, style, cur,
1542
0
      "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1543
0
  if (style != NULL) style->warnings++;
1544
0
  return;
1545
0
    }
1546
1547
134
    if (style->stripSpaces == NULL)
1548
134
  style->stripSpaces = xmlHashCreate(10);
1549
134
    if (style->stripSpaces == NULL) {
1550
0
        xmlFree(elements);
1551
0
  return;
1552
0
    }
1553
1554
134
    element = elements;
1555
2.68k
    while (*element != 0) {
1556
4.95k
  while (IS_BLANK(*element)) element++;
1557
2.54k
  if (*element == 0)
1558
0
      break;
1559
2.54k
        end = element;
1560
57.0k
  while ((*end != 0) && (!IS_BLANK(*end))) end++;
1561
2.54k
  element = xmlStrndup(element, end - element);
1562
2.54k
  if (element) {
1563
#ifdef WITH_XSLT_DEBUG_PARSING
1564
      xsltGenericDebug(xsltGenericDebugContext,
1565
    "add preserved space element %s\n", element);
1566
#endif
1567
2.54k
      if (xmlStrEqual(element, (const xmlChar *)"*")) {
1568
0
    style->stripAll = -1;
1569
2.54k
      } else {
1570
2.54k
    const xmlChar *URI;
1571
1572
    /*
1573
    * TODO: Don't use xsltGetQNameURI().
1574
    */
1575
2.54k
                URI = xsltGetQNameURI(cur, &element);
1576
1577
2.54k
    xmlHashAddEntry2(style->stripSpaces, element, URI,
1578
2.54k
        (xmlChar *) "preserve");
1579
2.54k
      }
1580
2.54k
      xmlFree(element);
1581
2.54k
  }
1582
2.54k
  element = end;
1583
2.54k
    }
1584
134
    xmlFree(elements);
1585
134
    if (cur->children != NULL) {
1586
0
  xsltParseContentError(style, cur->children);
1587
0
    }
1588
134
}
1589
1590
#ifdef XSLT_REFACTORED
1591
#else
1592
/**
1593
 * xsltParseStylesheetExtPrefix:
1594
 * @style:  the XSLT stylesheet
1595
 * @template:  the "extension-element-prefixes" prefix
1596
 *
1597
 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1598
 * and register the namespaces of extension instruction.
1599
 * SPEC "A namespace is designated as an extension namespace by using
1600
 *   an extension-element-prefixes attribute on:
1601
 *   1) an xsl:stylesheet element
1602
 *   2) an xsl:extension-element-prefixes attribute on a
1603
 *      literal result element
1604
 *   3) an extension instruction."
1605
 */
1606
static void
1607
xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1608
8.57k
           int isXsltElem) {
1609
8.57k
    xmlChar *prefixes;
1610
8.57k
    xmlChar *prefix, *end;
1611
1612
8.57k
    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1613
0
  return;
1614
1615
8.57k
    if (isXsltElem) {
1616
  /* For xsl:stylesheet/xsl:transform. */
1617
8.46k
  prefixes = xmlGetNsProp(cur,
1618
8.46k
      (const xmlChar *)"extension-element-prefixes", NULL);
1619
8.46k
    } else {
1620
  /* For literal result elements and extension instructions. */
1621
106
  prefixes = xmlGetNsProp(cur,
1622
106
      (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
1623
106
    }
1624
8.57k
    if (prefixes == NULL) {
1625
7.93k
  return;
1626
7.93k
    }
1627
1628
641
    prefix = prefixes;
1629
1.97k
    while (*prefix != 0) {
1630
2.02k
  while (IS_BLANK(*prefix)) prefix++;
1631
1.33k
  if (*prefix == 0)
1632
0
      break;
1633
1.33k
        end = prefix;
1634
8.86k
  while ((*end != 0) && (!IS_BLANK(*end))) end++;
1635
1.33k
  prefix = xmlStrndup(prefix, end - prefix);
1636
1.33k
  if (prefix) {
1637
1.33k
      xmlNsPtr ns;
1638
1639
1.33k
      if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1640
0
    ns = xmlSearchNs(style->doc, cur, NULL);
1641
1.33k
      else
1642
1.33k
    ns = xmlSearchNs(style->doc, cur, prefix);
1643
1.33k
      if (ns == NULL) {
1644
683
    xsltTransformError(NULL, style, cur,
1645
683
      "xsl:extension-element-prefix : undefined namespace %s\n",
1646
683
                           prefix);
1647
683
    if (style != NULL) style->warnings++;
1648
683
      } else {
1649
#ifdef WITH_XSLT_DEBUG_PARSING
1650
    xsltGenericDebug(xsltGenericDebugContext,
1651
        "add extension prefix %s\n", prefix);
1652
#endif
1653
651
    xsltRegisterExtPrefix(style, prefix, ns->href);
1654
651
      }
1655
1.33k
      xmlFree(prefix);
1656
1.33k
  }
1657
1.33k
  prefix = end;
1658
1.33k
    }
1659
641
    xmlFree(prefixes);
1660
641
}
1661
#endif /* else of XSLT_REFACTORED */
1662
1663
/**
1664
 * xsltParseStylesheetStripSpace:
1665
 * @style:  the XSLT stylesheet
1666
 * @cur:  the "strip-space" element
1667
 *
1668
 * parse an XSLT stylesheet's strip-space element and record
1669
 * the elements needing stripping
1670
 */
1671
1672
static void
1673
394
xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1674
394
    xmlChar *elements;
1675
394
    xmlChar *element, *end;
1676
1677
394
    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1678
0
  return;
1679
1680
394
    if (style->stripSpaces == NULL)
1681
394
  style->stripSpaces = xmlHashCreate(10);
1682
394
    if (style->stripSpaces == NULL)
1683
0
  return;
1684
1685
394
    elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1686
394
    if (elements == NULL) {
1687
348
  xsltTransformError(NULL, style, cur,
1688
348
      "xsltParseStylesheetStripSpace: missing elements attribute\n");
1689
348
  if (style != NULL) style->warnings++;
1690
348
  return;
1691
348
    }
1692
1693
46
    element = elements;
1694
92
    while (*element != 0) {
1695
46
  while (IS_BLANK(*element)) element++;
1696
46
  if (*element == 0)
1697
0
      break;
1698
46
        end = element;
1699
92
  while ((*end != 0) && (!IS_BLANK(*end))) end++;
1700
46
  element = xmlStrndup(element, end - element);
1701
46
  if (element) {
1702
#ifdef WITH_XSLT_DEBUG_PARSING
1703
      xsltGenericDebug(xsltGenericDebugContext,
1704
    "add stripped space element %s\n", element);
1705
#endif
1706
46
      if (xmlStrEqual(element, (const xmlChar *)"*")) {
1707
46
    style->stripAll = 1;
1708
46
      } else {
1709
0
    const xmlChar *URI;
1710
1711
    /*
1712
    * TODO: Don't use xsltGetQNameURI().
1713
    */
1714
0
                URI = xsltGetQNameURI(cur, &element);
1715
1716
0
    xmlHashAddEntry2(style->stripSpaces, element, URI,
1717
0
              (xmlChar *) "strip");
1718
0
      }
1719
46
      xmlFree(element);
1720
46
  }
1721
46
  element = end;
1722
46
    }
1723
46
    xmlFree(elements);
1724
46
    if (cur->children != NULL) {
1725
0
  xsltParseContentError(style, cur->children);
1726
0
    }
1727
46
}
1728
1729
#ifdef XSLT_REFACTORED
1730
#else
1731
/**
1732
 * xsltParseStylesheetExcludePrefix:
1733
 * @style:  the XSLT stylesheet
1734
 * @cur:  the current point in the stylesheet
1735
 *
1736
 * parse an XSLT stylesheet exclude prefix and record
1737
 * namespaces needing stripping
1738
 *
1739
 * Returns the number of Excluded prefixes added at that level
1740
 */
1741
1742
static int
1743
xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1744
         int isXsltElem)
1745
1.75M
{
1746
1.75M
    int nb = 0;
1747
1.75M
    xmlChar *prefixes;
1748
1.75M
    xmlChar *prefix, *end;
1749
1750
1.75M
    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1751
0
  return(0);
1752
1753
1.75M
    if (isXsltElem)
1754
8.46k
  prefixes = xmlGetNsProp(cur,
1755
8.46k
      (const xmlChar *)"exclude-result-prefixes", NULL);
1756
1.74M
    else
1757
1.74M
  prefixes = xmlGetNsProp(cur,
1758
1.74M
      (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
1759
1760
1.75M
    if (prefixes == NULL) {
1761
1.75M
  return(0);
1762
1.75M
    }
1763
1764
245
    prefix = prefixes;
1765
1.40k
    while (*prefix != 0) {
1766
2.09k
  while (IS_BLANK(*prefix)) prefix++;
1767
1.15k
  if (*prefix == 0)
1768
0
      break;
1769
1.15k
        end = prefix;
1770
4.43k
  while ((*end != 0) && (!IS_BLANK(*end))) end++;
1771
1.15k
  prefix = xmlStrndup(prefix, end - prefix);
1772
1.15k
  if (prefix) {
1773
1.15k
      xmlNsPtr ns;
1774
1775
1.15k
      if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1776
0
    ns = xmlSearchNs(style->doc, cur, NULL);
1777
1.15k
      else
1778
1.15k
    ns = xmlSearchNs(style->doc, cur, prefix);
1779
1.15k
      if (ns == NULL) {
1780
914
    xsltTransformError(NULL, style, cur,
1781
914
      "xsl:exclude-result-prefixes : undefined namespace %s\n",
1782
914
                           prefix);
1783
914
    if (style != NULL) style->warnings++;
1784
914
      } else {
1785
245
    if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
1786
#ifdef WITH_XSLT_DEBUG_PARSING
1787
        xsltGenericDebug(xsltGenericDebugContext,
1788
      "exclude result prefix %s\n", prefix);
1789
#endif
1790
29
        nb++;
1791
29
    }
1792
245
      }
1793
1.15k
      xmlFree(prefix);
1794
1.15k
  }
1795
1.15k
  prefix = end;
1796
1.15k
    }
1797
245
    xmlFree(prefixes);
1798
245
    return(nb);
1799
1.75M
}
1800
#endif /* else of XSLT_REFACTORED */
1801
1802
#ifdef XSLT_REFACTORED
1803
1804
/*
1805
* xsltTreeEnsureXMLDecl:
1806
* @doc: the doc
1807
*
1808
* BIG NOTE:
1809
*  This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1810
* Ensures that there is an XML namespace declaration on the doc.
1811
*
1812
* Returns the XML ns-struct or NULL on API and internal errors.
1813
*/
1814
static xmlNsPtr
1815
xsltTreeEnsureXMLDecl(xmlDocPtr doc)
1816
{
1817
    if (doc == NULL)
1818
  return (NULL);
1819
    if (doc->oldNs != NULL)
1820
  return (doc->oldNs);
1821
    {
1822
  xmlNsPtr ns;
1823
  ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1824
  if (ns == NULL) {
1825
      xmlGenericError(xmlGenericErrorContext,
1826
    "xsltTreeEnsureXMLDecl: Failed to allocate "
1827
    "the XML namespace.\n");
1828
      return (NULL);
1829
  }
1830
  memset(ns, 0, sizeof(xmlNs));
1831
  ns->type = XML_LOCAL_NAMESPACE;
1832
  /*
1833
  * URGENT TODO: revisit this.
1834
  */
1835
#ifdef LIBXML_NAMESPACE_DICT
1836
  if (doc->dict)
1837
      ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
1838
  else
1839
      ns->href = xmlStrdup(XML_XML_NAMESPACE);
1840
#else
1841
  ns->href = xmlStrdup(XML_XML_NAMESPACE);
1842
#endif
1843
  ns->prefix = xmlStrdup((const xmlChar *)"xml");
1844
  doc->oldNs = ns;
1845
  return (ns);
1846
    }
1847
}
1848
1849
/*
1850
* xsltTreeAcquireStoredNs:
1851
* @doc: the doc
1852
* @nsName: the namespace name
1853
* @prefix: the prefix
1854
*
1855
* BIG NOTE:
1856
*  This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1857
* Creates or reuses an xmlNs struct on doc->oldNs with
1858
* the given prefix and namespace name.
1859
*
1860
* Returns the aquired ns struct or NULL in case of an API
1861
*         or internal error.
1862
*/
1863
static xmlNsPtr
1864
xsltTreeAcquireStoredNs(xmlDocPtr doc,
1865
      const xmlChar *nsName,
1866
      const xmlChar *prefix)
1867
{
1868
    xmlNsPtr ns;
1869
1870
    if (doc == NULL)
1871
  return (NULL);
1872
    if (doc->oldNs != NULL)
1873
  ns = doc->oldNs;
1874
    else
1875
  ns = xsltTreeEnsureXMLDecl(doc);
1876
    if (ns == NULL)
1877
  return (NULL);
1878
    if (ns->next != NULL) {
1879
  /* Reuse. */
1880
  ns = ns->next;
1881
  while (ns != NULL) {
1882
      if ((ns->prefix == NULL) != (prefix == NULL)) {
1883
    /* NOP */
1884
      } else if (prefix == NULL) {
1885
    if (xmlStrEqual(ns->href, nsName))
1886
        return (ns);
1887
      } else {
1888
    if ((ns->prefix[0] == prefix[0]) &&
1889
         xmlStrEqual(ns->prefix, prefix) &&
1890
         xmlStrEqual(ns->href, nsName))
1891
        return (ns);
1892
1893
      }
1894
      if (ns->next == NULL)
1895
    break;
1896
      ns = ns->next;
1897
  }
1898
    }
1899
    /* Create. */
1900
    ns->next = xmlNewNs(NULL, nsName, prefix);
1901
    return (ns->next);
1902
}
1903
1904
/**
1905
 * xsltLREBuildEffectiveNs:
1906
 *
1907
 * Apply ns-aliasing on the namespace of the given @elem and
1908
 * its attributes.
1909
 */
1910
static int
1911
xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
1912
      xmlNodePtr elem)
1913
{
1914
    xmlNsPtr ns;
1915
    xsltNsAliasPtr alias;
1916
1917
    if ((cctxt == NULL) || (elem == NULL))
1918
  return(-1);
1919
    if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
1920
  return(0);
1921
1922
    alias = cctxt->nsAliases;
1923
    while (alias != NULL) {
1924
  if ( /* If both namespaces are NULL... */
1925
      ( (elem->ns == NULL) &&
1926
      ((alias->literalNs == NULL) ||
1927
      (alias->literalNs->href == NULL)) ) ||
1928
      /* ... or both namespace are equal */
1929
      ( (elem->ns != NULL) &&
1930
      (alias->literalNs != NULL) &&
1931
      xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1932
  {
1933
      if ((alias->targetNs != NULL) &&
1934
    (alias->targetNs->href != NULL))
1935
      {
1936
    /*
1937
    * Convert namespace.
1938
    */
1939
    if (elem->doc == alias->docOfTargetNs) {
1940
        /*
1941
        * This is the nice case: same docs.
1942
        * This will eventually assign a ns-decl which
1943
        * is shadowed, but this has no negative effect on
1944
        * the generation of the result tree.
1945
        */
1946
        elem->ns = alias->targetNs;
1947
    } else {
1948
        /*
1949
        * This target xmlNs originates from a different
1950
        * stylesheet tree. Try to locate it in the
1951
        * in-scope namespaces.
1952
        * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1953
        */
1954
        ns = xmlSearchNs(elem->doc, elem,
1955
      alias->targetNs->prefix);
1956
        /*
1957
        * If no matching ns-decl found, then assign a
1958
        * ns-decl stored in xmlDoc.
1959
        */
1960
        if ((ns == NULL) ||
1961
      (! xmlStrEqual(ns->href, alias->targetNs->href)))
1962
        {
1963
      /*
1964
      * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1965
      *  is not very efficient, but currently I don't
1966
      *  see an other way of *safely* changing a node's
1967
      *  namespace, since the xmlNs struct in
1968
      *  alias->targetNs might come from an other
1969
      *  stylesheet tree. So we need to anchor it in the
1970
      *  current document, without adding it to the tree,
1971
      *  which would otherwise change the in-scope-ns
1972
      *  semantic of the tree.
1973
      */
1974
      ns = xsltTreeAcquireStoredNs(elem->doc,
1975
          alias->targetNs->href,
1976
          alias->targetNs->prefix);
1977
1978
      if (ns == NULL) {
1979
          xsltTransformError(NULL, cctxt->style, elem,
1980
        "Internal error in "
1981
        "xsltLREBuildEffectiveNs(): "
1982
        "failed to acquire a stored "
1983
        "ns-declaration.\n");
1984
          cctxt->style->errors++;
1985
          return(-1);
1986
1987
      }
1988
        }
1989
        elem->ns = ns;
1990
    }
1991
      } else {
1992
    /*
1993
    * Move into or leave in the NULL namespace.
1994
    */
1995
    elem->ns = NULL;
1996
      }
1997
      break;
1998
  }
1999
  alias = alias->next;
2000
    }
2001
    /*
2002
    * Same with attributes of literal result elements.
2003
    */
2004
    if (elem->properties != NULL) {
2005
  xmlAttrPtr attr = elem->properties;
2006
2007
  while (attr != NULL) {
2008
      if (attr->ns == NULL) {
2009
    attr = attr->next;
2010
    continue;
2011
      }
2012
      alias = cctxt->nsAliases;
2013
      while (alias != NULL) {
2014
    if ( /* If both namespaces are NULL... */
2015
        ( (elem->ns == NULL) &&
2016
        ((alias->literalNs == NULL) ||
2017
        (alias->literalNs->href == NULL)) ) ||
2018
        /* ... or both namespace are equal */
2019
        ( (elem->ns != NULL) &&
2020
        (alias->literalNs != NULL) &&
2021
        xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
2022
    {
2023
        if ((alias->targetNs != NULL) &&
2024
      (alias->targetNs->href != NULL))
2025
        {
2026
      if (elem->doc == alias->docOfTargetNs) {
2027
          elem->ns = alias->targetNs;
2028
      } else {
2029
          ns = xmlSearchNs(elem->doc, elem,
2030
        alias->targetNs->prefix);
2031
          if ((ns == NULL) ||
2032
        (! xmlStrEqual(ns->href, alias->targetNs->href)))
2033
          {
2034
        ns = xsltTreeAcquireStoredNs(elem->doc,
2035
            alias->targetNs->href,
2036
            alias->targetNs->prefix);
2037
2038
        if (ns == NULL) {
2039
            xsltTransformError(NULL, cctxt->style, elem,
2040
          "Internal error in "
2041
          "xsltLREBuildEffectiveNs(): "
2042
          "failed to acquire a stored "
2043
          "ns-declaration.\n");
2044
            cctxt->style->errors++;
2045
            return(-1);
2046
2047
        }
2048
          }
2049
          elem->ns = ns;
2050
      }
2051
        } else {
2052
        /*
2053
        * Move into or leave in the NULL namespace.
2054
      */
2055
      elem->ns = NULL;
2056
        }
2057
        break;
2058
    }
2059
    alias = alias->next;
2060
      }
2061
2062
      attr = attr->next;
2063
  }
2064
    }
2065
    return(0);
2066
}
2067
2068
/**
2069
 * xsltLREBuildEffectiveNsNodes:
2070
 *
2071
 * Computes the effective namespaces nodes for a literal result
2072
 * element.
2073
 * @effectiveNs is the set of effective ns-nodes
2074
 *  on the literal result element, which will be added to the result
2075
 *  element if not already existing in the result tree.
2076
 *  This means that excluded namespaces (via exclude-result-prefixes,
2077
 *  extension-element-prefixes and the XSLT namespace) not added
2078
 *  to the set.
2079
 *  Namespace-aliasing was applied on the @effectiveNs.
2080
 */
2081
static int
2082
xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
2083
           xsltStyleItemLRElementInfoPtr item,
2084
           xmlNodePtr elem,
2085
           int isLRE)
2086
{
2087
    xmlNsPtr ns, tmpns;
2088
    xsltEffectiveNsPtr effNs, lastEffNs = NULL;
2089
    int i, j, holdByElem;
2090
    xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
2091
    xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
2092
2093
    if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
2094
  (item == NULL) || (item->effectiveNs != NULL))
2095
  return(-1);
2096
2097
    if (item->inScopeNs == NULL)
2098
  return(0);
2099
2100
    extElemNs = cctxt->inode->extElemNs;
2101
    exclResultNs = cctxt->inode->exclResultNs;
2102
2103
    for (i = 0; i < item->inScopeNs->totalNumber; i++) {
2104
  ns = item->inScopeNs->list[i];
2105
  /*
2106
  * Skip namespaces designated as excluded namespaces
2107
  * -------------------------------------------------
2108
  *
2109
  * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2110
  *  which are target namespaces of namespace-aliases
2111
  *  regardless if designated as excluded.
2112
  *
2113
  * Exclude the XSLT namespace.
2114
  */
2115
  if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2116
      goto skip_ns;
2117
2118
  /*
2119
  * Apply namespace aliasing
2120
  * ------------------------
2121
  *
2122
  * SPEC XSLT 2.0
2123
  *  "- A namespace node whose string value is a literal namespace
2124
  *     URI is not copied to the result tree.
2125
  *   - A namespace node whose string value is a target namespace URI
2126
  *     is copied to the result tree, whether or not the URI
2127
  *     identifies an excluded namespace."
2128
  *
2129
  * NOTE: The ns-aliasing machanism is non-cascading.
2130
  *  (checked with Saxon, Xalan and MSXML .NET).
2131
  * URGENT TODO: is style->nsAliases the effective list of
2132
  *  ns-aliases, or do we need to lookup the whole
2133
  *  import-tree?
2134
  * TODO: Get rid of import-tree lookup.
2135
  */
2136
  if (cctxt->hasNsAliases) {
2137
      xsltNsAliasPtr alias;
2138
      /*
2139
      * First check for being a target namespace.
2140
      */
2141
      alias = cctxt->nsAliases;
2142
      do {
2143
    /*
2144
    * TODO: Is xmlns="" handled already?
2145
    */
2146
    if ((alias->targetNs != NULL) &&
2147
        (xmlStrEqual(alias->targetNs->href, ns->href)))
2148
    {
2149
        /*
2150
        * Recognized as a target namespace; use it regardless
2151
        * if excluded otherwise.
2152
        */
2153
        goto add_effective_ns;
2154
    }
2155
    alias = alias->next;
2156
      } while (alias != NULL);
2157
2158
      alias = cctxt->nsAliases;
2159
      do {
2160
    /*
2161
    * TODO: Is xmlns="" handled already?
2162
    */
2163
    if ((alias->literalNs != NULL) &&
2164
        (xmlStrEqual(alias->literalNs->href, ns->href)))
2165
    {
2166
        /*
2167
        * Recognized as an namespace alias; do not use it.
2168
        */
2169
        goto skip_ns;
2170
    }
2171
    alias = alias->next;
2172
      } while (alias != NULL);
2173
  }
2174
2175
  /*
2176
  * Exclude excluded result namespaces.
2177
  */
2178
  if (exclResultNs) {
2179
      for (j = 0; j < exclResultNs->number; j++)
2180
    if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
2181
        goto skip_ns;
2182
  }
2183
  /*
2184
  * Exclude extension-element namespaces.
2185
  */
2186
  if (extElemNs) {
2187
      for (j = 0; j < extElemNs->number; j++)
2188
    if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
2189
        goto skip_ns;
2190
  }
2191
2192
add_effective_ns:
2193
  /*
2194
  * OPTIMIZE TODO: This information may not be needed.
2195
  */
2196
  if (isLRE && (elem->nsDef != NULL)) {
2197
      holdByElem = 0;
2198
      tmpns = elem->nsDef;
2199
      do {
2200
    if (tmpns == ns) {
2201
        holdByElem = 1;
2202
        break;
2203
    }
2204
    tmpns = tmpns->next;
2205
      } while (tmpns != NULL);
2206
  } else
2207
      holdByElem = 0;
2208
2209
2210
  /*
2211
  * Add the effective namespace declaration.
2212
  */
2213
  effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
2214
  if (effNs == NULL) {
2215
      xsltTransformError(NULL, cctxt->style, elem,
2216
    "Internal error in xsltLREBuildEffectiveNs(): "
2217
    "failed to allocate memory.\n");
2218
      cctxt->style->errors++;
2219
      return(-1);
2220
  }
2221
  if (cctxt->psData->effectiveNs == NULL) {
2222
      cctxt->psData->effectiveNs = effNs;
2223
      effNs->nextInStore = NULL;
2224
  } else {
2225
      effNs->nextInStore = cctxt->psData->effectiveNs;
2226
      cctxt->psData->effectiveNs = effNs;
2227
  }
2228
2229
  effNs->next = NULL;
2230
  effNs->prefix = ns->prefix;
2231
  effNs->nsName = ns->href;
2232
  effNs->holdByElem = holdByElem;
2233
2234
  if (lastEffNs == NULL)
2235
      item->effectiveNs = effNs;
2236
  else
2237
      lastEffNs->next = effNs;
2238
  lastEffNs = effNs;
2239
2240
skip_ns:
2241
  {}
2242
    }
2243
    return(0);
2244
}
2245
2246
2247
/**
2248
 * xsltLREInfoCreate:
2249
 *
2250
 * @isLRE: indicates if the given @elem is a literal result element
2251
 *
2252
 * Creates a new info for a literal result element.
2253
 */
2254
static int
2255
xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
2256
      xmlNodePtr elem,
2257
      int isLRE)
2258
{
2259
    xsltStyleItemLRElementInfoPtr item;
2260
2261
    if ((cctxt == NULL) || (cctxt->inode == NULL))
2262
  return(-1);
2263
2264
    item = (xsltStyleItemLRElementInfoPtr)
2265
  xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
2266
    if (item == NULL) {
2267
  xsltTransformError(NULL, cctxt->style, NULL,
2268
      "Internal error in xsltLREInfoCreate(): "
2269
      "memory allocation failed.\n");
2270
  cctxt->style->errors++;
2271
  return(-1);
2272
    }
2273
    memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
2274
    item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
2275
    /*
2276
    * Store it in the stylesheet.
2277
    */
2278
    item->next = cctxt->style->preComps;
2279
    cctxt->style->preComps = (xsltElemPreCompPtr) item;
2280
    /*
2281
    * @inScopeNs are used for execution of XPath expressions
2282
    *  in AVTs.
2283
    */
2284
    item->inScopeNs = cctxt->inode->inScopeNs;
2285
2286
    if (elem)
2287
  xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
2288
2289
    cctxt->inode->litResElemInfo = item;
2290
    cctxt->inode->nsChanged = 0;
2291
    cctxt->maxLREs++;
2292
    return(0);
2293
}
2294
2295
/**
2296
 * xsltCompilerVarInfoPush:
2297
 * @cctxt: the compilation context
2298
 *
2299
 * Pushes a new var/param info onto the stack.
2300
 *
2301
 * Returns the acquired variable info.
2302
 */
2303
static xsltVarInfoPtr
2304
xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
2305
          xmlNodePtr inst,
2306
          const xmlChar *name,
2307
          const xmlChar *nsName)
2308
{
2309
    xsltVarInfoPtr ivar;
2310
2311
    if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
2312
  ivar = cctxt->ivar->next;
2313
    } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
2314
  ivar = cctxt->ivars;
2315
    } else {
2316
  ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
2317
  if (ivar == NULL) {
2318
      xsltTransformError(NULL, cctxt->style, inst,
2319
    "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2320
      cctxt->style->errors++;
2321
      return(NULL);
2322
  }
2323
  /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2324
  if (cctxt->ivars == NULL) {
2325
      cctxt->ivars = ivar;
2326
      ivar->prev = NULL;
2327
  } else {
2328
      cctxt->ivar->next = ivar;
2329
      ivar->prev = cctxt->ivar;
2330
  }
2331
  cctxt->ivar = ivar;
2332
  ivar->next = NULL;
2333
    }
2334
    ivar->depth = cctxt->depth;
2335
    ivar->name = name;
2336
    ivar->nsName = nsName;
2337
    return(ivar);
2338
}
2339
2340
/**
2341
 * xsltCompilerVarInfoPop:
2342
 * @cctxt: the compilation context
2343
 *
2344
 * Pops all var/param infos from the stack, which
2345
 * have the current depth.
2346
 */
2347
static void
2348
xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
2349
{
2350
2351
    while ((cctxt->ivar != NULL) &&
2352
  (cctxt->ivar->depth > cctxt->depth))
2353
    {
2354
  cctxt->ivar = cctxt->ivar->prev;
2355
    }
2356
}
2357
2358
/*
2359
* xsltCompilerNodePush:
2360
*
2361
* @cctxt: the compilation context
2362
* @node: the node to be pushed (this can also be the doc-node)
2363
*
2364
*
2365
*
2366
* Returns the current node info structure or
2367
*         NULL in case of an internal error.
2368
*/
2369
static xsltCompilerNodeInfoPtr
2370
xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2371
{
2372
    xsltCompilerNodeInfoPtr inode, iprev;
2373
2374
    if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
2375
  inode = cctxt->inode->next;
2376
    } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
2377
  inode = cctxt->inodeList;
2378
    } else {
2379
  /*
2380
  * Create a new node-info.
2381
  */
2382
  inode = (xsltCompilerNodeInfoPtr)
2383
      xmlMalloc(sizeof(xsltCompilerNodeInfo));
2384
  if (inode == NULL) {
2385
      xsltTransformError(NULL, cctxt->style, NULL,
2386
    "xsltCompilerNodePush: malloc failed.\n");
2387
      return(NULL);
2388
  }
2389
  memset(inode, 0, sizeof(xsltCompilerNodeInfo));
2390
  if (cctxt->inodeList == NULL)
2391
      cctxt->inodeList = inode;
2392
  else {
2393
      cctxt->inodeLast->next = inode;
2394
      inode->prev = cctxt->inodeLast;
2395
  }
2396
  cctxt->inodeLast = inode;
2397
  cctxt->maxNodeInfos++;
2398
  if (cctxt->inode == NULL) {
2399
      cctxt->inode = inode;
2400
      /*
2401
      * Create an initial literal result element info for
2402
      * the root of the stylesheet.
2403
      */
2404
      xsltLREInfoCreate(cctxt, NULL, 0);
2405
  }
2406
    }
2407
    cctxt->depth++;
2408
    cctxt->inode = inode;
2409
    /*
2410
    * REVISIT TODO: Keep the reset always complete.
2411
    * NOTE: Be carefull with the @node, since it might be
2412
    *  a doc-node.
2413
    */
2414
    inode->node = node;
2415
    inode->depth = cctxt->depth;
2416
    inode->templ = NULL;
2417
    inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
2418
    inode->type = 0;
2419
    inode->item = NULL;
2420
    inode->curChildType = 0;
2421
    inode->extContentHandled = 0;
2422
    inode->isRoot = 0;
2423
2424
    if (inode->prev != NULL) {
2425
  iprev = inode->prev;
2426
  /*
2427
  * Inherit the following information:
2428
  * ---------------------------------
2429
  *
2430
  * In-scope namespaces
2431
  */
2432
  inode->inScopeNs = iprev->inScopeNs;
2433
  /*
2434
  * Info for literal result elements
2435
  */
2436
  inode->litResElemInfo = iprev->litResElemInfo;
2437
  inode->nsChanged = iprev->nsChanged;
2438
  /*
2439
  * Excluded result namespaces
2440
  */
2441
  inode->exclResultNs = iprev->exclResultNs;
2442
  /*
2443
  * Extension instruction namespaces
2444
  */
2445
  inode->extElemNs = iprev->extElemNs;
2446
  /*
2447
  * Whitespace preservation
2448
  */
2449
  inode->preserveWhitespace = iprev->preserveWhitespace;
2450
  /*
2451
  * Forwards-compatible mode
2452
  */
2453
  inode->forwardsCompat = iprev->forwardsCompat;
2454
    } else {
2455
  inode->inScopeNs = NULL;
2456
  inode->exclResultNs = NULL;
2457
  inode->extElemNs = NULL;
2458
  inode->preserveWhitespace = 0;
2459
  inode->forwardsCompat = 0;
2460
    }
2461
2462
    return(inode);
2463
}
2464
2465
/*
2466
* xsltCompilerNodePop:
2467
*
2468
* @cctxt: the compilation context
2469
* @node: the node to be pushed (this can also be the doc-node)
2470
*
2471
* Pops the current node info.
2472
*/
2473
static void
2474
xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2475
{
2476
    if (cctxt->inode == NULL) {
2477
  xmlGenericError(xmlGenericErrorContext,
2478
      "xsltCompilerNodePop: Top-node mismatch.\n");
2479
  return;
2480
    }
2481
    /*
2482
    * NOTE: Be carefull with the @node, since it might be
2483
    *  a doc-node.
2484
    */
2485
    if (cctxt->inode->node != node) {
2486
  xmlGenericError(xmlGenericErrorContext,
2487
  "xsltCompilerNodePop: Node mismatch.\n");
2488
  goto mismatch;
2489
    }
2490
    if (cctxt->inode->depth != cctxt->depth) {
2491
  xmlGenericError(xmlGenericErrorContext,
2492
  "xsltCompilerNodePop: Depth mismatch.\n");
2493
  goto mismatch;
2494
    }
2495
    cctxt->depth--;
2496
    /*
2497
    * Pop information of variables.
2498
    */
2499
    if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
2500
  xsltCompilerVarInfoPop(cctxt);
2501
2502
    cctxt->inode = cctxt->inode->prev;
2503
    if (cctxt->inode != NULL)
2504
  cctxt->inode->curChildType = 0;
2505
    return;
2506
2507
mismatch:
2508
    {
2509
  const xmlChar *nsName = NULL, *name = NULL;
2510
  const xmlChar *infnsName = NULL, *infname = NULL;
2511
2512
  if (node) {
2513
      if (node->type == XML_ELEMENT_NODE) {
2514
    name = node->name;
2515
    if (node->ns != NULL)
2516
        nsName = node->ns->href;
2517
    else
2518
        nsName = BAD_CAST "";
2519
      } else {
2520
    name = BAD_CAST "#document";
2521
    nsName = BAD_CAST "";
2522
      }
2523
  } else
2524
      name = BAD_CAST "Not given";
2525
2526
  if (cctxt->inode->node) {
2527
      if (node->type == XML_ELEMENT_NODE) {
2528
    infname = cctxt->inode->node->name;
2529
    if (cctxt->inode->node->ns != NULL)
2530
        infnsName = cctxt->inode->node->ns->href;
2531
    else
2532
        infnsName = BAD_CAST "";
2533
      } else {
2534
    infname = BAD_CAST "#document";
2535
    infnsName = BAD_CAST "";
2536
      }
2537
  } else
2538
      infname = BAD_CAST "Not given";
2539
2540
2541
  xmlGenericError(xmlGenericErrorContext,
2542
      "xsltCompilerNodePop: Given   : '%s' URI '%s'\n",
2543
      name, nsName);
2544
  xmlGenericError(xmlGenericErrorContext,
2545
      "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2546
      infname, infnsName);
2547
    }
2548
}
2549
2550
/*
2551
* xsltCompilerBuildInScopeNsList:
2552
*
2553
* Create and store the list of in-scope namespaces for the given
2554
* node in the stylesheet. If there are no changes in the in-scope
2555
* namespaces then the last ns-info of the ancestor axis will be returned.
2556
* Compilation-time only.
2557
*
2558
* Returns the ns-info or NULL if there are no namespaces in scope.
2559
*/
2560
static xsltNsListContainerPtr
2561
xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2562
{
2563
    xsltNsListContainerPtr nsi = NULL;
2564
    xmlNsPtr *list = NULL, ns;
2565
    int i, maxns = 5;
2566
    /*
2567
    * Create a new ns-list for this position in the node-tree.
2568
    * xmlGetNsList() will return NULL, if there are no ns-decls in the
2569
    * tree. Note that the ns-decl for the XML namespace is not added
2570
    * to the resulting list; the XPath module handles the XML namespace
2571
    * internally.
2572
    */
2573
    while (node != NULL) {
2574
        if (node->type == XML_ELEMENT_NODE) {
2575
            ns = node->nsDef;
2576
            while (ns != NULL) {
2577
                if (nsi == NULL) {
2578
        nsi = (xsltNsListContainerPtr)
2579
      xmlMalloc(sizeof(xsltNsListContainer));
2580
        if (nsi == NULL) {
2581
      xsltTransformError(NULL, cctxt->style, NULL,
2582
          "xsltCompilerBuildInScopeNsList: "
2583
          "malloc failed!\n");
2584
      goto internal_err;
2585
        }
2586
        memset(nsi, 0, sizeof(xsltNsListContainer));
2587
                    nsi->list =
2588
                        (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
2589
                    if (nsi->list == NULL) {
2590
      xsltTransformError(NULL, cctxt->style, NULL,
2591
          "xsltCompilerBuildInScopeNsList: "
2592
          "malloc failed!\n");
2593
      goto internal_err;
2594
                    }
2595
                    nsi->list[0] = NULL;
2596
                }
2597
    /*
2598
    * Skip shadowed namespace bindings.
2599
    */
2600
                for (i = 0; i < nsi->totalNumber; i++) {
2601
                    if ((ns->prefix == nsi->list[i]->prefix) ||
2602
                        (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
2603
        break;
2604
                }
2605
                if (i >= nsi->totalNumber) {
2606
                    if (nsi->totalNumber +1 >= maxns) {
2607
                        maxns *= 2;
2608
      nsi->list =
2609
          (xmlNsPtr *) xmlRealloc(nsi->list,
2610
        maxns * sizeof(xmlNsPtr));
2611
                        if (nsi->list == NULL) {
2612
                            xsltTransformError(NULL, cctxt->style, NULL,
2613
        "xsltCompilerBuildInScopeNsList: "
2614
        "realloc failed!\n");
2615
        goto internal_err;
2616
                        }
2617
                    }
2618
                    nsi->list[nsi->totalNumber++] = ns;
2619
                    nsi->list[nsi->totalNumber] = NULL;
2620
                }
2621
2622
                ns = ns->next;
2623
            }
2624
        }
2625
        node = node->parent;
2626
    }
2627
    if (nsi == NULL)
2628
  return(NULL);
2629
    /*
2630
    * Move the default namespace to last position.
2631
    */
2632
    nsi->xpathNumber = nsi->totalNumber;
2633
    for (i = 0; i < nsi->totalNumber; i++) {
2634
  if (nsi->list[i]->prefix == NULL) {
2635
      ns = nsi->list[i];
2636
      nsi->list[i] = nsi->list[nsi->totalNumber-1];
2637
      nsi->list[nsi->totalNumber-1] = ns;
2638
      nsi->xpathNumber--;
2639
      break;
2640
  }
2641
    }
2642
    /*
2643
    * Store the ns-list in the stylesheet.
2644
    */
2645
    if (xsltPointerListAddSize(
2646
  (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
2647
  (void *) nsi, 5) == -1)
2648
    {
2649
  xmlFree(nsi);
2650
  nsi = NULL;
2651
  xsltTransformError(NULL, cctxt->style, NULL,
2652
      "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2653
  goto internal_err;
2654
    }
2655
    /*
2656
    * Notify of change in status wrt namespaces.
2657
    */
2658
    if (cctxt->inode != NULL)
2659
  cctxt->inode->nsChanged = 1;
2660
2661
    return(nsi);
2662
2663
internal_err:
2664
    if (list != NULL)
2665
  xmlFree(list);
2666
    cctxt->style->errors++;
2667
    return(NULL);
2668
}
2669
2670
static int
2671
xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
2672
          xsltPointerListPtr list,
2673
          xmlNodePtr node,
2674
          const xmlChar *value)
2675
{
2676
    xmlChar *cur, *end;
2677
    xmlNsPtr ns;
2678
2679
    if ((cctxt == NULL) || (value == NULL) || (list == NULL))
2680
  return(-1);
2681
2682
    list->number = 0;
2683
2684
    cur = (xmlChar *) value;
2685
    while (*cur != 0) {
2686
  while (IS_BLANK(*cur)) cur++;
2687
  if (*cur == 0)
2688
      break;
2689
  end = cur;
2690
  while ((*end != 0) && (!IS_BLANK(*end))) end++;
2691
  cur = xmlStrndup(cur, end - cur);
2692
  if (cur == NULL) {
2693
      cur = end;
2694
      continue;
2695
  }
2696
  /*
2697
  * TODO: Export and use xmlSearchNsByPrefixStrict()
2698
  *   in Libxml2, tree.c, since xmlSearchNs() is in most
2699
  *   cases not efficient and in some cases not correct.
2700
  *
2701
  * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2702
  */
2703
  if ((cur[0] == '#') &&
2704
      xmlStrEqual(cur, (const xmlChar *)"#default"))
2705
      ns = xmlSearchNs(cctxt->style->doc, node, NULL);
2706
  else
2707
      ns = xmlSearchNs(cctxt->style->doc, node, cur);
2708
2709
  if (ns == NULL) {
2710
      /*
2711
      * TODO: Better to report the attr-node, otherwise
2712
      *  the user won't know which attribute was invalid.
2713
      */
2714
      xsltTransformError(NULL, cctxt->style, node,
2715
    "No namespace binding in scope for prefix '%s'.\n", cur);
2716
      /*
2717
      * XSLT-1.0: "It is an error if there is no namespace
2718
      *  bound to the prefix on the element bearing the
2719
      *  exclude-result-prefixes or xsl:exclude-result-prefixes
2720
      *  attribute."
2721
      */
2722
      cctxt->style->errors++;
2723
  } else {
2724
#ifdef WITH_XSLT_DEBUG_PARSING
2725
      xsltGenericDebug(xsltGenericDebugContext,
2726
    "resolved prefix '%s'\n", cur);
2727
#endif
2728
      /*
2729
      * Note that we put the namespace name into the dict.
2730
      */
2731
      if (xsltPointerListAddSize(list,
2732
    (void *) xmlDictLookup(cctxt->style->dict,
2733
    ns->href, -1), 5) == -1)
2734
      {
2735
    xmlFree(cur);
2736
    goto internal_err;
2737
      }
2738
  }
2739
  xmlFree(cur);
2740
2741
  cur = end;
2742
    }
2743
    return(0);
2744
2745
internal_err:
2746
    cctxt->style->errors++;
2747
    return(-1);
2748
}
2749
2750
/**
2751
 * xsltCompilerUtilsCreateMergedList:
2752
 * @dest: the destination list (optional)
2753
 * @first: the first list
2754
 * @second: the second list (optional)
2755
 *
2756
 * Appends the content of @second to @first into @destination.
2757
 * If @destination is NULL a new list will be created.
2758
 *
2759
 * Returns the merged list of items or NULL if there's nothing to merge.
2760
 */
2761
static xsltPointerListPtr
2762
xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
2763
          xsltPointerListPtr second)
2764
{
2765
    xsltPointerListPtr ret;
2766
    size_t num;
2767
2768
    if (first)
2769
  num = first->number;
2770
    else
2771
  num = 0;
2772
    if (second)
2773
  num += second->number;
2774
    if (num == 0)
2775
  return(NULL);
2776
    ret = xsltPointerListCreate(num);
2777
    if (ret == NULL)
2778
  return(NULL);
2779
    /*
2780
    * Copy contents.
2781
    */
2782
    if ((first != NULL) &&  (first->number != 0)) {
2783
  memcpy(ret->items, first->items,
2784
      first->number * sizeof(void *));
2785
  if ((second != NULL) && (second->number != 0))
2786
      memcpy(ret->items + first->number, second->items,
2787
    second->number * sizeof(void *));
2788
    } else if ((second != NULL) && (second->number != 0))
2789
  memcpy(ret->items, (void *) second->items,
2790
      second->number * sizeof(void *));
2791
    ret->number = num;
2792
    return(ret);
2793
}
2794
2795
/*
2796
* xsltParseExclResultPrefixes:
2797
*
2798
* Create and store the list of in-scope namespaces for the given
2799
* node in the stylesheet. If there are no changes in the in-scope
2800
* namespaces then the last ns-info of the ancestor axis will be returned.
2801
* Compilation-time only.
2802
*
2803
* Returns the ns-info or NULL if there are no namespaces in scope.
2804
*/
2805
static xsltPointerListPtr
2806
xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2807
          xsltPointerListPtr def,
2808
          int instrCategory)
2809
{
2810
    xsltPointerListPtr list = NULL;
2811
    xmlChar *value;
2812
    xmlAttrPtr attr;
2813
2814
    if ((cctxt == NULL) || (node == NULL))
2815
  return(NULL);
2816
2817
    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2818
  attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
2819
    else
2820
  attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
2821
      XSLT_NAMESPACE);
2822
    if (attr == NULL)
2823
  return(def);
2824
2825
    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2826
  /*
2827
  * Mark the XSLT attr.
2828
  */
2829
  attr->psvi = (void *) xsltXSLTAttrMarker;
2830
    }
2831
2832
    if ((attr->children != NULL) &&
2833
  (attr->children->content != NULL))
2834
  value = attr->children->content;
2835
    else {
2836
  xsltTransformError(NULL, cctxt->style, node,
2837
      "Attribute 'exclude-result-prefixes': Invalid value.\n");
2838
  cctxt->style->errors++;
2839
  return(def);
2840
    }
2841
2842
    if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2843
  BAD_CAST value) != 0)
2844
  goto exit;
2845
    if (cctxt->tmpList->number == 0)
2846
  goto exit;
2847
    /*
2848
    * Merge the list with the inherited list.
2849
    */
2850
    list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2851
    if (list == NULL)
2852
  goto exit;
2853
    /*
2854
    * Store the list in the stylesheet/compiler context.
2855
    */
2856
    if (xsltPointerListAddSize(
2857
  cctxt->psData->exclResultNamespaces, list, 5) == -1)
2858
    {
2859
  xsltPointerListFree(list);
2860
  list = NULL;
2861
  goto exit;
2862
    }
2863
    /*
2864
    * Notify of change in status wrt namespaces.
2865
    */
2866
    if (cctxt->inode != NULL)
2867
  cctxt->inode->nsChanged = 1;
2868
2869
exit:
2870
    if (list != NULL)
2871
  return(list);
2872
    else
2873
  return(def);
2874
}
2875
2876
/*
2877
* xsltParseExtElemPrefixes:
2878
*
2879
* Create and store the list of in-scope namespaces for the given
2880
* node in the stylesheet. If there are no changes in the in-scope
2881
* namespaces then the last ns-info of the ancestor axis will be returned.
2882
* Compilation-time only.
2883
*
2884
* Returns the ns-info or NULL if there are no namespaces in scope.
2885
*/
2886
static xsltPointerListPtr
2887
xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2888
       xsltPointerListPtr def,
2889
       int instrCategory)
2890
{
2891
    xsltPointerListPtr list = NULL;
2892
    xmlAttrPtr attr;
2893
    xmlChar *value;
2894
    int i;
2895
2896
    if ((cctxt == NULL) || (node == NULL))
2897
  return(NULL);
2898
2899
    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2900
  attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
2901
    else
2902
  attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
2903
      XSLT_NAMESPACE);
2904
    if (attr == NULL)
2905
  return(def);
2906
2907
    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2908
  /*
2909
  * Mark the XSLT attr.
2910
  */
2911
  attr->psvi = (void *) xsltXSLTAttrMarker;
2912
    }
2913
2914
    if ((attr->children != NULL) &&
2915
  (attr->children->content != NULL))
2916
  value = attr->children->content;
2917
    else {
2918
  xsltTransformError(NULL, cctxt->style, node,
2919
      "Attribute 'extension-element-prefixes': Invalid value.\n");
2920
  cctxt->style->errors++;
2921
  return(def);
2922
    }
2923
2924
2925
    if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2926
  BAD_CAST value) != 0)
2927
  goto exit;
2928
2929
    if (cctxt->tmpList->number == 0)
2930
  goto exit;
2931
    /*
2932
    * REVISIT: Register the extension namespaces.
2933
    */
2934
    for (i = 0; i < cctxt->tmpList->number; i++)
2935
  xsltRegisterExtPrefix(cctxt->style, NULL,
2936
  BAD_CAST cctxt->tmpList->items[i]);
2937
    /*
2938
    * Merge the list with the inherited list.
2939
    */
2940
    list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2941
    if (list == NULL)
2942
  goto exit;
2943
    /*
2944
    * Store the list in the stylesheet.
2945
    */
2946
    if (xsltPointerListAddSize(
2947
  cctxt->psData->extElemNamespaces, list, 5) == -1)
2948
    {
2949
  xsltPointerListFree(list);
2950
  list = NULL;
2951
  goto exit;
2952
    }
2953
    /*
2954
    * Notify of change in status wrt namespaces.
2955
    */
2956
    if (cctxt->inode != NULL)
2957
  cctxt->inode->nsChanged = 1;
2958
2959
exit:
2960
    if (list != NULL)
2961
  return(list);
2962
    else
2963
  return(def);
2964
}
2965
2966
/*
2967
* xsltParseAttrXSLTVersion:
2968
*
2969
* @cctxt: the compilation context
2970
* @node: the element-node
2971
* @isXsltElem: whether this is an XSLT element
2972
*
2973
* Parses the attribute xsl:version.
2974
*
2975
* Returns 1 if there was such an attribute, 0 if not and
2976
*         -1 if an internal or API error occured.
2977
*/
2978
static int
2979
xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2980
       int instrCategory)
2981
{
2982
    xmlChar *value;
2983
    xmlAttrPtr attr;
2984
2985
    if ((cctxt == NULL) || (node == NULL))
2986
  return(-1);
2987
2988
    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2989
  attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
2990
    else
2991
  attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
2992
2993
    if (attr == NULL)
2994
  return(0);
2995
2996
    attr->psvi = (void *) xsltXSLTAttrMarker;
2997
2998
    if ((attr->children != NULL) &&
2999
  (attr->children->content != NULL))
3000
  value = attr->children->content;
3001
    else {
3002
  xsltTransformError(NULL, cctxt->style, node,
3003
      "Attribute 'version': Invalid value.\n");
3004
  cctxt->style->errors++;
3005
  return(1);
3006
    }
3007
3008
    if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
3009
  cctxt->inode->forwardsCompat = 1;
3010
  /*
3011
  * TODO: To what extent do we support the
3012
  *  forwards-compatible mode?
3013
  */
3014
  /*
3015
  * Report this only once per compilation episode.
3016
  */
3017
  if (! cctxt->hasForwardsCompat) {
3018
      cctxt->hasForwardsCompat = 1;
3019
      cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
3020
      xsltTransformError(NULL, cctxt->style, node,
3021
    "Warning: the attribute xsl:version specifies a value "
3022
    "different from '1.0'. Switching to forwards-compatible "
3023
    "mode. Only features of XSLT 1.0 are supported by this "
3024
    "processor.\n");
3025
      cctxt->style->warnings++;
3026
      cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
3027
  }
3028
    } else {
3029
  cctxt->inode->forwardsCompat = 0;
3030
    }
3031
3032
    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
3033
  /*
3034
  * Set a marker on XSLT attributes.
3035
  */
3036
  attr->psvi = (void *) xsltXSLTAttrMarker;
3037
    }
3038
    return(1);
3039
}
3040
3041
static int
3042
xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
3043
{
3044
    xmlNodePtr deleteNode, cur, txt, textNode = NULL;
3045
    xmlDocPtr doc;
3046
    xsltStylesheetPtr style;
3047
    int internalize = 0, findSpaceAttr;
3048
    int xsltStylesheetElemDepth;
3049
    xmlAttrPtr attr;
3050
    xmlChar *value;
3051
    const xmlChar *name, *nsNameXSLT = NULL;
3052
    int strictWhitespace, inXSLText = 0;
3053
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
3054
    xsltNsMapPtr nsMapItem;
3055
#endif
3056
3057
    if ((cctxt == NULL) || (cctxt->style == NULL) ||
3058
  (node == NULL) || (node->type != XML_ELEMENT_NODE))
3059
        return(-1);
3060
3061
    doc = node->doc;
3062
    if (doc == NULL)
3063
  goto internal_err;
3064
3065
    style = cctxt->style;
3066
    if ((style->dict != NULL) && (doc->dict == style->dict))
3067
  internalize = 1;
3068
    else
3069
        style->internalized = 0;
3070
3071
    /*
3072
    * Init value of xml:space. Since this might be an embedded
3073
    * stylesheet, this is needed to be performed on the element
3074
    * where the stylesheet is rooted at, taking xml:space of
3075
    * ancestors into account.
3076
    */
3077
    if (! cctxt->simplified)
3078
  xsltStylesheetElemDepth = cctxt->depth +1;
3079
    else
3080
  xsltStylesheetElemDepth = 0;
3081
3082
    if (xmlNodeGetSpacePreserve(node) != 1)
3083
  cctxt->inode->preserveWhitespace = 0;
3084
    else
3085
  cctxt->inode->preserveWhitespace = 1;
3086
3087
    /*
3088
    * Eval if we should keep the old incorrect behaviour.
3089
    */
3090
    strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
3091
3092
    nsNameXSLT = xsltConstNamespaceNameXSLT;
3093
3094
    deleteNode = NULL;
3095
    cur = node;
3096
    while (cur != NULL) {
3097
  if (deleteNode != NULL) {
3098
3099
#ifdef WITH_XSLT_DEBUG_BLANKS
3100
      xsltGenericDebug(xsltGenericDebugContext,
3101
       "xsltParsePreprocessStylesheetTree: removing node\n");
3102
#endif
3103
      xmlUnlinkNode(deleteNode);
3104
      xmlFreeNode(deleteNode);
3105
      deleteNode = NULL;
3106
  }
3107
  if (cur->type == XML_ELEMENT_NODE) {
3108
3109
      /*
3110
      * Clear the PSVI field.
3111
      */
3112
      cur->psvi = NULL;
3113
3114
      xsltCompilerNodePush(cctxt, cur);
3115
3116
      inXSLText = 0;
3117
      textNode = NULL;
3118
      findSpaceAttr = 1;
3119
      cctxt->inode->stripWhitespace = 0;
3120
      /*
3121
      * TODO: I'd love to use a string pointer comparison here :-/
3122
      */
3123
      if (IS_XSLT_ELEM(cur)) {
3124
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
3125
    if (cur->ns->href != nsNameXSLT) {
3126
        nsMapItem = xsltNewNamespaceMapItem(cctxt,
3127
      doc, cur->ns, cur);
3128
        if (nsMapItem == NULL)
3129
      goto internal_err;
3130
        cur->ns->href = nsNameXSLT;
3131
    }
3132
#endif
3133
3134
    if (cur->name == NULL)
3135
        goto process_attributes;
3136
    /*
3137
    * Mark the XSLT element for later recognition.
3138
    * TODO: Using the marker is still too dangerous, since if
3139
    *   the parsing mechanism leaves out an XSLT element, then
3140
    *   this might hit the transformation-mechanism, which
3141
    *   will break if it doesn't expect such a marker.
3142
    */
3143
    /* cur->psvi = (void *) xsltXSLTElemMarker; */
3144
3145
    /*
3146
    * XSLT 2.0: "Any whitespace text node whose parent is
3147
    * one of the following elements is removed from the "
3148
    * tree, regardless of any xml:space attributes:..."
3149
    * xsl:apply-imports,
3150
    * xsl:apply-templates,
3151
    * xsl:attribute-set,
3152
    * xsl:call-template,
3153
    * xsl:choose,
3154
    * xsl:stylesheet, xsl:transform.
3155
    * XSLT 2.0: xsl:analyze-string,
3156
    *           xsl:character-map,
3157
    *           xsl:next-match
3158
    *
3159
    * TODO: I'd love to use a string pointer comparison here :-/
3160
    */
3161
    name = cur->name;
3162
    switch (*name) {
3163
        case 't':
3164
      if ((name[0] == 't') && (name[1] == 'e') &&
3165
          (name[2] == 'x') && (name[3] == 't') &&
3166
          (name[4] == 0))
3167
      {
3168
          /*
3169
          * Process the xsl:text element.
3170
          * ----------------------------
3171
          * Mark it for later recognition.
3172
          */
3173
          cur->psvi = (void *) xsltXSLTTextMarker;
3174
          /*
3175
          * For stylesheets, the set of
3176
          * whitespace-preserving element names
3177
          * consists of just xsl:text.
3178
          */
3179
          findSpaceAttr = 0;
3180
          cctxt->inode->preserveWhitespace = 1;
3181
          inXSLText = 1;
3182
      }
3183
      break;
3184
        case 'c':
3185
      if (xmlStrEqual(name, BAD_CAST "choose") ||
3186
          xmlStrEqual(name, BAD_CAST "call-template"))
3187
          cctxt->inode->stripWhitespace = 1;
3188
      break;
3189
        case 'a':
3190
      if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
3191
          xmlStrEqual(name, BAD_CAST "apply-imports") ||
3192
          xmlStrEqual(name, BAD_CAST "attribute-set"))
3193
3194
          cctxt->inode->stripWhitespace = 1;
3195
      break;
3196
        default:
3197
      if (xsltStylesheetElemDepth == cctxt->depth) {
3198
          /*
3199
          * This is a xsl:stylesheet/xsl:transform.
3200
          */
3201
          cctxt->inode->stripWhitespace = 1;
3202
          break;
3203
      }
3204
3205
      if ((cur->prev != NULL) &&
3206
          (cur->prev->type == XML_TEXT_NODE))
3207
      {
3208
          /*
3209
          * XSLT 2.0 : "Any whitespace text node whose
3210
          *  following-sibling node is an xsl:param or
3211
          *  xsl:sort element is removed from the tree,
3212
          *  regardless of any xml:space attributes."
3213
          */
3214
          if (((*name == 'p') || (*name == 's')) &&
3215
        (xmlStrEqual(name, BAD_CAST "param") ||
3216
         xmlStrEqual(name, BAD_CAST "sort")))
3217
          {
3218
        do {
3219
            if (IS_BLANK_NODE(cur->prev)) {
3220
          txt = cur->prev;
3221
          xmlUnlinkNode(txt);
3222
          xmlFreeNode(txt);
3223
            } else {
3224
          /*
3225
          * This will result in a content
3226
          * error, when hitting the parsing
3227
          * functions.
3228
          */
3229
          break;
3230
            }
3231
        } while (cur->prev);
3232
          }
3233
      }
3234
      break;
3235
    }
3236
      }
3237
3238
process_attributes:
3239
      /*
3240
      * Process attributes.
3241
      * ------------------
3242
      */
3243
      if (cur->properties != NULL) {
3244
    if (cur->children == NULL)
3245
        findSpaceAttr = 0;
3246
    attr = cur->properties;
3247
    do {
3248
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
3249
        if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
3250
      xmlStrEqual(attr->ns->href, nsNameXSLT))
3251
        {
3252
      nsMapItem = xsltNewNamespaceMapItem(cctxt,
3253
          doc, attr->ns, cur);
3254
      if (nsMapItem == NULL)
3255
          goto internal_err;
3256
      attr->ns->href = nsNameXSLT;
3257
        }
3258
#endif
3259
        if (internalize) {
3260
      /*
3261
      * Internalize the attribute's value; the goal is to
3262
      * speed up operations and minimize used space by
3263
      * compiled stylesheets.
3264
      */
3265
      txt = attr->children;
3266
      /*
3267
      * NOTE that this assumes only one
3268
      *  text-node in the attribute's content.
3269
      */
3270
      if ((txt != NULL) && (txt->content != NULL) &&
3271
          (!xmlDictOwns(style->dict, txt->content)))
3272
      {
3273
          value = (xmlChar *) xmlDictLookup(style->dict,
3274
        txt->content, -1);
3275
          xmlNodeSetContent(txt, NULL);
3276
          txt->content = value;
3277
      }
3278
        }
3279
        /*
3280
        * Process xml:space attributes.
3281
        * ----------------------------
3282
        */
3283
        if ((findSpaceAttr != 0) &&
3284
      (attr->ns != NULL) &&
3285
      (attr->name != NULL) &&
3286
      (attr->name[0] == 's') &&
3287
      (attr->ns->prefix != NULL) &&
3288
      (attr->ns->prefix[0] == 'x') &&
3289
      (attr->ns->prefix[1] == 'm') &&
3290
      (attr->ns->prefix[2] == 'l') &&
3291
      (attr->ns->prefix[3] == 0))
3292
        {
3293
      value = xmlGetNsProp(cur, BAD_CAST "space",
3294
          XML_XML_NAMESPACE);
3295
      if (value != NULL) {
3296
          if (xmlStrEqual(value, BAD_CAST "preserve")) {
3297
        cctxt->inode->preserveWhitespace = 1;
3298
          } else if (xmlStrEqual(value, BAD_CAST "default")) {
3299
        cctxt->inode->preserveWhitespace = 0;
3300
          } else {
3301
        /* Invalid value for xml:space. */
3302
        xsltTransformError(NULL, style, cur,
3303
            "Attribute xml:space: Invalid value.\n");
3304
        cctxt->style->warnings++;
3305
          }
3306
          findSpaceAttr = 0;
3307
          xmlFree(value);
3308
      }
3309
3310
        }
3311
        attr = attr->next;
3312
    } while (attr != NULL);
3313
      }
3314
      /*
3315
      * We'll descend into the children of element nodes only.
3316
      */
3317
      if (cur->children != NULL) {
3318
    cur = cur->children;
3319
    continue;
3320
      }
3321
  } else if ((cur->type == XML_TEXT_NODE) ||
3322
    (cur->type == XML_CDATA_SECTION_NODE))
3323
  {
3324
      /*
3325
      * Merge adjacent text/CDATA-section-nodes
3326
      * ---------------------------------------
3327
      * In order to avoid breaking of existing stylesheets,
3328
      * if the old behaviour is wanted (strictWhitespace == 0),
3329
      * then we *won't* merge adjacent text-nodes
3330
      * (except in xsl:text); this will ensure that whitespace-only
3331
      * text nodes are (incorrectly) not stripped in some cases.
3332
      *
3333
      * Example:               : <foo>  <!-- bar -->zoo</foo>
3334
      * Corrent (strict) result: <foo>  zoo</foo>
3335
      * Incorrect (old) result : <foo>zoo</foo>
3336
      *
3337
      * NOTE that we *will* merge adjacent text-nodes if
3338
      * they are in xsl:text.
3339
      * Example, the following:
3340
      * <xsl:text>  <!-- bar -->zoo<xsl:text>
3341
      * will result in both cases in:
3342
      * <xsl:text>  zoo<xsl:text>
3343
      */
3344
      cur->type = XML_TEXT_NODE;
3345
      if ((strictWhitespace != 0) || (inXSLText != 0)) {
3346
    /*
3347
    * New behaviour; merge nodes.
3348
    */
3349
    if (textNode == NULL)
3350
        textNode = cur;
3351
    else {
3352
        if (cur->content != NULL)
3353
      xmlNodeAddContent(textNode, cur->content);
3354
        deleteNode = cur;
3355
    }
3356
    if ((cur->next == NULL) ||
3357
        (cur->next->type == XML_ELEMENT_NODE))
3358
        goto end_of_text;
3359
    else
3360
        goto next_sibling;
3361
      } else {
3362
    /*
3363
    * Old behaviour.
3364
    */
3365
    if (textNode == NULL)
3366
        textNode = cur;
3367
    goto end_of_text;
3368
      }
3369
  } else if ((cur->type == XML_COMMENT_NODE) ||
3370
      (cur->type == XML_PI_NODE))
3371
  {
3372
      /*
3373
      * Remove processing instructions and comments.
3374
      */
3375
      deleteNode = cur;
3376
      if ((cur->next == NULL) ||
3377
    (cur->next->type == XML_ELEMENT_NODE))
3378
    goto end_of_text;
3379
      else
3380
    goto next_sibling;
3381
  } else {
3382
      textNode = NULL;
3383
      /*
3384
      * Invalid node-type for this data-model.
3385
      */
3386
      xsltTransformError(NULL, style, cur,
3387
    "Invalid type of node for the XSLT data model.\n");
3388
      cctxt->style->errors++;
3389
      goto next_sibling;
3390
  }
3391
3392
end_of_text:
3393
  if (textNode) {
3394
      value = textNode->content;
3395
      /*
3396
      * At this point all adjacent text/CDATA-section nodes
3397
      * have been merged.
3398
      *
3399
      * Strip whitespace-only text-nodes.
3400
      * (cctxt->inode->stripWhitespace)
3401
      */
3402
      if ((value == NULL) || (*value == 0) ||
3403
    (((cctxt->inode->stripWhitespace) ||
3404
      (! cctxt->inode->preserveWhitespace)) &&
3405
     IS_BLANK(*value) &&
3406
     xsltIsBlank(value)))
3407
      {
3408
    if (textNode != cur) {
3409
        xmlUnlinkNode(textNode);
3410
        xmlFreeNode(textNode);
3411
    } else
3412
        deleteNode = textNode;
3413
    textNode = NULL;
3414
    goto next_sibling;
3415
      }
3416
      /*
3417
      * Convert CDATA-section nodes to text-nodes.
3418
      * TODO: Can this produce problems?
3419
      */
3420
      if (textNode->type != XML_TEXT_NODE) {
3421
    textNode->type = XML_TEXT_NODE;
3422
    textNode->name = xmlStringText;
3423
      }
3424
      if (internalize &&
3425
    (textNode->content != NULL) &&
3426
    (!xmlDictOwns(style->dict, textNode->content)))
3427
      {
3428
    /*
3429
    * Internalize the string.
3430
    */
3431
    value = (xmlChar *) xmlDictLookup(style->dict,
3432
        textNode->content, -1);
3433
    xmlNodeSetContent(textNode, NULL);
3434
    textNode->content = value;
3435
      }
3436
      textNode = NULL;
3437
      /*
3438
      * Note that "disable-output-escaping" of the xsl:text
3439
      * element will be applied at a later level, when
3440
      * XSLT elements are processed.
3441
      */
3442
  }
3443
3444
next_sibling:
3445
  if (cur->type == XML_ELEMENT_NODE) {
3446
      xsltCompilerNodePop(cctxt, cur);
3447
  }
3448
  if (cur == node)
3449
      break;
3450
  if (cur->next != NULL) {
3451
      cur = cur->next;
3452
  } else {
3453
      cur = cur->parent;
3454
      inXSLText = 0;
3455
      goto next_sibling;
3456
  };
3457
    }
3458
    if (deleteNode != NULL) {
3459
#ifdef WITH_XSLT_DEBUG_PARSING
3460
  xsltGenericDebug(xsltGenericDebugContext,
3461
   "xsltParsePreprocessStylesheetTree: removing node\n");
3462
#endif
3463
  xmlUnlinkNode(deleteNode);
3464
  xmlFreeNode(deleteNode);
3465
    }
3466
    return(0);
3467
3468
internal_err:
3469
    return(-1);
3470
}
3471
3472
#endif /* XSLT_REFACTORED */
3473
3474
#ifdef XSLT_REFACTORED
3475
#else
3476
static void
3477
xsltPreprocessStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
3478
8.57k
{
3479
8.57k
    xmlNodePtr deleteNode, styleelem;
3480
8.57k
    int internalize = 0;
3481
3482
8.57k
    if ((style == NULL) || (cur == NULL))
3483
0
        return;
3484
3485
8.57k
    if ((cur->doc != NULL) && (style->dict != NULL) &&
3486
8.57k
        (cur->doc->dict == style->dict))
3487
8.57k
  internalize = 1;
3488
0
    else
3489
0
        style->internalized = 0;
3490
3491
8.57k
    if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
3492
8.57k
        (IS_XSLT_NAME(cur, "stylesheet"))) {
3493
8.46k
  styleelem = cur;
3494
8.46k
    } else {
3495
106
        styleelem = NULL;
3496
106
    }
3497
3498
    /*
3499
     * This content comes from the stylesheet
3500
     * For stylesheets, the set of whitespace-preserving
3501
     * element names consists of just xsl:text.
3502
     */
3503
8.57k
    deleteNode = NULL;
3504
3.33M
    while (cur != NULL) {
3505
3.32M
  if (deleteNode != NULL) {
3506
#ifdef WITH_XSLT_DEBUG_BLANKS
3507
      xsltGenericDebug(xsltGenericDebugContext,
3508
       "xsltPreprocessStylesheet: removing ignorable blank node\n");
3509
#endif
3510
424k
      xmlUnlinkNode(deleteNode);
3511
424k
      xmlFreeNode(deleteNode);
3512
424k
      deleteNode = NULL;
3513
424k
  }
3514
3.32M
  if (cur->type == XML_ELEMENT_NODE) {
3515
1.88M
      int exclPrefixes;
3516
      /*
3517
       * Internalize attributes values.
3518
       */
3519
1.88M
      if ((internalize) && (cur->properties != NULL)) {
3520
281k
          xmlAttrPtr attr = cur->properties;
3521
281k
    xmlNodePtr txt;
3522
3523
593k
    while (attr != NULL) {
3524
312k
        txt = attr->children;
3525
312k
        if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
3526
312k
            (txt->content != NULL) &&
3527
312k
      (!xmlDictOwns(style->dict, txt->content)))
3528
184k
        {
3529
184k
      xmlChar *tmp;
3530
3531
      /*
3532
       * internalize the text string, goal is to speed
3533
       * up operations and minimize used space by compiled
3534
       * stylesheets.
3535
       */
3536
184k
      tmp = (xmlChar *) xmlDictLookup(style->dict,
3537
184k
                                      txt->content, -1);
3538
184k
      if (tmp != txt->content) {
3539
184k
          xmlNodeSetContent(txt, NULL);
3540
184k
          txt->content = tmp;
3541
184k
      }
3542
184k
        }
3543
312k
        attr = attr->next;
3544
312k
    }
3545
281k
      }
3546
1.88M
      if (IS_XSLT_ELEM(cur)) {
3547
143k
    exclPrefixes = 0;
3548
143k
    if (IS_XSLT_NAME(cur, "text")) {
3549
6.69k
        for (;exclPrefixes > 0;exclPrefixes--)
3550
0
      exclPrefixPop(style);
3551
6.69k
        goto skip_children;
3552
6.69k
    }
3553
1.74M
      } else {
3554
1.74M
    exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
3555
1.74M
      }
3556
3557
1.88M
      if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
3558
562
    xmlNsPtr ns = cur->nsDef, prev = NULL, next;
3559
562
    xmlNodePtr root = NULL;
3560
562
    int i, moved;
3561
3562
562
    root = xmlDocGetRootElement(cur->doc);
3563
562
    if ((root != NULL) && (root != cur)) {
3564
828
        while (ns != NULL) {
3565
526
      moved = 0;
3566
526
      next = ns->next;
3567
928
      for (i = 0;i < style->exclPrefixNr;i++) {
3568
526
          if ((ns->prefix != NULL) &&
3569
526
              (xmlStrEqual(ns->href,
3570
320
               style->exclPrefixTab[i]))) {
3571
        /*
3572
         * Move the namespace definition on the root
3573
         * element to avoid duplicating it without
3574
         * loosing it.
3575
         */
3576
124
        if (prev == NULL) {
3577
28
            cur->nsDef = ns->next;
3578
96
        } else {
3579
96
            prev->next = ns->next;
3580
96
        }
3581
124
        ns->next = root->nsDef;
3582
124
        root->nsDef = ns;
3583
124
        moved = 1;
3584
124
        break;
3585
124
          }
3586
526
      }
3587
526
      if (moved == 0)
3588
402
          prev = ns;
3589
526
      ns = next;
3590
526
        }
3591
302
    }
3592
562
      }
3593
      /*
3594
       * If we have prefixes locally, recurse and pop them up when
3595
       * going back
3596
       */
3597
1.88M
      if (exclPrefixes > 0) {
3598
0
    xsltPreprocessStylesheet(style, cur->children);
3599
0
    for (;exclPrefixes > 0;exclPrefixes--)
3600
0
        exclPrefixPop(style);
3601
0
    goto skip_children;
3602
0
      }
3603
1.88M
  } else if (cur->type == XML_TEXT_NODE) {
3604
1.42M
      if (IS_BLANK_NODE(cur)) {
3605
421k
    if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
3606
421k
        deleteNode = cur;
3607
421k
    }
3608
1.00M
      } else if ((cur->content != NULL) && (internalize) &&
3609
1.00M
                 (!xmlDictOwns(style->dict, cur->content))) {
3610
613k
    xmlChar *tmp;
3611
3612
    /*
3613
     * internalize the text string, goal is to speed
3614
     * up operations and minimize used space by compiled
3615
     * stylesheets.
3616
     */
3617
613k
    tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
3618
613k
    xmlNodeSetContent(cur, NULL);
3619
613k
    cur->content = tmp;
3620
613k
      }
3621
1.42M
  } else if ((cur->type != XML_ELEMENT_NODE) &&
3622
10.4k
       (cur->type != XML_CDATA_SECTION_NODE)) {
3623
10.4k
      deleteNode = cur;
3624
10.4k
      goto skip_children;
3625
10.4k
  }
3626
3627
  /*
3628
   * Skip to next node. In case of a namespaced element children of
3629
   * the stylesheet and not in the XSLT namespace and not an extension
3630
   * element, ignore its content.
3631
   */
3632
3.30M
  if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
3633
3.30M
      (styleelem != NULL) && (cur->parent == styleelem) &&
3634
3.30M
      (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
3635
3.30M
      (!xsltCheckExtURI(style, cur->ns->href))) {
3636
439
      goto skip_children;
3637
3.30M
  } else if (cur->children != NULL) {
3638
778k
      cur = cur->children;
3639
778k
      continue;
3640
778k
  }
3641
3642
2.54M
skip_children:
3643
2.54M
  if (cur->next != NULL) {
3644
1.96M
      cur = cur->next;
3645
1.96M
      continue;
3646
1.96M
  }
3647
787k
  do {
3648
3649
787k
      cur = cur->parent;
3650
787k
      if (cur == NULL)
3651
0
    break;
3652
787k
      if (cur == (xmlNodePtr) style->doc) {
3653
8.57k
    cur = NULL;
3654
8.57k
    break;
3655
8.57k
      }
3656
778k
      if (cur->next != NULL) {
3657
578k
    cur = cur->next;
3658
578k
    break;
3659
578k
      }
3660
778k
  } while (cur != NULL);
3661
587k
    }
3662
8.57k
    if (deleteNode != NULL) {
3663
#ifdef WITH_XSLT_DEBUG_PARSING
3664
  xsltGenericDebug(xsltGenericDebugContext,
3665
   "xsltPreprocessStylesheet: removing ignorable blank node\n");
3666
#endif
3667
7.30k
  xmlUnlinkNode(deleteNode);
3668
7.30k
  xmlFreeNode(deleteNode);
3669
7.30k
    }
3670
8.57k
}
3671
#endif /* end of else XSLT_REFACTORED */
3672
3673
/**
3674
 * xsltGatherNamespaces:
3675
 * @style:  the XSLT stylesheet
3676
 *
3677
 * Browse the stylesheet and build the namspace hash table which
3678
 * will be used for XPath interpretation. If needed do a bit of normalization
3679
 */
3680
3681
static void
3682
7.39k
xsltGatherNamespaces(xsltStylesheetPtr style) {
3683
7.39k
    xmlNodePtr cur;
3684
7.39k
    const xmlChar *URI;
3685
3686
7.39k
    if (style == NULL)
3687
0
        return;
3688
    /*
3689
     * TODO: basically if the stylesheet uses the same prefix for different
3690
     *       patterns, well they may be in problem, hopefully they will get
3691
     *       a warning first.
3692
     */
3693
    /*
3694
    * TODO: Eliminate the use of the hash for XPath expressions.
3695
    *   An expression should be evaluated in the context of the in-scope
3696
    *   namespaces; eliminate the restriction of an XML document to contain
3697
    *   no duplicate prefixes for different namespace names.
3698
    *
3699
    */
3700
7.39k
    cur = xmlDocGetRootElement(style->doc);
3701
7.39k
    while (cur != NULL) {
3702
0
  if (cur->type == XML_ELEMENT_NODE) {
3703
0
      xmlNsPtr ns = cur->nsDef;
3704
0
      while (ns != NULL) {
3705
0
    if (ns->prefix != NULL) {
3706
0
        if (style->nsHash == NULL) {
3707
0
      style->nsHash = xmlHashCreate(10);
3708
0
      if (style->nsHash == NULL) {
3709
0
          xsltTransformError(NULL, style, cur,
3710
0
     "xsltGatherNamespaces: failed to create hash table\n");
3711
0
          style->errors++;
3712
0
          return;
3713
0
      }
3714
0
        }
3715
0
        URI = xmlHashLookup(style->nsHash, ns->prefix);
3716
0
        if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3717
0
      xsltTransformError(NULL, style, cur,
3718
0
       "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3719
0
      style->warnings++;
3720
0
        } else if (URI == NULL) {
3721
0
      xmlHashUpdateEntry(style->nsHash, ns->prefix,
3722
0
          (void *) ns->href, NULL);
3723
3724
#ifdef WITH_XSLT_DEBUG_PARSING
3725
      xsltGenericDebug(xsltGenericDebugContext,
3726
     "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
3727
#endif
3728
0
        }
3729
0
    }
3730
0
    ns = ns->next;
3731
0
      }
3732
0
  }
3733
3734
  /*
3735
   * Skip to next node
3736
   */
3737
0
  if (cur->children != NULL) {
3738
0
      if (cur->children->type != XML_ENTITY_DECL) {
3739
0
    cur = cur->children;
3740
0
    continue;
3741
0
      }
3742
0
  }
3743
0
  if (cur->next != NULL) {
3744
0
      cur = cur->next;
3745
0
      continue;
3746
0
  }
3747
3748
0
  do {
3749
0
      cur = cur->parent;
3750
0
      if (cur == NULL)
3751
0
    break;
3752
0
      if (cur == (xmlNodePtr) style->doc) {
3753
0
    cur = NULL;
3754
0
    break;
3755
0
      }
3756
0
      if (cur->next != NULL) {
3757
0
    cur = cur->next;
3758
0
    break;
3759
0
      }
3760
0
  } while (cur != NULL);
3761
0
    }
3762
7.39k
}
3763
3764
#ifdef XSLT_REFACTORED
3765
3766
static xsltStyleType
3767
xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
3768
           xmlNodePtr node)
3769
{
3770
    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
3771
  (node->name == NULL))
3772
  return(0);
3773
3774
    if (node->name[0] == 'a') {
3775
  if (IS_XSLT_NAME(node, "apply-templates"))
3776
      return(XSLT_FUNC_APPLYTEMPLATES);
3777
  else if (IS_XSLT_NAME(node, "attribute"))
3778
      return(XSLT_FUNC_ATTRIBUTE);
3779
  else if (IS_XSLT_NAME(node, "apply-imports"))
3780
      return(XSLT_FUNC_APPLYIMPORTS);
3781
  else if (IS_XSLT_NAME(node, "attribute-set"))
3782
      return(0);
3783
3784
    } else if (node->name[0] == 'c') {
3785
  if (IS_XSLT_NAME(node, "choose"))
3786
      return(XSLT_FUNC_CHOOSE);
3787
  else if (IS_XSLT_NAME(node, "copy"))
3788
      return(XSLT_FUNC_COPY);
3789
  else if (IS_XSLT_NAME(node, "copy-of"))
3790
      return(XSLT_FUNC_COPYOF);
3791
  else if (IS_XSLT_NAME(node, "call-template"))
3792
      return(XSLT_FUNC_CALLTEMPLATE);
3793
  else if (IS_XSLT_NAME(node, "comment"))
3794
      return(XSLT_FUNC_COMMENT);
3795
3796
    } else if (node->name[0] == 'd') {
3797
  if (IS_XSLT_NAME(node, "document"))
3798
      return(XSLT_FUNC_DOCUMENT);
3799
  else if (IS_XSLT_NAME(node, "decimal-format"))
3800
      return(0);
3801
3802
    } else if (node->name[0] == 'e') {
3803
  if (IS_XSLT_NAME(node, "element"))
3804
      return(XSLT_FUNC_ELEMENT);
3805
3806
    } else if (node->name[0] == 'f') {
3807
  if (IS_XSLT_NAME(node, "for-each"))
3808
      return(XSLT_FUNC_FOREACH);
3809
  else if (IS_XSLT_NAME(node, "fallback"))
3810
      return(XSLT_FUNC_FALLBACK);
3811
3812
    } else if (*(node->name) == 'i') {
3813
  if (IS_XSLT_NAME(node, "if"))
3814
      return(XSLT_FUNC_IF);
3815
  else if (IS_XSLT_NAME(node, "include"))
3816
      return(0);
3817
  else if (IS_XSLT_NAME(node, "import"))
3818
      return(0);
3819
3820
    } else if (*(node->name) == 'k') {
3821
  if (IS_XSLT_NAME(node, "key"))
3822
      return(0);
3823
3824
    } else if (*(node->name) == 'm') {
3825
  if (IS_XSLT_NAME(node, "message"))
3826
      return(XSLT_FUNC_MESSAGE);
3827
3828
    } else if (*(node->name) == 'n') {
3829
  if (IS_XSLT_NAME(node, "number"))
3830
      return(XSLT_FUNC_NUMBER);
3831
  else if (IS_XSLT_NAME(node, "namespace-alias"))
3832
      return(0);
3833
3834
    } else if (*(node->name) == 'o') {
3835
  if (IS_XSLT_NAME(node, "otherwise"))
3836
      return(XSLT_FUNC_OTHERWISE);
3837
  else if (IS_XSLT_NAME(node, "output"))
3838
      return(0);
3839
3840
    } else if (*(node->name) == 'p') {
3841
  if (IS_XSLT_NAME(node, "param"))
3842
      return(XSLT_FUNC_PARAM);
3843
  else if (IS_XSLT_NAME(node, "processing-instruction"))
3844
      return(XSLT_FUNC_PI);
3845
  else if (IS_XSLT_NAME(node, "preserve-space"))
3846
      return(0);
3847
3848
    } else if (*(node->name) == 's') {
3849
  if (IS_XSLT_NAME(node, "sort"))
3850
      return(XSLT_FUNC_SORT);
3851
  else if (IS_XSLT_NAME(node, "strip-space"))
3852
      return(0);
3853
  else if (IS_XSLT_NAME(node, "stylesheet"))
3854
      return(0);
3855
3856
    } else if (node->name[0] == 't') {
3857
  if (IS_XSLT_NAME(node, "text"))
3858
      return(XSLT_FUNC_TEXT);
3859
  else if (IS_XSLT_NAME(node, "template"))
3860
      return(0);
3861
  else if (IS_XSLT_NAME(node, "transform"))
3862
      return(0);
3863
3864
    } else if (*(node->name) == 'v') {
3865
  if (IS_XSLT_NAME(node, "value-of"))
3866
      return(XSLT_FUNC_VALUEOF);
3867
  else if (IS_XSLT_NAME(node, "variable"))
3868
      return(XSLT_FUNC_VARIABLE);
3869
3870
    } else if (*(node->name) == 'w') {
3871
  if (IS_XSLT_NAME(node, "when"))
3872
      return(XSLT_FUNC_WHEN);
3873
  if (IS_XSLT_NAME(node, "with-param"))
3874
      return(XSLT_FUNC_WITHPARAM);
3875
    }
3876
    return(0);
3877
}
3878
3879
/**
3880
 * xsltParseAnyXSLTElem:
3881
 *
3882
 * @cctxt: the compilation context
3883
 * @elem: the element node of the XSLT instruction
3884
 *
3885
 * Parses, validates the content models and compiles XSLT instructions.
3886
 *
3887
 * Returns 0 if everything's fine;
3888
 *         -1 on API or internal errors.
3889
 */
3890
int
3891
xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
3892
{
3893
    if ((cctxt == NULL) || (elem == NULL) ||
3894
  (elem->type != XML_ELEMENT_NODE))
3895
  return(-1);
3896
3897
    elem->psvi = NULL;
3898
3899
    if (! (IS_XSLT_ELEM_FAST(elem)))
3900
  return(-1);
3901
    /*
3902
    * Detection of handled content of extension instructions.
3903
    */
3904
    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
3905
  cctxt->inode->extContentHandled = 1;
3906
    }
3907
3908
    xsltCompilerNodePush(cctxt, elem);
3909
    /*
3910
    * URGENT TODO: Find a way to speed up this annoying redundant
3911
    *  textual node-name and namespace comparison.
3912
    */
3913
    if (cctxt->inode->prev->curChildType != 0)
3914
  cctxt->inode->type = cctxt->inode->prev->curChildType;
3915
    else
3916
  cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
3917
    /*
3918
    * Update the in-scope namespaces if needed.
3919
    */
3920
    if (elem->nsDef != NULL)
3921
  cctxt->inode->inScopeNs =
3922
      xsltCompilerBuildInScopeNsList(cctxt, elem);
3923
    /*
3924
    * xsltStylePreCompute():
3925
    *  This will compile the information found on the current
3926
    *  element's attributes. NOTE that this won't process the
3927
    *  children of the instruction.
3928
    */
3929
    xsltStylePreCompute(cctxt->style, elem);
3930
    /*
3931
    * TODO: How to react on errors in xsltStylePreCompute() ?
3932
    */
3933
3934
    /*
3935
    * Validate the content model of the XSLT-element.
3936
    */
3937
    switch (cctxt->inode->type) {
3938
  case XSLT_FUNC_APPLYIMPORTS:
3939
      /* EMPTY */
3940
      goto empty_content;
3941
  case XSLT_FUNC_APPLYTEMPLATES:
3942
      /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3943
      goto apply_templates;
3944
  case XSLT_FUNC_ATTRIBUTE:
3945
      /* <!-- Content: template --> */
3946
      goto sequence_constructor;
3947
  case XSLT_FUNC_CALLTEMPLATE:
3948
      /* <!-- Content: xsl:with-param* --> */
3949
      goto call_template;
3950
  case XSLT_FUNC_CHOOSE:
3951
      /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3952
      goto choose;
3953
  case XSLT_FUNC_COMMENT:
3954
      /* <!-- Content: template --> */
3955
      goto sequence_constructor;
3956
  case XSLT_FUNC_COPY:
3957
      /* <!-- Content: template --> */
3958
      goto sequence_constructor;
3959
  case XSLT_FUNC_COPYOF:
3960
      /* EMPTY */
3961
      goto empty_content;
3962
  case XSLT_FUNC_DOCUMENT: /* Extra one */
3963
      /* ?? template ?? */
3964
      goto sequence_constructor;
3965
  case XSLT_FUNC_ELEMENT:
3966
      /* <!-- Content: template --> */
3967
      goto sequence_constructor;
3968
  case XSLT_FUNC_FALLBACK:
3969
      /* <!-- Content: template --> */
3970
      goto sequence_constructor;
3971
  case XSLT_FUNC_FOREACH:
3972
      /* <!-- Content: (xsl:sort*, template) --> */
3973
      goto for_each;
3974
  case XSLT_FUNC_IF:
3975
      /* <!-- Content: template --> */
3976
      goto sequence_constructor;
3977
  case XSLT_FUNC_OTHERWISE:
3978
      /* <!-- Content: template --> */
3979
      goto sequence_constructor;
3980
  case XSLT_FUNC_MESSAGE:
3981
      /* <!-- Content: template --> */
3982
      goto sequence_constructor;
3983
  case XSLT_FUNC_NUMBER:
3984
      /* EMPTY */
3985
      goto empty_content;
3986
  case XSLT_FUNC_PARAM:
3987
      /*
3988
      * Check for redefinition.
3989
      */
3990
      if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
3991
    xsltVarInfoPtr ivar = cctxt->ivar;
3992
3993
    do {
3994
        if ((ivar->name ==
3995
       ((xsltStyleItemParamPtr) elem->psvi)->name) &&
3996
      (ivar->nsName ==
3997
       ((xsltStyleItemParamPtr) elem->psvi)->ns))
3998
        {
3999
      elem->psvi = NULL;
4000
      xsltTransformError(NULL, cctxt->style, elem,
4001
          "Redefinition of variable or parameter '%s'.\n",
4002
          ivar->name);
4003
      cctxt->style->errors++;
4004
      goto error;
4005
        }
4006
        ivar = ivar->prev;
4007
    } while (ivar != NULL);
4008
      }
4009
      /*  <!-- Content: template --> */
4010
      goto sequence_constructor;
4011
  case XSLT_FUNC_PI:
4012
      /*  <!-- Content: template --> */
4013
      goto sequence_constructor;
4014
  case XSLT_FUNC_SORT:
4015
      /* EMPTY */
4016
      goto empty_content;
4017
  case XSLT_FUNC_TEXT:
4018
      /* <!-- Content: #PCDATA --> */
4019
      goto text;
4020
  case XSLT_FUNC_VALUEOF:
4021
      /* EMPTY */
4022
      goto empty_content;
4023
  case XSLT_FUNC_VARIABLE:
4024
      /*
4025
      * Check for redefinition.
4026
      */
4027
      if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
4028
    xsltVarInfoPtr ivar = cctxt->ivar;
4029
4030
    do {
4031
        if ((ivar->name ==
4032
       ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
4033
      (ivar->nsName ==
4034
       ((xsltStyleItemVariablePtr) elem->psvi)->ns))
4035
        {
4036
      elem->psvi = NULL;
4037
      xsltTransformError(NULL, cctxt->style, elem,
4038
          "Redefinition of variable or parameter '%s'.\n",
4039
          ivar->name);
4040
      cctxt->style->errors++;
4041
      goto error;
4042
        }
4043
        ivar = ivar->prev;
4044
    } while (ivar != NULL);
4045
      }
4046
      /* <!-- Content: template --> */
4047
      goto sequence_constructor;
4048
  case XSLT_FUNC_WHEN:
4049
      /* <!-- Content: template --> */
4050
      goto sequence_constructor;
4051
  case XSLT_FUNC_WITHPARAM:
4052
      /* <!-- Content: template --> */
4053
      goto sequence_constructor;
4054
  default:
4055
#ifdef WITH_XSLT_DEBUG_PARSING
4056
      xsltGenericDebug(xsltGenericDebugContext,
4057
    "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4058
    elem->name);
4059
#endif
4060
      xsltTransformError(NULL, cctxt->style, elem,
4061
    "xsltParseXSLTNode: Internal error; "
4062
    "unhandled XSLT element '%s'.\n", elem->name);
4063
      cctxt->style->errors++;
4064
      goto internal_err;
4065
    }
4066
4067
apply_templates:
4068
    /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4069
    if (elem->children != NULL) {
4070
  xmlNodePtr child = elem->children;
4071
  do {
4072
      if (child->type == XML_ELEMENT_NODE) {
4073
    if (IS_XSLT_ELEM_FAST(child)) {
4074
        if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
4075
      cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4076
      xsltParseAnyXSLTElem(cctxt, child);
4077
        } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
4078
      cctxt->inode->curChildType = XSLT_FUNC_SORT;
4079
      xsltParseAnyXSLTElem(cctxt, child);
4080
        } else
4081
      xsltParseContentError(cctxt->style, child);
4082
    } else
4083
        xsltParseContentError(cctxt->style, child);
4084
      }
4085
      child = child->next;
4086
  } while (child != NULL);
4087
    }
4088
    goto exit;
4089
4090
call_template:
4091
    /* <!-- Content: xsl:with-param* --> */
4092
    if (elem->children != NULL) {
4093
  xmlNodePtr child = elem->children;
4094
  do {
4095
      if (child->type == XML_ELEMENT_NODE) {
4096
    if (IS_XSLT_ELEM_FAST(child)) {
4097
        xsltStyleType type;
4098
4099
        type = xsltGetXSLTElementTypeByNode(cctxt, child);
4100
        if (type == XSLT_FUNC_WITHPARAM) {
4101
      cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4102
      xsltParseAnyXSLTElem(cctxt, child);
4103
        } else {
4104
      xsltParseContentError(cctxt->style, child);
4105
        }
4106
    } else
4107
        xsltParseContentError(cctxt->style, child);
4108
      }
4109
      child = child->next;
4110
  } while (child != NULL);
4111
    }
4112
    goto exit;
4113
4114
text:
4115
    if (elem->children != NULL) {
4116
  xmlNodePtr child = elem->children;
4117
  do {
4118
      if ((child->type != XML_TEXT_NODE) &&
4119
    (child->type != XML_CDATA_SECTION_NODE))
4120
      {
4121
    xsltTransformError(NULL, cctxt->style, elem,
4122
        "The XSLT 'text' element must have only character "
4123
        "data as content.\n");
4124
      }
4125
      child = child->next;
4126
  } while (child != NULL);
4127
    }
4128
    goto exit;
4129
4130
empty_content:
4131
    if (elem->children != NULL) {
4132
  xmlNodePtr child = elem->children;
4133
  /*
4134
  * Relaxed behaviour: we will allow whitespace-only text-nodes.
4135
  */
4136
  do {
4137
      if (((child->type != XML_TEXT_NODE) &&
4138
     (child->type != XML_CDATA_SECTION_NODE)) ||
4139
    (! IS_BLANK_NODE(child)))
4140
      {
4141
    xsltTransformError(NULL, cctxt->style, elem,
4142
        "This XSLT element must have no content.\n");
4143
    cctxt->style->errors++;
4144
    break;
4145
      }
4146
      child = child->next;
4147
  } while (child != NULL);
4148
    }
4149
    goto exit;
4150
4151
choose:
4152
    /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4153
    /*
4154
    * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4155
    *   The old behaviour did not check this.
4156
    * NOTE: In XSLT 2.0 they are stripped beforehand
4157
    *  if whitespace-only (regardless of xml:space).
4158
    */
4159
    if (elem->children != NULL) {
4160
  xmlNodePtr child = elem->children;
4161
  int nbWhen = 0, nbOtherwise = 0, err = 0;
4162
  do {
4163
      if (child->type == XML_ELEMENT_NODE) {
4164
    if (IS_XSLT_ELEM_FAST(child)) {
4165
        xsltStyleType type;
4166
4167
        type = xsltGetXSLTElementTypeByNode(cctxt, child);
4168
        if (type == XSLT_FUNC_WHEN) {
4169
      nbWhen++;
4170
      if (nbOtherwise) {
4171
          xsltParseContentError(cctxt->style, child);
4172
          err = 1;
4173
          break;
4174
      }
4175
      cctxt->inode->curChildType = XSLT_FUNC_WHEN;
4176
      xsltParseAnyXSLTElem(cctxt, child);
4177
        } else if (type == XSLT_FUNC_OTHERWISE) {
4178
      if (! nbWhen) {
4179
          xsltParseContentError(cctxt->style, child);
4180
          err = 1;
4181
          break;
4182
      }
4183
      if (nbOtherwise) {
4184
          xsltTransformError(NULL, cctxt->style, elem,
4185
        "The XSLT 'choose' element must not contain "
4186
        "more than one XSLT 'otherwise' element.\n");
4187
          cctxt->style->errors++;
4188
          err = 1;
4189
          break;
4190
      }
4191
      nbOtherwise++;
4192
      cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
4193
      xsltParseAnyXSLTElem(cctxt, child);
4194
        } else
4195
      xsltParseContentError(cctxt->style, child);
4196
    } else
4197
        xsltParseContentError(cctxt->style, child);
4198
      }
4199
      /*
4200
    else
4201
        xsltParseContentError(cctxt, child);
4202
      */
4203
      child = child->next;
4204
  } while (child != NULL);
4205
  if ((! err) && (! nbWhen)) {
4206
      xsltTransformError(NULL, cctxt->style, elem,
4207
    "The XSLT element 'choose' must contain at least one "
4208
    "XSLT element 'when'.\n");
4209
    cctxt->style->errors++;
4210
  }
4211
    }
4212
    goto exit;
4213
4214
for_each:
4215
    /* <!-- Content: (xsl:sort*, template) --> */
4216
    /*
4217
    * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4218
    *   The old behaviour did not allow this, but it catched this
4219
    *   only at transformation-time.
4220
    *   In XSLT 2.0 they are stripped beforehand if whitespace-only
4221
    *   (regardless of xml:space).
4222
    */
4223
    if (elem->children != NULL) {
4224
  xmlNodePtr child = elem->children;
4225
  /*
4226
  * Parse xsl:sort first.
4227
  */
4228
  do {
4229
      if ((child->type == XML_ELEMENT_NODE) &&
4230
    IS_XSLT_ELEM_FAST(child))
4231
      {
4232
    if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
4233
        XSLT_FUNC_SORT)
4234
    {
4235
        cctxt->inode->curChildType = XSLT_FUNC_SORT;
4236
        xsltParseAnyXSLTElem(cctxt, child);
4237
    } else
4238
        break;
4239
      } else
4240
    break;
4241
      child = child->next;
4242
  } while (child != NULL);
4243
  /*
4244
  * Parse the sequece constructor.
4245
  */
4246
  if (child != NULL)
4247
      xsltParseSequenceConstructor(cctxt, child);
4248
    }
4249
    goto exit;
4250
4251
sequence_constructor:
4252
    /*
4253
    * Parse the sequence constructor.
4254
    */
4255
    if (elem->children != NULL)
4256
  xsltParseSequenceConstructor(cctxt, elem->children);
4257
4258
    /*
4259
    * Register information for vars/params. Only needed if there
4260
    * are any following siblings.
4261
    */
4262
    if ((elem->next != NULL) &&
4263
  ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
4264
   (cctxt->inode->type == XSLT_FUNC_PARAM)))
4265
    {
4266
  if ((elem->psvi != NULL) &&
4267
      (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
4268
  {
4269
      xsltCompilerVarInfoPush(cctxt, elem,
4270
    ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
4271
    ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
4272
  }
4273
    }
4274
4275
error:
4276
exit:
4277
    xsltCompilerNodePop(cctxt, elem);
4278
    return(0);
4279
4280
internal_err:
4281
    xsltCompilerNodePop(cctxt, elem);
4282
    return(-1);
4283
}
4284
4285
/**
4286
 * xsltForwardsCompatUnkownItemCreate:
4287
 *
4288
 * @cctxt: the compilation context
4289
 *
4290
 * Creates a compiled representation of the unknown
4291
 * XSLT instruction.
4292
 *
4293
 * Returns the compiled representation.
4294
 */
4295
static xsltStyleItemUknownPtr
4296
xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
4297
{
4298
    xsltStyleItemUknownPtr item;
4299
4300
    item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
4301
    if (item == NULL) {
4302
  xsltTransformError(NULL, cctxt->style, NULL,
4303
      "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4304
      "Failed to allocate memory.\n");
4305
  cctxt->style->errors++;
4306
  return(NULL);
4307
    }
4308
    memset(item, 0, sizeof(xsltStyleItemUknown));
4309
    item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
4310
    /*
4311
    * Store it in the stylesheet.
4312
    */
4313
    item->next = cctxt->style->preComps;
4314
    cctxt->style->preComps = (xsltElemPreCompPtr) item;
4315
    return(item);
4316
}
4317
4318
/**
4319
 * xsltParseUnknownXSLTElem:
4320
 *
4321
 * @cctxt: the compilation context
4322
 * @node: the element of the unknown XSLT instruction
4323
 *
4324
 * Parses an unknown XSLT element.
4325
 * If forwards compatible mode is enabled this will allow
4326
 * such an unknown XSLT and; otherwise it is rejected.
4327
 *
4328
 * Returns 1 in the unknown XSLT instruction is rejected,
4329
 *         0 if everything's fine and
4330
 *         -1 on API or internal errors.
4331
 */
4332
static int
4333
xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
4334
          xmlNodePtr node)
4335
{
4336
    if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
4337
  return(-1);
4338
4339
    /*
4340
    * Detection of handled content of extension instructions.
4341
    */
4342
    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4343
  cctxt->inode->extContentHandled = 1;
4344
    }
4345
    if (cctxt->inode->forwardsCompat == 0) {
4346
  /*
4347
  * We are not in forwards-compatible mode, so raise an error.
4348
  */
4349
  xsltTransformError(NULL, cctxt->style, node,
4350
      "Unknown XSLT element '%s'.\n", node->name);
4351
  cctxt->style->errors++;
4352
  return(1);
4353
    }
4354
    /*
4355
    * Forwards-compatible mode.
4356
    * ------------------------
4357
    *
4358
    * Parse/compile xsl:fallback elements.
4359
    *
4360
    * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4361
    * ANSWER: No, since in the stylesheet the fallback behaviour might
4362
    *  also be provided by using the XSLT function "element-available".
4363
    */
4364
    if (cctxt->unknownItem == NULL) {
4365
  /*
4366
  * Create a singleton for all unknown XSLT instructions.
4367
  */
4368
  cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
4369
  if (cctxt->unknownItem == NULL) {
4370
      node->psvi = NULL;
4371
      return(-1);
4372
  }
4373
    }
4374
    node->psvi = cctxt->unknownItem;
4375
    if (node->children == NULL)
4376
  return(0);
4377
    else {
4378
  xmlNodePtr child = node->children;
4379
4380
  xsltCompilerNodePush(cctxt, node);
4381
  /*
4382
  * Update the in-scope namespaces if needed.
4383
  */
4384
  if (node->nsDef != NULL)
4385
      cctxt->inode->inScopeNs =
4386
    xsltCompilerBuildInScopeNsList(cctxt, node);
4387
  /*
4388
  * Parse all xsl:fallback children.
4389
  */
4390
  do {
4391
      if ((child->type == XML_ELEMENT_NODE) &&
4392
    IS_XSLT_ELEM_FAST(child) &&
4393
    IS_XSLT_NAME(child, "fallback"))
4394
      {
4395
    cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
4396
    xsltParseAnyXSLTElem(cctxt, child);
4397
      }
4398
      child = child->next;
4399
  } while (child != NULL);
4400
4401
  xsltCompilerNodePop(cctxt, node);
4402
    }
4403
    return(0);
4404
}
4405
4406
/**
4407
 * xsltParseSequenceConstructor:
4408
 *
4409
 * @cctxt: the compilation context
4410
 * @cur: the start-node of the content to be parsed
4411
 *
4412
 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4413
 * This will additionally remove xsl:text elements from the tree.
4414
 */
4415
void
4416
xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
4417
{
4418
    xsltStyleType type;
4419
    xmlNodePtr deleteNode = NULL;
4420
4421
    if (cctxt == NULL) {
4422
  xmlGenericError(xmlGenericErrorContext,
4423
      "xsltParseSequenceConstructor: Bad arguments\n");
4424
  cctxt->style->errors++;
4425
  return;
4426
    }
4427
    /*
4428
    * Detection of handled content of extension instructions.
4429
    */
4430
    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4431
  cctxt->inode->extContentHandled = 1;
4432
    }
4433
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
4434
  return;
4435
    /*
4436
    * This is the content reffered to as a "template".
4437
    * E.g. an xsl:element has such content model:
4438
    * <xsl:element
4439
    *   name = { qname }
4440
    *   namespace = { uri-reference }
4441
    *   use-attribute-sets = qnames>
4442
    * <!-- Content: template -->
4443
    *
4444
    * NOTE that in XSLT-2 the term "template" was abandoned due to
4445
    *  confusion with xsl:template and the term "sequence constructor"
4446
    *  was introduced instead.
4447
    *
4448
    * The following XSLT-instructions are allowed to appear:
4449
    *  xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4450
    *  xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4451
    *  xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4452
    *  xsl:message, xsl:fallback,
4453
    *  xsl:processing-instruction, xsl:comment, xsl:element
4454
    *  xsl:attribute.
4455
    * Additional allowed content:
4456
    * 1) extension instructions
4457
    * 2) literal result elements
4458
    * 3) PCDATA
4459
    *
4460
    * NOTE that this content model does *not* allow xsl:param.
4461
    */
4462
    while (cur != NULL) {
4463
        cctxt->style->principal->opCount += 1;
4464
4465
  if (deleteNode != NULL) {
4466
#ifdef WITH_XSLT_DEBUG_BLANKS
4467
      xsltGenericDebug(xsltGenericDebugContext,
4468
       "xsltParseSequenceConstructor: removing xsl:text element\n");
4469
#endif
4470
      xmlUnlinkNode(deleteNode);
4471
      xmlFreeNode(deleteNode);
4472
      deleteNode = NULL;
4473
  }
4474
  if (cur->type == XML_ELEMENT_NODE) {
4475
4476
      if (cur->psvi == xsltXSLTTextMarker) {
4477
    /*
4478
    * xsl:text elements
4479
    * --------------------------------------------------------
4480
    */
4481
    xmlNodePtr tmp;
4482
4483
    cur->psvi = NULL;
4484
    /*
4485
    * Mark the xsl:text element for later deletion.
4486
    */
4487
    deleteNode = cur;
4488
    /*
4489
    * Validate content.
4490
    */
4491
    tmp = cur->children;
4492
    if (tmp) {
4493
        /*
4494
        * We don't expect more than one text-node in the
4495
        * content, since we already merged adjacent
4496
        * text/CDATA-nodes and eliminated PI/comment-nodes.
4497
        */
4498
        if ((tmp->type == XML_TEXT_NODE) ||
4499
      (tmp->next == NULL))
4500
        {
4501
      /*
4502
      * Leave the contained text-node in the tree.
4503
      */
4504
      xmlUnlinkNode(tmp);
4505
      if (xmlAddPrevSibling(cur, tmp) == NULL) {
4506
                            xsltTransformError(ctxt, NULL, NULL,
4507
                                    "out of memory\n");
4508
                            xmlFreeNode(tmp);
4509
                        }
4510
        } else {
4511
      tmp = NULL;
4512
      xsltTransformError(NULL, cctxt->style, cur,
4513
          "Element 'xsl:text': Invalid type "
4514
          "of node found in content.\n");
4515
      cctxt->style->errors++;
4516
        }
4517
    }
4518
    if (cur->properties) {
4519
        xmlAttrPtr attr;
4520
        /*
4521
        * TODO: We need to report errors for
4522
        *  invalid attrs.
4523
        */
4524
        attr = cur->properties;
4525
        do {
4526
      if ((attr->ns == NULL) &&
4527
          (attr->name != NULL) &&
4528
          (attr->name[0] == 'd') &&
4529
          xmlStrEqual(attr->name,
4530
          BAD_CAST "disable-output-escaping"))
4531
      {
4532
          /*
4533
          * Attr "disable-output-escaping".
4534
          * XSLT-2: This attribute is deprecated.
4535
          */
4536
          if ((attr->children != NULL) &&
4537
        xmlStrEqual(attr->children->content,
4538
        BAD_CAST "yes"))
4539
          {
4540
        /*
4541
        * Disable output escaping for this
4542
        * text node.
4543
        */
4544
        if (tmp)
4545
            tmp->name = xmlStringTextNoenc;
4546
          } else if ((attr->children == NULL) ||
4547
        (attr->children->content == NULL) ||
4548
        (!xmlStrEqual(attr->children->content,
4549
        BAD_CAST "no")))
4550
          {
4551
        xsltTransformError(NULL, cctxt->style,
4552
            cur,
4553
            "Attribute 'disable-output-escaping': "
4554
            "Invalid value. Expected is "
4555
            "'yes' or 'no'.\n");
4556
        cctxt->style->errors++;
4557
          }
4558
          break;
4559
      }
4560
      attr = attr->next;
4561
        } while (attr != NULL);
4562
    }
4563
      } else if (IS_XSLT_ELEM_FAST(cur)) {
4564
    /*
4565
    * TODO: Using the XSLT-marker is still not stable yet.
4566
    */
4567
    /* if (cur->psvi == xsltXSLTElemMarker) { */
4568
    /*
4569
    * XSLT instructions
4570
    * --------------------------------------------------------
4571
    */
4572
    cur->psvi = NULL;
4573
    type = xsltGetXSLTElementTypeByNode(cctxt, cur);
4574
    switch (type) {
4575
        case XSLT_FUNC_APPLYIMPORTS:
4576
        case XSLT_FUNC_APPLYTEMPLATES:
4577
        case XSLT_FUNC_ATTRIBUTE:
4578
        case XSLT_FUNC_CALLTEMPLATE:
4579
        case XSLT_FUNC_CHOOSE:
4580
        case XSLT_FUNC_COMMENT:
4581
        case XSLT_FUNC_COPY:
4582
        case XSLT_FUNC_COPYOF:
4583
        case XSLT_FUNC_DOCUMENT: /* Extra one */
4584
        case XSLT_FUNC_ELEMENT:
4585
        case XSLT_FUNC_FALLBACK:
4586
        case XSLT_FUNC_FOREACH:
4587
        case XSLT_FUNC_IF:
4588
        case XSLT_FUNC_MESSAGE:
4589
        case XSLT_FUNC_NUMBER:
4590
        case XSLT_FUNC_PI:
4591
        case XSLT_FUNC_TEXT:
4592
        case XSLT_FUNC_VALUEOF:
4593
        case XSLT_FUNC_VARIABLE:
4594
      /*
4595
      * Parse the XSLT element.
4596
      */
4597
      cctxt->inode->curChildType = type;
4598
      xsltParseAnyXSLTElem(cctxt, cur);
4599
      break;
4600
        default:
4601
      xsltParseUnknownXSLTElem(cctxt, cur);
4602
      cur = cur->next;
4603
      continue;
4604
    }
4605
      } else {
4606
    /*
4607
    * Non-XSLT elements
4608
    * -----------------
4609
    */
4610
    xsltCompilerNodePush(cctxt, cur);
4611
    /*
4612
    * Update the in-scope namespaces if needed.
4613
    */
4614
    if (cur->nsDef != NULL)
4615
        cctxt->inode->inScopeNs =
4616
      xsltCompilerBuildInScopeNsList(cctxt, cur);
4617
    /*
4618
    * The current element is either a literal result element
4619
    * or an extension instruction.
4620
    *
4621
    * Process attr "xsl:extension-element-prefixes".
4622
    * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4623
    * processed by the implementor of the extension function;
4624
    * i.e., it won't be handled by the XSLT processor.
4625
    */
4626
    /* SPEC 1.0:
4627
    *   "exclude-result-prefixes" is only allowed on literal
4628
    *   result elements and "xsl:exclude-result-prefixes"
4629
    *   on xsl:stylesheet/xsl:transform.
4630
    * SPEC 2.0:
4631
    *   "There are a number of standard attributes
4632
    *   that may appear on any XSLT element: specifically
4633
    *   version, exclude-result-prefixes,
4634
    *   extension-element-prefixes, xpath-default-namespace,
4635
    *   default-collation, and use-when."
4636
    *
4637
    * SPEC 2.0:
4638
    *   For literal result elements:
4639
    *   "xsl:version, xsl:exclude-result-prefixes,
4640
    *    xsl:extension-element-prefixes,
4641
    *    xsl:xpath-default-namespace,
4642
    *    xsl:default-collation, or xsl:use-when."
4643
    */
4644
    if (cur->properties)
4645
        cctxt->inode->extElemNs =
4646
      xsltParseExtElemPrefixes(cctxt,
4647
          cur, cctxt->inode->extElemNs,
4648
          XSLT_ELEMENT_CATEGORY_LRE);
4649
    /*
4650
    * Eval if we have an extension instruction here.
4651
    */
4652
    if ((cur->ns != NULL) &&
4653
        (cctxt->inode->extElemNs != NULL) &&
4654
        (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
4655
    {
4656
        /*
4657
        * Extension instructions
4658
        * ----------------------------------------------------
4659
        * Mark the node information.
4660
        */
4661
        cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
4662
        cctxt->inode->extContentHandled = 0;
4663
        if (cur->psvi != NULL) {
4664
      cur->psvi = NULL;
4665
      /*
4666
      * TODO: Temporary sanity check.
4667
      */
4668
      xsltTransformError(NULL, cctxt->style, cur,
4669
          "Internal error in xsltParseSequenceConstructor(): "
4670
          "Occupied PSVI field.\n");
4671
      cctxt->style->errors++;
4672
      cur = cur->next;
4673
      continue;
4674
        }
4675
        cur->psvi = (void *)
4676
      xsltPreComputeExtModuleElement(cctxt->style, cur);
4677
4678
        if (cur->psvi == NULL) {
4679
      /*
4680
      * OLD COMMENT: "Unknown element, maybe registered
4681
      *  at the context level. Mark it for later
4682
      *  recognition."
4683
      * QUESTION: What does the xsltExtMarker mean?
4684
      *  ANSWER: It is used in
4685
      *   xsltApplySequenceConstructor() at
4686
      *   transformation-time to look out for extension
4687
      *   registered in the transformation context.
4688
      */
4689
      cur->psvi = (void *) xsltExtMarker;
4690
        }
4691
        /*
4692
        * BIG NOTE: Now the ugly part. In previous versions
4693
        *  of Libxslt (until 1.1.16), all the content of an
4694
        *  extension instruction was processed and compiled without
4695
        *  the need of the extension-author to explicitely call
4696
        *  such a processing;.We now need to mimic this old
4697
        *  behaviour in order to avoid breaking old code
4698
        *  on the extension-author's side.
4699
        * The mechanism:
4700
        *  1) If the author does *not* set the
4701
        *    compile-time-flag @extContentHandled, then we'll
4702
        *    parse the content assuming that it's a "template"
4703
        *    (or "sequence constructor in XSLT 2.0 terms).
4704
        *    NOTE: If the extension is registered at
4705
        *    transformation-time only, then there's no way of
4706
        *    knowing that content shall be valid, and we'll
4707
        *    process the content the same way.
4708
        *  2) If the author *does* set the flag, then we'll assume
4709
        *   that the author has handled the parsing him/herself
4710
        *   (e.g. called xsltParseSequenceConstructor(), etc.
4711
        *   explicitely in his/her code).
4712
        */
4713
        if ((cur->children != NULL) &&
4714
      (cctxt->inode->extContentHandled == 0))
4715
        {
4716
      /*
4717
      * Default parsing of the content using the
4718
      * sequence-constructor model.
4719
      */
4720
      xsltParseSequenceConstructor(cctxt, cur->children);
4721
        }
4722
    } else {
4723
        /*
4724
        * Literal result element
4725
        * ----------------------------------------------------
4726
        * Allowed XSLT attributes:
4727
        *  xsl:extension-element-prefixes CDATA #IMPLIED
4728
        *  xsl:exclude-result-prefixes CDATA #IMPLIED
4729
        *  TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4730
        *  xsl:version NMTOKEN #IMPLIED
4731
        */
4732
        cur->psvi = NULL;
4733
        cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
4734
        if (cur->properties != NULL) {
4735
      xmlAttrPtr attr = cur->properties;
4736
      /*
4737
      * Attribute "xsl:exclude-result-prefixes".
4738
      */
4739
      cctxt->inode->exclResultNs =
4740
          xsltParseExclResultPrefixes(cctxt, cur,
4741
        cctxt->inode->exclResultNs,
4742
        XSLT_ELEMENT_CATEGORY_LRE);
4743
      /*
4744
      * Attribute "xsl:version".
4745
      */
4746
      xsltParseAttrXSLTVersion(cctxt, cur,
4747
          XSLT_ELEMENT_CATEGORY_LRE);
4748
      /*
4749
      * Report invalid XSLT attributes.
4750
      * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4751
      * next to xsl:version, xsl:exclude-result-prefixes and
4752
      * xsl:extension-element-prefixes.
4753
      *
4754
      * Mark all XSLT attributes, in order to skip such
4755
      * attributes when instantiating the LRE.
4756
      */
4757
      do {
4758
          if ((attr->psvi != xsltXSLTAttrMarker) &&
4759
        IS_XSLT_ATTR_FAST(attr))
4760
          {
4761
        if (! xmlStrEqual(attr->name,
4762
            BAD_CAST "use-attribute-sets"))
4763
        {
4764
            xsltTransformError(NULL, cctxt->style,
4765
          cur,
4766
          "Unknown XSLT attribute '%s'.\n",
4767
          attr->name);
4768
            cctxt->style->errors++;
4769
        } else {
4770
            /*
4771
            * XSLT attr marker.
4772
            */
4773
            attr->psvi = (void *) xsltXSLTAttrMarker;
4774
        }
4775
          }
4776
          attr = attr->next;
4777
      } while (attr != NULL);
4778
        }
4779
        /*
4780
        * Create/reuse info for the literal result element.
4781
        */
4782
        if (cctxt->inode->nsChanged)
4783
      xsltLREInfoCreate(cctxt, cur, 1);
4784
        cur->psvi = cctxt->inode->litResElemInfo;
4785
        /*
4786
        * Apply ns-aliasing on the element and on its attributes.
4787
        */
4788
        if (cctxt->hasNsAliases)
4789
      xsltLREBuildEffectiveNs(cctxt, cur);
4790
        /*
4791
        * Compile attribute value templates (AVT).
4792
        */
4793
        if (cur->properties) {
4794
      xmlAttrPtr attr = cur->properties;
4795
4796
      while (attr != NULL) {
4797
          xsltCompileAttr(cctxt->style, attr);
4798
          attr = attr->next;
4799
      }
4800
        }
4801
        /*
4802
        * Parse the content, which is defined to be a "template"
4803
        * (or "sequence constructor" in XSLT 2.0 terms).
4804
        */
4805
        if (cur->children != NULL) {
4806
      xsltParseSequenceConstructor(cctxt, cur->children);
4807
        }
4808
    }
4809
    /*
4810
    * Leave the non-XSLT element.
4811
    */
4812
    xsltCompilerNodePop(cctxt, cur);
4813
      }
4814
  }
4815
  cur = cur->next;
4816
    }
4817
    if (deleteNode != NULL) {
4818
#ifdef WITH_XSLT_DEBUG_BLANKS
4819
  xsltGenericDebug(xsltGenericDebugContext,
4820
      "xsltParseSequenceConstructor: removing xsl:text element\n");
4821
#endif
4822
  xmlUnlinkNode(deleteNode);
4823
  xmlFreeNode(deleteNode);
4824
  deleteNode = NULL;
4825
    }
4826
}
4827
4828
/**
4829
 * xsltParseTemplateContent:
4830
 * @style:  the XSLT stylesheet
4831
 * @templ:  the node containing the content to be parsed
4832
 *
4833
 * Parses and compiles the content-model of an xsl:template element.
4834
 * Note that this is *not* the "template" content model (or "sequence
4835
 *  constructor" in XSLT 2.0); it it allows addional xsl:param
4836
 *  elements as immediate children of @templ.
4837
 *
4838
 * Called by:
4839
 *   exsltFuncFunctionComp() (EXSLT, functions.c)
4840
 *   So this is intended to be called from extension functions.
4841
 */
4842
void
4843
xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4844
    if ((style == NULL) || (templ == NULL) ||
4845
        (templ->type == XML_NAMESPACE_DECL))
4846
  return;
4847
4848
    /*
4849
    * Detection of handled content of extension instructions.
4850
    */
4851
    if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4852
  XSLT_CCTXT(style)->inode->extContentHandled = 1;
4853
    }
4854
4855
    if (templ->children != NULL) {
4856
  xmlNodePtr child = templ->children;
4857
  /*
4858
  * Process xsl:param elements, which can only occur as the
4859
  * immediate children of xsl:template (well, and of any
4860
  * user-defined extension instruction if needed).
4861
  */
4862
  do {
4863
            style->principal->opCount += 1;
4864
4865
      if ((child->type == XML_ELEMENT_NODE) &&
4866
    IS_XSLT_ELEM_FAST(child) &&
4867
    IS_XSLT_NAME(child, "param"))
4868
      {
4869
    XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
4870
    xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
4871
      } else
4872
    break;
4873
      child = child->next;
4874
  } while (child != NULL);
4875
  /*
4876
  * Parse the content and register the pattern.
4877
  */
4878
  xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
4879
    }
4880
}
4881
4882
#else /* XSLT_REFACTORED */
4883
4884
/**
4885
 * xsltParseTemplateContent:
4886
 * @style:  the XSLT stylesheet
4887
 * @templ:  the container node (can be a document for literal results)
4888
 *
4889
 * parse a template content-model
4890
 * Clean-up the template content from unwanted ignorable blank nodes
4891
 * and process xslt:text
4892
 */
4893
void
4894
3.47k
xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4895
3.47k
    xmlNodePtr cur, delete;
4896
4897
3.47k
    if ((style == NULL) || (templ == NULL) ||
4898
3.47k
        (templ->type == XML_NAMESPACE_DECL)) return;
4899
4900
    /*
4901
     * This content comes from the stylesheet
4902
     * For stylesheets, the set of whitespace-preserving
4903
     * element names consists of just xsl:text.
4904
     */
4905
3.47k
    cur = templ->children;
4906
3.47k
    delete = NULL;
4907
1.48M
    while (cur != NULL) {
4908
1.48M
        style->principal->opCount += 1;
4909
4910
1.48M
  if (delete != NULL) {
4911
#ifdef WITH_XSLT_DEBUG_BLANKS
4912
      xsltGenericDebug(xsltGenericDebugContext,
4913
       "xsltParseTemplateContent: removing text\n");
4914
#endif
4915
5.92k
      xmlUnlinkNode(delete);
4916
5.92k
      xmlFreeNode(delete);
4917
5.92k
      delete = NULL;
4918
5.92k
  }
4919
1.48M
  if (IS_XSLT_ELEM(cur)) {
4920
93.8k
            xsltStylePreCompute(style, cur);
4921
4922
93.8k
      if (IS_XSLT_NAME(cur, "text")) {
4923
    /*
4924
    * TODO: Processing of xsl:text should be moved to
4925
    *   xsltPreprocessStylesheet(), since otherwise this
4926
    *   will be performed for every multiply included
4927
    *   stylesheet; i.e. this here is not skipped with
4928
    *   the use of the style->nopreproc flag.
4929
    */
4930
5.96k
    if (cur->children != NULL) {
4931
4.48k
        xmlChar *prop;
4932
4.48k
        xmlNodePtr text = cur->children, next;
4933
4.48k
        int noesc = 0;
4934
4935
4.48k
        prop = xmlGetNsProp(cur,
4936
4.48k
      (const xmlChar *)"disable-output-escaping",
4937
4.48k
      NULL);
4938
4.48k
        if (prop != NULL) {
4939
#ifdef WITH_XSLT_DEBUG_PARSING
4940
      xsltGenericDebug(xsltGenericDebugContext,
4941
           "Disable escaping: %s\n", text->content);
4942
#endif
4943
2.68k
      if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
4944
2.46k
          noesc = 1;
4945
2.46k
      } else if (!xmlStrEqual(prop,
4946
226
            (const xmlChar *)"no")){
4947
226
          xsltTransformError(NULL, style, cur,
4948
226
       "xsl:text: disable-output-escaping allows only yes or no\n");
4949
226
          style->warnings++;
4950
4951
226
      }
4952
2.68k
      xmlFree(prop);
4953
2.68k
        }
4954
4955
8.96k
        while (text != NULL) {
4956
4.64k
      if (text->type == XML_COMMENT_NODE) {
4957
0
          text = text->next;
4958
0
          continue;
4959
0
      }
4960
4.64k
      if ((text->type != XML_TEXT_NODE) &&
4961
4.64k
           (text->type != XML_CDATA_SECTION_NODE)) {
4962
167
          xsltTransformError(NULL, style, cur,
4963
167
     "xsltParseTemplateContent: xslt:text content problem\n");
4964
167
          style->errors++;
4965
167
          break;
4966
167
      }
4967
4.48k
      if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
4968
2.46k
          text->name = xmlStringTextNoenc;
4969
4.48k
      text = text->next;
4970
4.48k
        }
4971
4972
        /*
4973
         * replace xsl:text by the list of childs
4974
         */
4975
4.48k
        if (text == NULL) {
4976
4.31k
      text = cur->children;
4977
8.62k
      while (text != NULL) {
4978
4.31k
          if ((style->internalized) &&
4979
4.31k
              (text->content != NULL) &&
4980
4.31k
              (!xmlDictOwns(style->dict, text->content))) {
4981
4982
        /*
4983
         * internalize the text string
4984
         */
4985
3.41k
        if (text->doc->dict != NULL) {
4986
3.41k
            const xmlChar *tmp;
4987
4988
3.41k
            tmp = xmlDictLookup(text->doc->dict,
4989
3.41k
                                text->content, -1);
4990
3.41k
            if (tmp != text->content) {
4991
3.41k
                xmlNodeSetContent(text, NULL);
4992
3.41k
          text->content = (xmlChar *) tmp;
4993
3.41k
            }
4994
3.41k
        }
4995
3.41k
          }
4996
4997
4.31k
          next = text->next;
4998
4.31k
          xmlUnlinkNode(text);
4999
4.31k
                            if (xmlAddPrevSibling(cur, text) == NULL) {
5000
0
                                xsltTransformError(NULL, style, NULL,
5001
0
                                        "out of memory\n");
5002
0
                                xmlFreeNode(text);
5003
0
                            }
5004
4.31k
          text = next;
5005
4.31k
      }
5006
4.31k
        }
5007
4.48k
    }
5008
5.96k
    delete = cur;
5009
5.96k
    goto skip_children;
5010
5.96k
      }
5011
93.8k
  }
5012
1.38M
  else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
5013
1.38M
      (xsltCheckExtPrefix(style, cur->ns->prefix)))
5014
5.47k
  {
5015
      /*
5016
       * okay this is an extension element compile it too
5017
       */
5018
5.47k
      xsltStylePreCompute(style, cur);
5019
5.47k
  }
5020
1.38M
  else if (cur->type == XML_ELEMENT_NODE)
5021
826k
  {
5022
      /*
5023
       * This is an element which will be output as part of the
5024
       * template exectution, precompile AVT if found.
5025
       */
5026
826k
      if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
5027
0
    cur->ns = xmlSearchNsByHref(cur->doc, cur,
5028
0
      style->defaultAlias);
5029
0
      }
5030
826k
      if (cur->properties != NULL) {
5031
141k
          xmlAttrPtr attr = cur->properties;
5032
5033
286k
    while (attr != NULL) {
5034
145k
        xsltCompileAttr(style, attr);
5035
145k
        attr = attr->next;
5036
145k
    }
5037
141k
      }
5038
826k
  }
5039
  /*
5040
   * Skip to next node
5041
   */
5042
1.47M
  if (cur->children != NULL) {
5043
346k
      if (cur->children->type != XML_ENTITY_DECL) {
5044
346k
    cur = cur->children;
5045
346k
    continue;
5046
346k
      }
5047
346k
  }
5048
1.13M
skip_children:
5049
1.13M
  if (cur->next != NULL) {
5050
876k
      cur = cur->next;
5051
876k
      continue;
5052
876k
  }
5053
5054
349k
  do {
5055
349k
      cur = cur->parent;
5056
349k
      if (cur == NULL)
5057
0
    break;
5058
349k
      if (cur == templ) {
5059
3.21k
    cur = NULL;
5060
3.21k
    break;
5061
3.21k
      }
5062
346k
      if (cur->next != NULL) {
5063
256k
    cur = cur->next;
5064
256k
    break;
5065
256k
      }
5066
346k
  } while (cur != NULL);
5067
259k
    }
5068
3.47k
    if (delete != NULL) {
5069
#ifdef WITH_XSLT_DEBUG_PARSING
5070
  xsltGenericDebug(xsltGenericDebugContext,
5071
   "xsltParseTemplateContent: removing text\n");
5072
#endif
5073
38
  xmlUnlinkNode(delete);
5074
38
  xmlFreeNode(delete);
5075
38
  delete = NULL;
5076
38
    }
5077
5078
    /*
5079
     * Skip the first params
5080
     */
5081
3.47k
    cur = templ->children;
5082
13.3k
    while (cur != NULL) {
5083
11.1k
  if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
5084
1.18k
      break;
5085
9.91k
  cur = cur->next;
5086
9.91k
    }
5087
5088
    /*
5089
     * Browse the remainder of the template
5090
     */
5091
3.47k
    while (cur != NULL) {
5092
1.18k
  if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
5093
0
      xmlNodePtr param = cur;
5094
5095
0
      xsltTransformError(NULL, style, cur,
5096
0
    "xsltParseTemplateContent: ignoring misplaced param element\n");
5097
0
      if (style != NULL) style->warnings++;
5098
0
            cur = cur->next;
5099
0
      xmlUnlinkNode(param);
5100
0
      xmlFreeNode(param);
5101
0
  } else
5102
1.18k
      break;
5103
1.18k
    }
5104
3.47k
}
5105
5106
#endif /* else XSLT_REFACTORED */
5107
5108
/**
5109
 * xsltParseStylesheetKey:
5110
 * @style:  the XSLT stylesheet
5111
 * @key:  the "key" element
5112
 *
5113
 * <!-- Category: top-level-element -->
5114
 * <xsl:key name = qname, match = pattern, use = expression />
5115
 *
5116
 * parse an XSLT stylesheet key definition and register it
5117
 */
5118
5119
static void
5120
5
xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
5121
5
    xmlChar *prop = NULL;
5122
5
    xmlChar *use = NULL;
5123
5
    xmlChar *match = NULL;
5124
5
    xmlChar *name = NULL;
5125
5
    xmlChar *nameURI = NULL;
5126
5127
5
    if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
5128
0
  return;
5129
5130
    /*
5131
     * Get arguments
5132
     */
5133
5
    prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
5134
5
    if (prop != NULL) {
5135
5
        const xmlChar *URI;
5136
5137
  /*
5138
  * TODO: Don't use xsltGetQNameURI().
5139
  */
5140
5
  URI = xsltGetQNameURI(key, &prop);
5141
5
  if (prop == NULL) {
5142
0
      if (style != NULL) style->errors++;
5143
0
      goto error;
5144
5
  } else {
5145
5
      name = prop;
5146
5
      if (URI != NULL)
5147
0
    nameURI = xmlStrdup(URI);
5148
5
  }
5149
#ifdef WITH_XSLT_DEBUG_PARSING
5150
  xsltGenericDebug(xsltGenericDebugContext,
5151
       "xsltParseStylesheetKey: name %s\n", name);
5152
#endif
5153
5
    } else {
5154
0
  xsltTransformError(NULL, style, key,
5155
0
      "xsl:key : error missing name\n");
5156
0
  if (style != NULL) style->errors++;
5157
0
  goto error;
5158
0
    }
5159
5160
5
    match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
5161
5
    if (match == NULL) {
5162
0
  xsltTransformError(NULL, style, key,
5163
0
      "xsl:key : error missing match\n");
5164
0
  if (style != NULL) style->errors++;
5165
0
  goto error;
5166
0
    }
5167
5168
5
    use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
5169
5
    if (use == NULL) {
5170
0
  xsltTransformError(NULL, style, key,
5171
0
      "xsl:key : error missing use\n");
5172
0
  if (style != NULL) style->errors++;
5173
0
  goto error;
5174
0
    }
5175
5176
    /*
5177
     * register the keys
5178
     */
5179
5
    xsltAddKey(style, name, nameURI, match, use, key);
5180
5181
5182
5
error:
5183
5
    if (use != NULL)
5184
5
  xmlFree(use);
5185
5
    if (match != NULL)
5186
5
  xmlFree(match);
5187
5
    if (name != NULL)
5188
5
  xmlFree(name);
5189
5
    if (nameURI != NULL)
5190
0
  xmlFree(nameURI);
5191
5192
5
    if (key->children != NULL) {
5193
0
  xsltParseContentError(style, key->children);
5194
0
    }
5195
5
}
5196
5197
#ifdef XSLT_REFACTORED
5198
/**
5199
 * xsltParseXSLTTemplate:
5200
 * @style:  the XSLT stylesheet
5201
 * @template:  the "template" element
5202
 *
5203
 * parse an XSLT stylesheet template building the associated structures
5204
 * TODO: Is @style ever expected to be NULL?
5205
 *
5206
 * Called from:
5207
 *   xsltParseXSLTStylesheet()
5208
 *   xsltParseStylesheetTop()
5209
 */
5210
5211
static void
5212
xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
5213
    xsltTemplatePtr templ;
5214
    xmlChar *prop;
5215
    double  priority;
5216
5217
    if ((cctxt == NULL) || (templNode == NULL) ||
5218
        (templNode->type != XML_ELEMENT_NODE))
5219
  return;
5220
5221
    /*
5222
     * Create and link the structure
5223
     */
5224
    templ = xsltNewTemplate();
5225
    if (templ == NULL)
5226
  return;
5227
5228
    xsltCompilerNodePush(cctxt, templNode);
5229
    if (templNode->nsDef != NULL)
5230
  cctxt->inode->inScopeNs =
5231
      xsltCompilerBuildInScopeNsList(cctxt, templNode);
5232
5233
    templ->next = cctxt->style->templates;
5234
    cctxt->style->templates = templ;
5235
    templ->style = cctxt->style;
5236
5237
    /*
5238
    * Attribute "mode".
5239
    */
5240
    prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
5241
    if (prop != NULL) {
5242
        const xmlChar *modeURI;
5243
5244
  /*
5245
  * TODO: We need a standardized function for extraction
5246
  *  of namespace names and local names from QNames.
5247
  *  Don't use xsltGetQNameURI() as it cannot channe�
5248
  *  reports through the context.
5249
  */
5250
  modeURI = xsltGetQNameURI(templNode, &prop);
5251
  if (prop == NULL) {
5252
      cctxt->style->errors++;
5253
      goto error;
5254
  }
5255
  templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
5256
  xmlFree(prop);
5257
  prop = NULL;
5258
  if (xmlValidateNCName(templ->mode, 0)) {
5259
      xsltTransformError(NULL, cctxt->style, templNode,
5260
    "xsl:template: Attribute 'mode': The local part '%s' "
5261
    "of the value is not a valid NCName.\n", templ->name);
5262
      cctxt->style->errors++;
5263
      goto error;
5264
  }
5265
  if (modeURI != NULL)
5266
      templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
5267
#ifdef WITH_XSLT_DEBUG_PARSING
5268
  xsltGenericDebug(xsltGenericDebugContext,
5269
       "xsltParseXSLTTemplate: mode %s\n", templ->mode);
5270
#endif
5271
    }
5272
    /*
5273
    * Attribute "match".
5274
    */
5275
    prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
5276
    if (prop != NULL) {
5277
  templ->match  = prop;
5278
  prop = NULL;
5279
    }
5280
    /*
5281
    * Attribute "priority".
5282
    */
5283
    prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
5284
    if (prop != NULL) {
5285
  priority = xmlXPathStringEvalNumber(prop);
5286
  templ->priority = (float) priority;
5287
  xmlFree(prop);
5288
  prop = NULL;
5289
    }
5290
    /*
5291
    * Attribute "name".
5292
    */
5293
    prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
5294
    if (prop != NULL) {
5295
        const xmlChar *nameURI;
5296
  xsltTemplatePtr curTempl;
5297
5298
  /*
5299
  * TODO: Don't use xsltGetQNameURI().
5300
  */
5301
  nameURI = xsltGetQNameURI(templNode, &prop);
5302
  if (prop == NULL) {
5303
      cctxt->style->errors++;
5304
      goto error;
5305
  }
5306
  templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
5307
  xmlFree(prop);
5308
  prop = NULL;
5309
  if (xmlValidateNCName(templ->name, 0)) {
5310
      xsltTransformError(NULL, cctxt->style, templNode,
5311
    "xsl:template: Attribute 'name': The local part '%s' of "
5312
    "the value is not a valid NCName.\n", templ->name);
5313
      cctxt->style->errors++;
5314
      goto error;
5315
  }
5316
  if (nameURI != NULL)
5317
      templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
5318
  curTempl = templ->next;
5319
  while (curTempl != NULL) {
5320
      if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
5321
    xmlStrEqual(curTempl->nameURI, nameURI) ) ||
5322
    (nameURI == NULL && curTempl->nameURI == NULL &&
5323
    xmlStrEqual(curTempl->name, templ->name)))
5324
      {
5325
    xsltTransformError(NULL, cctxt->style, templNode,
5326
        "xsl:template: error duplicate name '%s'\n", templ->name);
5327
    cctxt->style->errors++;
5328
    goto error;
5329
      }
5330
      curTempl = curTempl->next;
5331
  }
5332
    }
5333
    if (templNode->children != NULL) {
5334
  xsltParseTemplateContent(cctxt->style, templNode);
5335
  /*
5336
  * MAYBE TODO: Custom behaviour: In order to stay compatible with
5337
  * Xalan and MSXML(.NET), we could allow whitespace
5338
  * to appear before an xml:param element; this whitespace
5339
  * will additionally become part of the "template".
5340
  * NOTE that this is totally deviates from the spec, but
5341
  * is the de facto behaviour of Xalan and MSXML(.NET).
5342
  * Personally I wouldn't allow this, since if we have:
5343
  * <xsl:template ...xml:space="preserve">
5344
  *   <xsl:param name="foo"/>
5345
  *   <xsl:param name="bar"/>
5346
  *   <xsl:param name="zoo"/>
5347
  * ... the whitespace between every xsl:param would be
5348
  * added to the result tree.
5349
  */
5350
    }
5351
5352
    templ->elem = templNode;
5353
    templ->content = templNode->children;
5354
    xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
5355
5356
error:
5357
    xsltCompilerNodePop(cctxt, templNode);
5358
    return;
5359
}
5360
5361
#else /* XSLT_REFACTORED */
5362
5363
/**
5364
 * xsltParseStylesheetTemplate:
5365
 * @style:  the XSLT stylesheet
5366
 * @template:  the "template" element
5367
 *
5368
 * parse an XSLT stylesheet template building the associated structures
5369
 */
5370
5371
static void
5372
2.72k
xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
5373
2.72k
    xsltTemplatePtr ret;
5374
2.72k
    xmlChar *prop;
5375
2.72k
    xmlChar *mode = NULL;
5376
2.72k
    xmlChar *modeURI = NULL;
5377
2.72k
    double  priority;
5378
5379
2.72k
    if ((style == NULL) || (template == NULL) ||
5380
2.72k
        (template->type != XML_ELEMENT_NODE))
5381
0
  return;
5382
5383
2.72k
    if (style->principal->opLimit > 0) {
5384
2.72k
        if (style->principal->opCount > style->principal->opLimit) {
5385
2
            xsltTransformError(NULL, style, NULL,
5386
2
                "XSLT parser operation limit exceeded\n");
5387
2
      style->errors++;
5388
2
            return;
5389
2
        }
5390
2.72k
    }
5391
5392
    /*
5393
     * Create and link the structure
5394
     */
5395
2.72k
    ret = xsltNewTemplate();
5396
2.72k
    if (ret == NULL)
5397
1
  return;
5398
2.72k
    ret->next = style->templates;
5399
2.72k
    style->templates = ret;
5400
2.72k
    ret->style = style;
5401
5402
    /*
5403
     * Get inherited namespaces
5404
     */
5405
    /*
5406
    * TODO: Apply the optimized in-scope-namespace mechanism
5407
    *   as for the other XSLT instructions.
5408
    */
5409
2.72k
    xsltGetInheritedNsList(style, ret, template);
5410
5411
    /*
5412
     * Get arguments
5413
     */
5414
2.72k
    prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
5415
2.72k
    if (prop != NULL) {
5416
1
        const xmlChar *URI;
5417
5418
  /*
5419
  * TODO: Don't use xsltGetQNameURI().
5420
  */
5421
1
  URI = xsltGetQNameURI(template, &prop);
5422
1
  if (prop == NULL) {
5423
0
      if (style != NULL) style->errors++;
5424
0
      goto error;
5425
1
  } else {
5426
1
      mode = prop;
5427
1
      if (URI != NULL)
5428
0
    modeURI = xmlStrdup(URI);
5429
1
  }
5430
1
  ret->mode = xmlDictLookup(style->dict, mode, -1);
5431
1
  ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
5432
#ifdef WITH_XSLT_DEBUG_PARSING
5433
  xsltGenericDebug(xsltGenericDebugContext,
5434
       "xsltParseStylesheetTemplate: mode %s\n", mode);
5435
#endif
5436
1
        if (mode != NULL) xmlFree(mode);
5437
1
  if (modeURI != NULL) xmlFree(modeURI);
5438
1
    }
5439
2.72k
    prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
5440
2.72k
    if (prop != NULL) {
5441
2.67k
  if (ret->match != NULL) xmlFree(ret->match);
5442
2.67k
  ret->match  = prop;
5443
2.67k
    }
5444
5445
2.72k
    prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
5446
2.72k
    if (prop != NULL) {
5447
152
  priority = xmlXPathStringEvalNumber(prop);
5448
152
  ret->priority = (float) priority;
5449
152
  xmlFree(prop);
5450
152
    }
5451
5452
2.72k
    prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
5453
2.72k
    if (prop != NULL) {
5454
46
        const xmlChar *URI;
5455
5456
  /*
5457
  * TODO: Don't use xsltGetQNameURI().
5458
  */
5459
46
  URI = xsltGetQNameURI(template, &prop);
5460
46
  if (prop == NULL) {
5461
0
      if (style != NULL) style->errors++;
5462
0
      goto error;
5463
46
  } else {
5464
46
      if (xmlValidateNCName(prop,0)) {
5465
0
          xsltTransformError(NULL, style, template,
5466
0
              "xsl:template : error invalid name '%s'\n", prop);
5467
0
    if (style != NULL) style->errors++;
5468
0
                xmlFree(prop);
5469
0
    goto error;
5470
0
      }
5471
46
      ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
5472
46
      xmlFree(prop);
5473
46
      prop = NULL;
5474
46
      if (URI != NULL)
5475
0
    ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
5476
46
      else
5477
46
    ret->nameURI = NULL;
5478
46
  }
5479
46
    }
5480
5481
    /*
5482
     * parse the content and register the pattern
5483
     */
5484
2.72k
    xsltParseTemplateContent(style, template);
5485
2.72k
    ret->elem = template;
5486
2.72k
    ret->content = template->children;
5487
2.72k
    xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
5488
5489
2.72k
error:
5490
2.72k
    return;
5491
2.72k
}
5492
5493
#endif /* else XSLT_REFACTORED */
5494
5495
#ifdef XSLT_REFACTORED
5496
5497
/**
5498
 * xsltIncludeComp:
5499
 * @cctxt: the compilation context
5500
 * @node:  the xsl:include node
5501
 *
5502
 * Process the xslt include node on the source node
5503
 */
5504
static xsltStyleItemIncludePtr
5505
xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
5506
    xsltStyleItemIncludePtr item;
5507
5508
    if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
5509
  return(NULL);
5510
5511
    node->psvi = NULL;
5512
    item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
5513
    if (item == NULL) {
5514
  xsltTransformError(NULL, cctxt->style, node,
5515
    "xsltIncludeComp : malloc failed\n");
5516
  cctxt->style->errors++;
5517
  return(NULL);
5518
    }
5519
    memset(item, 0, sizeof(xsltStyleItemInclude));
5520
5521
    node->psvi = item;
5522
    item->inst = node;
5523
    item->type = XSLT_FUNC_INCLUDE;
5524
5525
    item->next = cctxt->style->preComps;
5526
    cctxt->style->preComps = (xsltElemPreCompPtr) item;
5527
5528
    return(item);
5529
}
5530
5531
static int
5532
xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
5533
            xmlNodePtr cur,
5534
            const xmlChar *name,
5535
            const xmlChar *namespaceURI,
5536
            int breakOnOtherElem,
5537
            xmlNodePtr *resultNode)
5538
{
5539
    if (name == NULL)
5540
  return(-1);
5541
5542
    *resultNode = NULL;
5543
    while (cur != NULL) {
5544
  if (cur->type == XML_ELEMENT_NODE) {
5545
      if ((cur->ns != NULL) && (cur->name != NULL)) {
5546
    if ((*(cur->name) == *name) &&
5547
        xmlStrEqual(cur->name, name) &&
5548
        xmlStrEqual(cur->ns->href, namespaceURI))
5549
    {
5550
        *resultNode = cur;
5551
        return(1);
5552
    }
5553
      }
5554
      if (breakOnOtherElem)
5555
    break;
5556
  }
5557
  cur = cur->next;
5558
    }
5559
    *resultNode = cur;
5560
    return(0);
5561
}
5562
5563
static int
5564
xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
5565
        xmlNodePtr node,
5566
        xsltStyleType type)
5567
{
5568
    int ret = 0;
5569
5570
    /*
5571
    * TODO: The reason why this function exists:
5572
    *  due to historical reasons some of the
5573
    *  top-level declarations are processed by functions
5574
    *  in other files. Since we need still to set
5575
    *  up the node-info and generate information like
5576
    *  in-scope namespaces, this is a wrapper around
5577
    *  those old parsing functions.
5578
    */
5579
    xsltCompilerNodePush(cctxt, node);
5580
    if (node->nsDef != NULL)
5581
  cctxt->inode->inScopeNs =
5582
      xsltCompilerBuildInScopeNsList(cctxt, node);
5583
    cctxt->inode->type = type;
5584
5585
    switch (type) {
5586
  case XSLT_FUNC_INCLUDE:
5587
      {
5588
    int oldIsInclude;
5589
5590
    if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
5591
        goto exit;
5592
    /*
5593
    * Mark this stylesheet tree as being currently included.
5594
    */
5595
    oldIsInclude = cctxt->isInclude;
5596
    cctxt->isInclude = 1;
5597
5598
    if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
5599
        cctxt->style->errors++;
5600
    }
5601
    cctxt->isInclude = oldIsInclude;
5602
      }
5603
      break;
5604
  case XSLT_FUNC_PARAM:
5605
      xsltStylePreCompute(cctxt->style, node);
5606
      xsltParseGlobalParam(cctxt->style, node);
5607
      break;
5608
  case XSLT_FUNC_VARIABLE:
5609
      xsltStylePreCompute(cctxt->style, node);
5610
      xsltParseGlobalVariable(cctxt->style, node);
5611
      break;
5612
  case XSLT_FUNC_ATTRSET:
5613
      xsltParseStylesheetAttributeSet(cctxt->style, node);
5614
      break;
5615
  default:
5616
      xsltTransformError(NULL, cctxt->style, node,
5617
    "Internal error: (xsltParseTopLevelXSLTElem) "
5618
    "Cannot handle this top-level declaration.\n");
5619
      cctxt->style->errors++;
5620
      ret = -1;
5621
    }
5622
5623
exit:
5624
    xsltCompilerNodePop(cctxt, node);
5625
5626
    return(ret);
5627
}
5628
5629
#if 0
5630
static int
5631
xsltParseRemoveWhitespace(xmlNodePtr node)
5632
{
5633
    if ((node == NULL) || (node->children == NULL))
5634
  return(0);
5635
    else {
5636
  xmlNodePtr delNode = NULL, child = node->children;
5637
5638
  do {
5639
      if (delNode) {
5640
    xmlUnlinkNode(delNode);
5641
    xmlFreeNode(delNode);
5642
    delNode = NULL;
5643
      }
5644
      if (((child->type == XML_TEXT_NODE) ||
5645
     (child->type == XML_CDATA_SECTION_NODE)) &&
5646
    (IS_BLANK_NODE(child)))
5647
    delNode = child;
5648
      child = child->next;
5649
  } while (child != NULL);
5650
  if (delNode) {
5651
      xmlUnlinkNode(delNode);
5652
      xmlFreeNode(delNode);
5653
      delNode = NULL;
5654
  }
5655
    }
5656
    return(0);
5657
}
5658
#endif
5659
5660
static int
5661
xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
5662
{
5663
#ifdef WITH_XSLT_DEBUG_PARSING
5664
    int templates = 0;
5665
#endif
5666
    xmlNodePtr cur, start = NULL;
5667
    xsltStylesheetPtr style;
5668
5669
    if ((cctxt == NULL) || (node == NULL) ||
5670
  (node->type != XML_ELEMENT_NODE))
5671
  return(-1);
5672
5673
    style = cctxt->style;
5674
    /*
5675
    * At this stage all import declarations of all stylesheet modules
5676
    * with the same stylesheet level have been processed.
5677
    * Now we can safely parse the rest of the declarations.
5678
    */
5679
    if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
5680
    {
5681
  xsltDocumentPtr include;
5682
  /*
5683
  * URGENT TODO: Make this work with simplified stylesheets!
5684
  *   I.e., when we won't find an xsl:stylesheet element.
5685
  */
5686
  /*
5687
  * This is as include declaration.
5688
  */
5689
  include = ((xsltStyleItemIncludePtr) node->psvi)->include;
5690
  if (include == NULL) {
5691
      /* TODO: raise error? */
5692
      return(-1);
5693
  }
5694
  /*
5695
  * TODO: Actually an xsl:include should locate an embedded
5696
  *  stylesheet as well; so the document-element won't always
5697
  *  be the element where the actual stylesheet is rooted at.
5698
  *  But such embedded stylesheets are not supported by Libxslt yet.
5699
  */
5700
  node = xmlDocGetRootElement(include->doc);
5701
  if (node == NULL) {
5702
      return(-1);
5703
  }
5704
    }
5705
5706
    if (node->children == NULL)
5707
  return(0);
5708
    /*
5709
    * Push the xsl:stylesheet/xsl:transform element.
5710
    */
5711
    xsltCompilerNodePush(cctxt, node);
5712
    cctxt->inode->isRoot = 1;
5713
    cctxt->inode->nsChanged = 0;
5714
    /*
5715
    * Start with the naked dummy info for literal result elements.
5716
    */
5717
    cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
5718
5719
    /*
5720
    * In every case, we need to have
5721
    * the in-scope namespaces of the element, where the
5722
    * stylesheet is rooted at, regardless if it's an XSLT
5723
    * instruction or a literal result instruction (or if
5724
    * this is an embedded stylesheet).
5725
    */
5726
    cctxt->inode->inScopeNs =
5727
  xsltCompilerBuildInScopeNsList(cctxt, node);
5728
5729
    /*
5730
    * Process attributes of xsl:stylesheet/xsl:transform.
5731
    * --------------------------------------------------
5732
    * Allowed are:
5733
    *  id = id
5734
    *  extension-element-prefixes = tokens
5735
    *  exclude-result-prefixes = tokens
5736
    *  version = number (mandatory)
5737
    */
5738
    if (xsltParseAttrXSLTVersion(cctxt, node,
5739
  XSLT_ELEMENT_CATEGORY_XSLT) == 0)
5740
    {
5741
  /*
5742
  * Attribute "version".
5743
  * XSLT 1.0: "An xsl:stylesheet element *must* have a version
5744
  *  attribute, indicating the version of XSLT that the
5745
  *  stylesheet requires".
5746
  * The root element of a simplified stylesheet must also have
5747
  * this attribute.
5748
  */
5749
#ifdef XSLT_REFACTORED_MANDATORY_VERSION
5750
  if (isXsltElem)
5751
      xsltTransformError(NULL, cctxt->style, node,
5752
    "The attribute 'version' is missing.\n");
5753
  cctxt->style->errors++;
5754
#else
5755
  /* OLD behaviour. */
5756
  xsltTransformError(NULL, cctxt->style, node,
5757
      "xsl:version is missing: document may not be a stylesheet\n");
5758
  cctxt->style->warnings++;
5759
#endif
5760
    }
5761
    /*
5762
    * The namespaces declared by the attributes
5763
    *  "extension-element-prefixes" and
5764
    *  "exclude-result-prefixes" are local to *this*
5765
    *  stylesheet tree; i.e., they are *not* visible to
5766
    *  other stylesheet-modules, whether imported or included.
5767
    *
5768
    * Attribute "extension-element-prefixes".
5769
    */
5770
    cctxt->inode->extElemNs =
5771
  xsltParseExtElemPrefixes(cctxt, node, NULL,
5772
      XSLT_ELEMENT_CATEGORY_XSLT);
5773
    /*
5774
    * Attribute "exclude-result-prefixes".
5775
    */
5776
    cctxt->inode->exclResultNs =
5777
  xsltParseExclResultPrefixes(cctxt, node, NULL,
5778
      XSLT_ELEMENT_CATEGORY_XSLT);
5779
    /*
5780
    * Create/reuse info for the literal result element.
5781
    */
5782
    if (cctxt->inode->nsChanged)
5783
  xsltLREInfoCreate(cctxt, node, 0);
5784
    /*
5785
    * Processed top-level elements:
5786
    * ----------------------------
5787
    *  xsl:variable, xsl:param (QName, in-scope ns,
5788
    *    expression (vars allowed))
5789
    *  xsl:attribute-set (QName, in-scope ns)
5790
    *  xsl:strip-space, xsl:preserve-space (XPath NameTests,
5791
    *    in-scope ns)
5792
    *    I *think* global scope, merge with includes
5793
    *  xsl:output (QName, in-scope ns)
5794
    *  xsl:key (QName, in-scope ns, pattern,
5795
    *    expression (vars *not* allowed))
5796
    *  xsl:decimal-format (QName, needs in-scope ns)
5797
    *  xsl:namespace-alias (in-scope ns)
5798
    *    global scope, merge with includes
5799
    *  xsl:template (last, QName, pattern)
5800
    *
5801
    * (whitespace-only text-nodes have *not* been removed
5802
    *  yet; this will be done in xsltParseSequenceConstructor)
5803
    *
5804
    * Report misplaced child-nodes first.
5805
    */
5806
    cur = node->children;
5807
    while (cur != NULL) {
5808
  if (cur->type == XML_TEXT_NODE) {
5809
      xsltTransformError(NULL, style, cur,
5810
    "Misplaced text node (content: '%s').\n",
5811
    (cur->content != NULL) ? cur->content : BAD_CAST "");
5812
      style->errors++;
5813
  } else if (cur->type != XML_ELEMENT_NODE) {
5814
      xsltTransformError(NULL, style, cur, "Misplaced node.\n");
5815
      style->errors++;
5816
  }
5817
  cur = cur->next;
5818
    }
5819
    /*
5820
    * Skip xsl:import elements; they have been processed
5821
    * already.
5822
    */
5823
    cur = node->children;
5824
    while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
5825
      BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
5826
  cur = cur->next;
5827
    if (cur == NULL)
5828
  goto exit;
5829
5830
    start = cur;
5831
    /*
5832
    * Process all top-level xsl:param elements.
5833
    */
5834
    while ((cur != NULL) &&
5835
  xsltParseFindTopLevelElem(cctxt, cur,
5836
  BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
5837
    {
5838
  xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);
5839
  cur = cur->next;
5840
    }
5841
    /*
5842
    * Process all top-level xsl:variable elements.
5843
    */
5844
    cur = start;
5845
    while ((cur != NULL) &&
5846
  xsltParseFindTopLevelElem(cctxt, cur,
5847
  BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
5848
    {
5849
  xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
5850
  cur = cur->next;
5851
    }
5852
    /*
5853
    * Process all the rest of top-level elements.
5854
    */
5855
    cur = start;
5856
    while (cur != NULL) {
5857
  /*
5858
  * Process element nodes.
5859
  */
5860
  if (cur->type == XML_ELEMENT_NODE) {
5861
      if (cur->ns == NULL) {
5862
    xsltTransformError(NULL, style, cur,
5863
        "Unexpected top-level element in no namespace.\n");
5864
    style->errors++;
5865
    cur = cur->next;
5866
    continue;
5867
      }
5868
      /*
5869
      * Process all XSLT elements.
5870
      */
5871
      if (IS_XSLT_ELEM_FAST(cur)) {
5872
    /*
5873
    * xsl:import is only allowed at the beginning.
5874
    */
5875
    if (IS_XSLT_NAME(cur, "import")) {
5876
        xsltTransformError(NULL, style, cur,
5877
      "Misplaced xsl:import element.\n");
5878
        style->errors++;
5879
        cur = cur->next;
5880
        continue;
5881
    }
5882
    /*
5883
    * TODO: Change the return type of the parsing functions
5884
    *  to int.
5885
    */
5886
    if (IS_XSLT_NAME(cur, "template")) {
5887
#ifdef WITH_XSLT_DEBUG_PARSING
5888
        templates++;
5889
#endif
5890
        /*
5891
        * TODO: Is the position of xsl:template in the
5892
        *  tree significant? If not it would be easier to
5893
        *  parse them at a later stage.
5894
        */
5895
        xsltParseXSLTTemplate(cctxt, cur);
5896
    } else if (IS_XSLT_NAME(cur, "variable")) {
5897
        /* NOP; done already */
5898
    } else if (IS_XSLT_NAME(cur, "param")) {
5899
        /* NOP; done already */
5900
    } else if (IS_XSLT_NAME(cur, "include")) {
5901
        if (cur->psvi != NULL)
5902
      xsltParseXSLTStylesheetElemCore(cctxt, cur);
5903
        else {
5904
      xsltTransformError(NULL, style, cur,
5905
          "Internal error: "
5906
          "(xsltParseXSLTStylesheetElemCore) "
5907
          "The xsl:include element was not compiled.\n");
5908
      style->errors++;
5909
        }
5910
    } else if (IS_XSLT_NAME(cur, "strip-space")) {
5911
        /* No node info needed. */
5912
        xsltParseStylesheetStripSpace(style, cur);
5913
    } else if (IS_XSLT_NAME(cur, "preserve-space")) {
5914
        /* No node info needed. */
5915
        xsltParseStylesheetPreserveSpace(style, cur);
5916
    } else if (IS_XSLT_NAME(cur, "output")) {
5917
        /* No node-info needed. */
5918
        xsltParseStylesheetOutput(style, cur);
5919
    } else if (IS_XSLT_NAME(cur, "key")) {
5920
        /* TODO: node-info needed for expressions ? */
5921
        xsltParseStylesheetKey(style, cur);
5922
    } else if (IS_XSLT_NAME(cur, "decimal-format")) {
5923
        /* No node-info needed. */
5924
        xsltParseStylesheetDecimalFormat(style, cur);
5925
    } else if (IS_XSLT_NAME(cur, "attribute-set")) {
5926
        xsltParseTopLevelXSLTElem(cctxt, cur,
5927
      XSLT_FUNC_ATTRSET);
5928
    } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
5929
        /* NOP; done already */
5930
    } else {
5931
        if (cctxt->inode->forwardsCompat) {
5932
      /*
5933
      * Forwards-compatible mode:
5934
      *
5935
      * XSLT-1: "if it is a top-level element and
5936
      *  XSLT 1.0 does not allow such elements as top-level
5937
      *  elements, then the element must be ignored along
5938
      *  with its content;"
5939
      */
5940
      /*
5941
      * TODO: I don't think we should generate a warning.
5942
      */
5943
      xsltTransformError(NULL, style, cur,
5944
          "Forwards-compatible mode: Ignoring unknown XSLT "
5945
          "element '%s'.\n", cur->name);
5946
      style->warnings++;
5947
        } else {
5948
      xsltTransformError(NULL, style, cur,
5949
          "Unknown XSLT element '%s'.\n", cur->name);
5950
      style->errors++;
5951
        }
5952
    }
5953
      } else {
5954
    xsltTopLevelFunction function;
5955
5956
    /*
5957
    * Process non-XSLT elements, which are in a
5958
    *  non-NULL namespace.
5959
    */
5960
    /*
5961
    * QUESTION: What does xsltExtModuleTopLevelLookup()
5962
    *  do exactly?
5963
    */
5964
    function = xsltExtModuleTopLevelLookup(cur->name,
5965
        cur->ns->href);
5966
    if (function != NULL)
5967
        function(style, cur);
5968
#ifdef WITH_XSLT_DEBUG_PARSING
5969
    xsltGenericDebug(xsltGenericDebugContext,
5970
        "xsltParseXSLTStylesheetElemCore : User-defined "
5971
        "data element '%s'.\n", cur->name);
5972
#endif
5973
      }
5974
  }
5975
  cur = cur->next;
5976
    }
5977
5978
exit:
5979
5980
#ifdef WITH_XSLT_DEBUG_PARSING
5981
    xsltGenericDebug(xsltGenericDebugContext,
5982
  "### END of parsing top-level elements of doc '%s'.\n",
5983
  node->doc->URL);
5984
    xsltGenericDebug(xsltGenericDebugContext,
5985
  "### Templates: %d\n", templates);
5986
#ifdef XSLT_REFACTORED
5987
    xsltGenericDebug(xsltGenericDebugContext,
5988
  "### Max inodes: %d\n", cctxt->maxNodeInfos);
5989
    xsltGenericDebug(xsltGenericDebugContext,
5990
  "### Max LREs  : %d\n", cctxt->maxLREs);
5991
#endif /* XSLT_REFACTORED */
5992
#endif /* WITH_XSLT_DEBUG_PARSING */
5993
5994
    xsltCompilerNodePop(cctxt, node);
5995
    return(0);
5996
}
5997
5998
/**
5999
 * xsltParseXSLTStylesheet:
6000
 * @cctxt: the compiler context
6001
 * @node: the xsl:stylesheet/xsl:transform element-node
6002
 *
6003
 * Parses the xsl:stylesheet and xsl:transform element.
6004
 *
6005
 * <xsl:stylesheet
6006
 *  id = id
6007
 *  extension-element-prefixes = tokens
6008
 *  exclude-result-prefixes = tokens
6009
 *  version = number>
6010
 *  <!-- Content: (xsl:import*, top-level-elements) -->
6011
 * </xsl:stylesheet>
6012
 *
6013
 * BIG TODO: The xsl:include stuff.
6014
 *
6015
 * Called by xsltParseStylesheetTree()
6016
 *
6017
 * Returns 0 on success, a positive result on errors and
6018
 *         -1 on API or internal errors.
6019
 */
6020
static int
6021
xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
6022
{
6023
    xmlNodePtr cur, start;
6024
6025
    if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
6026
  return(-1);
6027
6028
    if (node->children == NULL)
6029
  goto exit;
6030
6031
    /*
6032
    * Process top-level elements:
6033
    *  xsl:import (must be first)
6034
    *  xsl:include (this is just a pre-processing)
6035
    */
6036
    cur = node->children;
6037
    /*
6038
    * Process xsl:import elements.
6039
    * XSLT 1.0: "The xsl:import element children must precede all
6040
    *  other element children of an xsl:stylesheet element,
6041
    *  including any xsl:include element children."
6042
    */
6043
    while ((cur != NULL) &&
6044
  xsltParseFindTopLevelElem(cctxt, cur,
6045
      BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
6046
    {
6047
  if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
6048
      cctxt->style->errors++;
6049
  }
6050
  cur = cur->next;
6051
    }
6052
    if (cur == NULL)
6053
  goto exit;
6054
    start = cur;
6055
    /*
6056
    * Pre-process all xsl:include elements.
6057
    */
6058
    cur = start;
6059
    while ((cur != NULL) &&
6060
  xsltParseFindTopLevelElem(cctxt, cur,
6061
      BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
6062
    {
6063
  xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
6064
  cur = cur->next;
6065
    }
6066
    /*
6067
    * Pre-process all xsl:namespace-alias elements.
6068
    * URGENT TODO: This won't work correctly: the order of included
6069
    *  aliases and aliases defined here is significant.
6070
    */
6071
    cur = start;
6072
    while ((cur != NULL) &&
6073
  xsltParseFindTopLevelElem(cctxt, cur,
6074
      BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
6075
    {
6076
  xsltNamespaceAlias(cctxt->style, cur);
6077
  cur = cur->next;
6078
    }
6079
6080
    if (cctxt->isInclude) {
6081
  /*
6082
  * If this stylesheet is intended for inclusion, then
6083
  * we will process only imports and includes.
6084
  */
6085
  goto exit;
6086
    }
6087
    /*
6088
    * Now parse the rest of the top-level elements.
6089
    */
6090
    xsltParseXSLTStylesheetElemCore(cctxt, node);
6091
exit:
6092
6093
    return(0);
6094
}
6095
6096
#else /* XSLT_REFACTORED */
6097
6098
/**
6099
 * xsltParseStylesheetTop:
6100
 * @style:  the XSLT stylesheet
6101
 * @top:  the top level "stylesheet" or "transform" element
6102
 *
6103
 * scan the top level elements of an XSL stylesheet
6104
 */
6105
static void
6106
8.46k
xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
6107
8.46k
    xmlNodePtr cur;
6108
8.46k
    xmlChar *prop;
6109
#ifdef WITH_XSLT_DEBUG_PARSING
6110
    int templates = 0;
6111
#endif
6112
6113
8.46k
    if ((top == NULL) || (top->type != XML_ELEMENT_NODE))
6114
0
  return;
6115
6116
8.46k
    if (style->principal->opLimit > 0) {
6117
8.46k
        if (style->principal->opCount > style->principal->opLimit) {
6118
115
            xsltTransformError(NULL, style, NULL,
6119
115
                "XSLT parser operation limit exceeded\n");
6120
115
      style->errors++;
6121
115
            return;
6122
115
        }
6123
8.46k
    }
6124
6125
8.35k
    prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
6126
8.35k
    if (prop == NULL) {
6127
7.66k
  xsltTransformError(NULL, style, top,
6128
7.66k
      "xsl:version is missing: document may not be a stylesheet\n");
6129
7.66k
  if (style != NULL) style->warnings++;
6130
7.66k
    } else {
6131
685
  if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6132
685
            (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6133
371
      xsltTransformError(NULL, style, top,
6134
371
    "xsl:version: only 1.1 features are supported\n");
6135
371
      if (style != NULL) {
6136
371
                style->forwards_compatible = 1;
6137
371
                style->warnings++;
6138
371
            }
6139
371
  }
6140
685
  xmlFree(prop);
6141
685
    }
6142
6143
    /*
6144
     * process xsl:import elements
6145
     */
6146
8.35k
    cur = top->children;
6147
29.9k
    while (cur != NULL) {
6148
25.2k
            style->principal->opCount += 1;
6149
6150
25.2k
      if (IS_BLANK_NODE(cur)) {
6151
0
        cur = cur->next;
6152
0
        continue;
6153
0
      }
6154
25.2k
      if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
6155
21.6k
        if (xsltParseStylesheetImport(style, cur) != 0)
6156
20.1k
          if (style != NULL) style->errors++;
6157
21.6k
      } else
6158
3.65k
        break;
6159
21.6k
      cur = cur->next;
6160
21.6k
    }
6161
6162
    /*
6163
     * process other top-level elements
6164
     */
6165
34.5k
    while (cur != NULL) {
6166
26.2k
        style->principal->opCount += 1;
6167
6168
26.2k
  if (IS_BLANK_NODE(cur)) {
6169
0
      cur = cur->next;
6170
0
      continue;
6171
0
  }
6172
26.2k
  if (cur->type == XML_TEXT_NODE) {
6173
9.95k
      if (cur->content != NULL) {
6174
9.95k
    xsltTransformError(NULL, style, cur,
6175
9.95k
        "misplaced text node: '%s'\n", cur->content);
6176
9.95k
      }
6177
9.95k
      if (style != NULL) style->errors++;
6178
9.95k
            cur = cur->next;
6179
9.95k
      continue;
6180
9.95k
  }
6181
16.2k
  if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
6182
1.30k
      xsltGenericError(xsltGenericErrorContext,
6183
1.30k
         "Found a top-level element %s with null namespace URI\n",
6184
1.30k
         cur->name);
6185
1.30k
      if (style != NULL) style->errors++;
6186
1.30k
      cur = cur->next;
6187
1.30k
      continue;
6188
1.30k
  }
6189
14.9k
  if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
6190
731
      xsltTopLevelFunction function;
6191
6192
731
      function = xsltExtModuleTopLevelLookup(cur->name,
6193
731
               cur->ns->href);
6194
731
      if (function != NULL)
6195
205
    function(style, cur);
6196
6197
#ifdef WITH_XSLT_DEBUG_PARSING
6198
      xsltGenericDebug(xsltGenericDebugContext,
6199
        "xsltParseStylesheetTop : found foreign element %s\n",
6200
        cur->name);
6201
#endif
6202
731
            cur = cur->next;
6203
731
      continue;
6204
731
  }
6205
14.2k
  if (IS_XSLT_NAME(cur, "import")) {
6206
702
      xsltTransformError(NULL, style, cur,
6207
702
      "xsltParseStylesheetTop: ignoring misplaced import element\n");
6208
702
      if (style != NULL) style->errors++;
6209
13.5k
        } else if (IS_XSLT_NAME(cur, "include")) {
6210
4.14k
      if (xsltParseStylesheetInclude(style, cur) != 0)
6211
2.97k
    if (style != NULL) style->errors++;
6212
9.39k
        } else if (IS_XSLT_NAME(cur, "strip-space")) {
6213
394
      xsltParseStylesheetStripSpace(style, cur);
6214
9.00k
        } else if (IS_XSLT_NAME(cur, "preserve-space")) {
6215
134
      xsltParseStylesheetPreserveSpace(style, cur);
6216
8.86k
        } else if (IS_XSLT_NAME(cur, "output")) {
6217
1.17k
      xsltParseStylesheetOutput(style, cur);
6218
7.69k
        } else if (IS_XSLT_NAME(cur, "key")) {
6219
5
      xsltParseStylesheetKey(style, cur);
6220
7.69k
        } else if (IS_XSLT_NAME(cur, "decimal-format")) {
6221
7
      xsltParseStylesheetDecimalFormat(style, cur);
6222
7.68k
        } else if (IS_XSLT_NAME(cur, "attribute-set")) {
6223
483
      xsltParseStylesheetAttributeSet(style, cur);
6224
7.20k
        } else if (IS_XSLT_NAME(cur, "variable")) {
6225
1.17k
      xsltParseGlobalVariable(style, cur);
6226
6.02k
        } else if (IS_XSLT_NAME(cur, "param")) {
6227
4
      xsltParseGlobalParam(style, cur);
6228
6.01k
        } else if (IS_XSLT_NAME(cur, "template")) {
6229
#ifdef WITH_XSLT_DEBUG_PARSING
6230
      templates++;
6231
#endif
6232
2.72k
      xsltParseStylesheetTemplate(style, cur);
6233
3.29k
        } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
6234
244
      xsltNamespaceAlias(style, cur);
6235
3.05k
  } else {
6236
3.05k
            if ((style != NULL) && (style->forwards_compatible == 0)) {
6237
2.99k
          xsltTransformError(NULL, style, cur,
6238
2.99k
      "xsltParseStylesheetTop: unknown %s element\n",
6239
2.99k
      cur->name);
6240
2.99k
          if (style != NULL) style->errors++;
6241
2.99k
      }
6242
3.05k
  }
6243
14.2k
  cur = cur->next;
6244
14.2k
    }
6245
#ifdef WITH_XSLT_DEBUG_PARSING
6246
    xsltGenericDebug(xsltGenericDebugContext,
6247
        "parsed %d templates\n", templates);
6248
#endif
6249
8.35k
}
6250
6251
#endif /* else of XSLT_REFACTORED */
6252
6253
#ifdef XSLT_REFACTORED
6254
/**
6255
 * xsltParseSimplifiedStylesheetTree:
6256
 *
6257
 * @style: the stylesheet (TODO: Change this to the compiler context)
6258
 * @doc: the document containing the stylesheet.
6259
 * @node: the node where the stylesheet is rooted at
6260
 *
6261
 * Returns 0 in case of success, a positive result if an error occurred
6262
 *         and -1 on API and internal errors.
6263
 */
6264
static int
6265
xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
6266
          xmlDocPtr doc,
6267
          xmlNodePtr node)
6268
{
6269
    xsltTemplatePtr templ;
6270
6271
    if ((cctxt == NULL) || (node == NULL))
6272
  return(-1);
6273
6274
    if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
6275
    {
6276
  /*
6277
  * TODO: Adjust report, since this might be an
6278
  * embedded stylesheet.
6279
  */
6280
  xsltTransformError(NULL, cctxt->style, node,
6281
      "The attribute 'xsl:version' is missing; cannot identify "
6282
      "this document as an XSLT stylesheet document.\n");
6283
  cctxt->style->errors++;
6284
  return(1);
6285
    }
6286
6287
#ifdef WITH_XSLT_DEBUG_PARSING
6288
    xsltGenericDebug(xsltGenericDebugContext,
6289
  "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6290
#endif
6291
6292
    /*
6293
    * Create and link the template
6294
    */
6295
    templ = xsltNewTemplate();
6296
    if (templ == NULL) {
6297
  return(-1);
6298
    }
6299
    templ->next = cctxt->style->templates;
6300
    cctxt->style->templates = templ;
6301
    templ->match = xmlStrdup(BAD_CAST "/");
6302
6303
    /*
6304
    * Note that we push the document-node in this special case.
6305
    */
6306
    xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6307
    /*
6308
    * In every case, we need to have
6309
    * the in-scope namespaces of the element, where the
6310
    * stylesheet is rooted at, regardless if it's an XSLT
6311
    * instruction or a literal result instruction (or if
6312
    * this is an embedded stylesheet).
6313
    */
6314
    cctxt->inode->inScopeNs =
6315
  xsltCompilerBuildInScopeNsList(cctxt, node);
6316
    /*
6317
    * Parse the content and register the match-pattern.
6318
    */
6319
    xsltParseSequenceConstructor(cctxt, node);
6320
    xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6321
6322
    templ->elem = (xmlNodePtr) doc;
6323
    templ->content = node;
6324
    xsltAddTemplate(cctxt->style, templ, NULL, NULL);
6325
    cctxt->style->literal_result = 1;
6326
    return(0);
6327
}
6328
6329
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
6330
/**
6331
 * xsltRestoreDocumentNamespaces:
6332
 * @ns: map of namespaces
6333
 * @doc: the document
6334
 *
6335
 * Restore the namespaces for the document
6336
 *
6337
 * Returns 0 in case of success, -1 in case of failure
6338
 */
6339
int
6340
xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
6341
{
6342
    if (doc == NULL)
6343
  return(-1);
6344
    /*
6345
    * Revert the changes we have applied to the namespace-URIs of
6346
    * ns-decls.
6347
    */
6348
    while (ns != NULL) {
6349
  if ((ns->doc == doc) && (ns->ns != NULL)) {
6350
      ns->ns->href = ns->origNsName;
6351
      ns->origNsName = NULL;
6352
      ns->ns = NULL;
6353
  }
6354
  ns = ns->next;
6355
    }
6356
    return(0);
6357
}
6358
#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6359
6360
/**
6361
 * xsltParseStylesheetProcess:
6362
 * @style:  the XSLT stylesheet (the current stylesheet-level)
6363
 * @doc:  and xmlDoc parsed XML
6364
 *
6365
 * Parses an XSLT stylesheet, adding the associated structures.
6366
 * Called by:
6367
 *  xsltParseStylesheetImportedDoc() (xslt.c)
6368
 *  xsltParseStylesheetInclude() (imports.c)
6369
 *
6370
 * Returns the value of the @style parameter if everything
6371
 * went right, NULL if something went amiss.
6372
 */
6373
xsltStylesheetPtr
6374
xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
6375
{
6376
    xsltCompilerCtxtPtr cctxt;
6377
    xmlNodePtr cur;
6378
    int oldIsSimplifiedStylesheet;
6379
6380
    xsltInitGlobals();
6381
6382
    if ((style == NULL) || (doc == NULL))
6383
  return(NULL);
6384
6385
    cctxt = XSLT_CCTXT(style);
6386
6387
    cur = xmlDocGetRootElement(doc);
6388
    if (cur == NULL) {
6389
  xsltTransformError(NULL, style, (xmlNodePtr) doc,
6390
    "xsltParseStylesheetProcess : empty stylesheet\n");
6391
  return(NULL);
6392
    }
6393
    oldIsSimplifiedStylesheet = cctxt->simplified;
6394
6395
    if ((IS_XSLT_ELEM(cur)) &&
6396
  ((IS_XSLT_NAME(cur, "stylesheet")) ||
6397
   (IS_XSLT_NAME(cur, "transform")))) {
6398
#ifdef WITH_XSLT_DEBUG_PARSING
6399
  xsltGenericDebug(xsltGenericDebugContext,
6400
    "xsltParseStylesheetProcess : found stylesheet\n");
6401
#endif
6402
  cctxt->simplified = 0;
6403
  style->literal_result = 0;
6404
    } else {
6405
  cctxt->simplified = 1;
6406
  style->literal_result = 1;
6407
    }
6408
    /*
6409
    * Pre-process the stylesheet if not already done before.
6410
    *  This will remove PIs and comments, merge adjacent
6411
    *  text nodes, internalize strings, etc.
6412
    */
6413
    if (! style->nopreproc)
6414
  xsltParsePreprocessStylesheetTree(cctxt, cur);
6415
    /*
6416
    * Parse and compile the stylesheet.
6417
    */
6418
    if (style->literal_result == 0) {
6419
  if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
6420
      return(NULL);
6421
    } else {
6422
  if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
6423
      return(NULL);
6424
    }
6425
6426
    cctxt->simplified = oldIsSimplifiedStylesheet;
6427
6428
    return(style);
6429
}
6430
6431
#else /* XSLT_REFACTORED */
6432
6433
/**
6434
 * xsltParseStylesheetProcess:
6435
 * @ret:  the XSLT stylesheet (the current stylesheet-level)
6436
 * @doc:  and xmlDoc parsed XML
6437
 *
6438
 * Parses an XSLT stylesheet, adding the associated structures.
6439
 * Called by:
6440
 *  xsltParseStylesheetImportedDoc() (xslt.c)
6441
 *  xsltParseStylesheetInclude() (imports.c)
6442
 *
6443
 * Returns the value of the @style parameter if everything
6444
 * went right, NULL if something went amiss.
6445
 */
6446
xsltStylesheetPtr
6447
8.57k
xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
6448
8.57k
    xmlNodePtr cur;
6449
6450
8.57k
    xsltInitGlobals();
6451
6452
8.57k
    if (doc == NULL)
6453
0
  return(NULL);
6454
8.57k
    if (ret == NULL)
6455
0
  return(ret);
6456
6457
    /*
6458
     * First steps, remove blank nodes,
6459
     * locate the xsl:stylesheet element and the
6460
     * namespace declaration.
6461
     */
6462
8.57k
    cur = xmlDocGetRootElement(doc);
6463
8.57k
    if (cur == NULL) {
6464
0
  xsltTransformError(NULL, ret, (xmlNodePtr) doc,
6465
0
    "xsltParseStylesheetProcess : empty stylesheet\n");
6466
0
  return(NULL);
6467
0
    }
6468
6469
8.57k
    if ((IS_XSLT_ELEM(cur)) &&
6470
8.57k
  ((IS_XSLT_NAME(cur, "stylesheet")) ||
6471
8.46k
   (IS_XSLT_NAME(cur, "transform")))) {
6472
#ifdef WITH_XSLT_DEBUG_PARSING
6473
  xsltGenericDebug(xsltGenericDebugContext,
6474
    "xsltParseStylesheetProcess : found stylesheet\n");
6475
#endif
6476
8.46k
  ret->literal_result = 0;
6477
8.46k
  xsltParseStylesheetExcludePrefix(ret, cur, 1);
6478
8.46k
  xsltParseStylesheetExtPrefix(ret, cur, 1);
6479
8.46k
    } else {
6480
106
  xsltParseStylesheetExcludePrefix(ret, cur, 0);
6481
106
  xsltParseStylesheetExtPrefix(ret, cur, 0);
6482
106
  ret->literal_result = 1;
6483
106
    }
6484
8.57k
    if (!ret->nopreproc) {
6485
8.57k
  xsltPreprocessStylesheet(ret, cur);
6486
8.57k
    }
6487
8.57k
    if (ret->literal_result == 0) {
6488
8.46k
  xsltParseStylesheetTop(ret, cur);
6489
8.46k
    } else {
6490
106
  xmlChar *prop;
6491
106
  xsltTemplatePtr template;
6492
6493
  /*
6494
   * the document itself might be the template, check xsl:version
6495
   */
6496
106
  prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
6497
106
  if (prop == NULL) {
6498
28
      xsltTransformError(NULL, ret, cur,
6499
28
    "xsltParseStylesheetProcess : document is not a stylesheet\n");
6500
28
      return(NULL);
6501
28
  }
6502
6503
#ifdef WITH_XSLT_DEBUG_PARSING
6504
        xsltGenericDebug(xsltGenericDebugContext,
6505
    "xsltParseStylesheetProcess : document is stylesheet\n");
6506
#endif
6507
6508
78
  if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6509
78
            (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6510
78
      xsltTransformError(NULL, ret, cur,
6511
78
    "xsl:version: only 1.1 features are supported\n");
6512
78
            ret->forwards_compatible = 1;
6513
78
      ret->warnings++;
6514
78
  }
6515
78
  xmlFree(prop);
6516
6517
  /*
6518
   * Create and link the template
6519
   */
6520
78
  template = xsltNewTemplate();
6521
78
  if (template == NULL) {
6522
0
      return(NULL);
6523
0
  }
6524
78
  template->next = ret->templates;
6525
78
  ret->templates = template;
6526
78
  template->match = xmlStrdup((const xmlChar *)"/");
6527
6528
  /*
6529
   * parse the content and register the pattern
6530
   */
6531
78
  xsltParseTemplateContent(ret, (xmlNodePtr) doc);
6532
78
  template->elem = (xmlNodePtr) doc;
6533
78
  template->content = doc->children;
6534
78
  xsltAddTemplate(ret, template, NULL, NULL);
6535
78
  ret->literal_result = 1;
6536
78
    }
6537
6538
8.54k
    return(ret);
6539
8.57k
}
6540
6541
#endif /* else of XSLT_REFACTORED */
6542
6543
/**
6544
 * xsltParseStylesheetImportedDoc:
6545
 * @doc:  an xmlDoc parsed XML
6546
 * @parentStyle: pointer to the parent stylesheet (if it exists)
6547
 *
6548
 * parse an XSLT stylesheet building the associated structures
6549
 * except the processing not needed for imported documents.
6550
 *
6551
 * Returns a new XSLT stylesheet structure.
6552
 */
6553
6554
xsltStylesheetPtr
6555
xsltParseStylesheetImportedDoc(xmlDocPtr doc,
6556
6.79k
             xsltStylesheetPtr parentStyle) {
6557
6.79k
    xsltStylesheetPtr retStyle;
6558
6559
6.79k
    if (doc == NULL)
6560
0
  return(NULL);
6561
6562
6.79k
    retStyle = xsltNewStylesheetInternal(parentStyle);
6563
6.79k
    if (retStyle == NULL)
6564
0
  return(NULL);
6565
6566
6.79k
    if (xsltParseStylesheetUser(retStyle, doc) != 0) {
6567
5.31k
        xsltFreeStylesheet(retStyle);
6568
5.31k
        return(NULL);
6569
5.31k
    }
6570
6571
1.48k
    return(retStyle);
6572
6.79k
}
6573
6574
/**
6575
 * xsltParseStylesheetUser:
6576
 * @style: pointer to the stylesheet
6577
 * @doc:  an xmlDoc parsed XML
6578
 *
6579
 * Parse an XSLT stylesheet with a user-provided stylesheet struct.
6580
 *
6581
 * Returns 0 if successful, -1 in case of error.
6582
 */
6583
int
6584
7.39k
xsltParseStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc) {
6585
7.39k
    if ((style == NULL) || (doc == NULL))
6586
0
  return(-1);
6587
6588
    /*
6589
    * Adjust the string dict.
6590
    */
6591
7.39k
    if (doc->dict != NULL) {
6592
7.39k
        xmlDictFree(style->dict);
6593
7.39k
  style->dict = doc->dict;
6594
#ifdef WITH_XSLT_DEBUG
6595
        xsltGenericDebug(xsltGenericDebugContext,
6596
      "reusing dictionary from %s for stylesheet\n",
6597
      doc->URL);
6598
#endif
6599
7.39k
  xmlDictReference(style->dict);
6600
7.39k
    }
6601
6602
    /*
6603
    * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6604
    *  the stylesheet to containt distinct namespace prefixes.
6605
    */
6606
7.39k
    xsltGatherNamespaces(style);
6607
6608
#ifdef XSLT_REFACTORED
6609
    {
6610
  xsltCompilerCtxtPtr cctxt;
6611
  xsltStylesheetPtr oldCurSheet;
6612
6613
  if (style->parent == NULL) {
6614
      xsltPrincipalStylesheetDataPtr principalData;
6615
      /*
6616
      * Create extra data for the principal stylesheet.
6617
      */
6618
      principalData = xsltNewPrincipalStylesheetData();
6619
      if (principalData == NULL) {
6620
    return(-1);
6621
      }
6622
      style->principalData = principalData;
6623
      /*
6624
      * Create the compilation context
6625
      * ------------------------------
6626
      * (only once; for the principal stylesheet).
6627
      * This is currently the only function where the
6628
      * compilation context is created.
6629
      */
6630
      cctxt = xsltCompilationCtxtCreate(style);
6631
      if (cctxt == NULL) {
6632
    return(-1);
6633
      }
6634
      style->compCtxt = (void *) cctxt;
6635
      cctxt->style = style;
6636
      cctxt->dict = style->dict;
6637
      cctxt->psData = principalData;
6638
      /*
6639
      * Push initial dummy node info.
6640
      */
6641
      cctxt->depth = -1;
6642
      xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6643
  } else {
6644
      /*
6645
      * Imported stylesheet.
6646
      */
6647
      cctxt = style->parent->compCtxt;
6648
      style->compCtxt = cctxt;
6649
  }
6650
  /*
6651
  * Save the old and set the current stylesheet structure in the
6652
  * compilation context.
6653
  */
6654
  oldCurSheet = cctxt->style;
6655
  cctxt->style = style;
6656
6657
  style->doc = doc;
6658
  xsltParseStylesheetProcess(style, doc);
6659
6660
  cctxt->style = oldCurSheet;
6661
  if (style->parent == NULL) {
6662
      /*
6663
      * Pop the initial dummy node info.
6664
      */
6665
      xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6666
  } else {
6667
      /*
6668
      * Clear the compilation context of imported
6669
      * stylesheets.
6670
      * TODO: really?
6671
      */
6672
      /* style->compCtxt = NULL; */
6673
  }
6674
6675
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
6676
        if (style->errors != 0) {
6677
            /*
6678
            * Restore all changes made to namespace URIs of ns-decls.
6679
            */
6680
            if (cctxt->psData->nsMap)
6681
                xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
6682
        }
6683
#endif
6684
6685
        if (style->parent == NULL) {
6686
            xsltCompilationCtxtFree(style->compCtxt);
6687
            style->compCtxt = NULL;
6688
        }
6689
    }
6690
6691
#else /* XSLT_REFACTORED */
6692
    /*
6693
    * Old behaviour.
6694
    */
6695
7.39k
    style->doc = doc;
6696
7.39k
    if (xsltParseStylesheetProcess(style, doc) == NULL) {
6697
25
        style->doc = NULL;
6698
25
        return(-1);
6699
25
    }
6700
7.36k
#endif /* else of XSLT_REFACTORED */
6701
6702
7.36k
    if (style->parent == NULL)
6703
592
        xsltResolveStylesheetAttributeSet(style);
6704
6705
7.36k
    if (style->errors != 0) {
6706
        /*
6707
        * Detach the doc from the stylesheet; otherwise the doc
6708
        * will be freed in xsltFreeStylesheet().
6709
        */
6710
5.49k
        style->doc = NULL;
6711
        /*
6712
        * Cleanup the doc if its the main stylesheet.
6713
        */
6714
5.49k
        if (style->parent == NULL)
6715
197
            xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
6716
5.49k
        return(-1);
6717
5.49k
    }
6718
6719
1.87k
    return(0);
6720
7.36k
}
6721
6722
/**
6723
 * xsltParseStylesheetDoc:
6724
 * @doc:  an xmlDoc parsed XML
6725
 *
6726
 * parse an XSLT stylesheet, building the associated structures.  doc
6727
 * is kept as a reference within the returned stylesheet, so changes
6728
 * to doc after the parsing will be reflected when the stylesheet
6729
 * is applied, and the doc is automatically freed when the
6730
 * stylesheet is closed.
6731
 *
6732
 * Returns a new XSLT stylesheet structure.
6733
 */
6734
6735
xsltStylesheetPtr
6736
0
xsltParseStylesheetDoc(xmlDocPtr doc) {
6737
0
    xsltInitGlobals();
6738
6739
0
    return(xsltParseStylesheetImportedDoc(doc, NULL));
6740
0
}
6741
6742
/**
6743
 * xsltParseStylesheetFile:
6744
 * @filename:  the filename/URL to the stylesheet
6745
 *
6746
 * Load and parse an XSLT stylesheet
6747
 *
6748
 * Returns a new XSLT stylesheet structure.
6749
 */
6750
6751
xsltStylesheetPtr
6752
0
xsltParseStylesheetFile(const xmlChar* filename) {
6753
0
    xsltSecurityPrefsPtr sec;
6754
0
    xsltStylesheetPtr ret;
6755
0
    xmlDocPtr doc;
6756
6757
0
    xsltInitGlobals();
6758
6759
0
    if (filename == NULL)
6760
0
  return(NULL);
6761
6762
#ifdef WITH_XSLT_DEBUG_PARSING
6763
    xsltGenericDebug(xsltGenericDebugContext,
6764
      "xsltParseStylesheetFile : parse %s\n", filename);
6765
#endif
6766
6767
    /*
6768
     * Security framework check
6769
     */
6770
0
    sec = xsltGetDefaultSecurityPrefs();
6771
0
    if (sec != NULL) {
6772
0
  int res;
6773
6774
0
  res = xsltCheckRead(sec, NULL, filename);
6775
0
  if (res <= 0) {
6776
0
            if (res == 0)
6777
0
                xsltTransformError(NULL, NULL, NULL,
6778
0
                     "xsltParseStylesheetFile: read rights for %s denied\n",
6779
0
                                 filename);
6780
0
      return(NULL);
6781
0
  }
6782
0
    }
6783
6784
0
    doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
6785
0
                               NULL, XSLT_LOAD_START);
6786
0
    if (doc == NULL) {
6787
0
  xsltTransformError(NULL, NULL, NULL,
6788
0
    "xsltParseStylesheetFile : cannot parse %s\n", filename);
6789
0
  return(NULL);
6790
0
    }
6791
0
    ret = xsltParseStylesheetDoc(doc);
6792
0
    if (ret == NULL) {
6793
0
  xmlFreeDoc(doc);
6794
0
  return(NULL);
6795
0
    }
6796
6797
0
    return(ret);
6798
0
}
6799
6800
/************************************************************************
6801
 *                  *
6802
 *      Handling of Stylesheet PI     *
6803
 *                  *
6804
 ************************************************************************/
6805
6806
0
#define CUR (*cur)
6807
0
#define SKIP(val) cur += (val)
6808
0
#define NXT(val) cur[(val)]
6809
#define SKIP_BLANKS           \
6810
0
    while (IS_BLANK(CUR)) NEXT
6811
0
#define NEXT ((*cur) ?  cur++ : cur)
6812
6813
/**
6814
 * xsltParseStylesheetPI:
6815
 * @value: the value of the PI
6816
 *
6817
 * This function checks that the type is text/xml and extracts
6818
 * the URI-Reference for the stylesheet
6819
 *
6820
 * Returns the URI-Reference for the stylesheet or NULL (it need to
6821
 *         be freed by the caller)
6822
 */
6823
static xmlChar *
6824
0
xsltParseStylesheetPI(const xmlChar *value) {
6825
0
    const xmlChar *cur;
6826
0
    const xmlChar *start;
6827
0
    xmlChar *val;
6828
0
    xmlChar tmp;
6829
0
    xmlChar *href = NULL;
6830
0
    int isXml = 0;
6831
6832
0
    if (value == NULL)
6833
0
  return(NULL);
6834
6835
0
    cur = value;
6836
0
    while (CUR != 0) {
6837
0
  SKIP_BLANKS;
6838
0
  if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6839
0
      (NXT(3) == 'e')) {
6840
0
      SKIP(4);
6841
0
      SKIP_BLANKS;
6842
0
      if (CUR != '=')
6843
0
    continue;
6844
0
      NEXT;
6845
0
      if ((CUR != '\'') && (CUR != '"'))
6846
0
    continue;
6847
0
      tmp = CUR;
6848
0
      NEXT;
6849
0
      start = cur;
6850
0
      while ((CUR != 0) && (CUR != tmp))
6851
0
    NEXT;
6852
0
      if (CUR != tmp)
6853
0
    continue;
6854
0
      val = xmlStrndup(start, cur - start);
6855
0
      NEXT;
6856
0
      if (val == NULL)
6857
0
    return(NULL);
6858
0
      if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
6859
0
    (xmlStrcasecmp(val, BAD_CAST "text/xsl")) &&
6860
0
    (xmlStrcasecmp(val, BAD_CAST "application/xslt+xml"))) {
6861
0
                xmlFree(val);
6862
0
    break;
6863
0
      }
6864
0
      isXml = 1;
6865
0
      xmlFree(val);
6866
0
  } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6867
0
      (NXT(3) == 'f')) {
6868
0
      SKIP(4);
6869
0
      SKIP_BLANKS;
6870
0
      if (CUR != '=')
6871
0
    continue;
6872
0
      NEXT;
6873
0
      if ((CUR != '\'') && (CUR != '"'))
6874
0
    continue;
6875
0
      tmp = CUR;
6876
0
      NEXT;
6877
0
      start = cur;
6878
0
      while ((CUR != 0) && (CUR != tmp))
6879
0
    NEXT;
6880
0
      if (CUR != tmp)
6881
0
    continue;
6882
0
      if (href == NULL)
6883
0
    href = xmlStrndup(start, cur - start);
6884
0
      NEXT;
6885
0
  } else {
6886
0
      while ((CUR != 0) && (!IS_BLANK(CUR)))
6887
0
    NEXT;
6888
0
  }
6889
6890
0
    }
6891
6892
0
    if (!isXml) {
6893
0
  if (href != NULL)
6894
0
      xmlFree(href);
6895
0
  href = NULL;
6896
0
    }
6897
0
    return(href);
6898
0
}
6899
6900
/**
6901
 * xsltLoadStylesheetPI:
6902
 * @doc:  a document to process
6903
 *
6904
 * This function tries to locate the stylesheet PI in the given document
6905
 * If found, and if contained within the document, it will extract
6906
 * that subtree to build the stylesheet to process @doc (doc itself will
6907
 * be modified). If found but referencing an external document it will
6908
 * attempt to load it and generate a stylesheet from it. In both cases,
6909
 * the resulting stylesheet and the document need to be freed once the
6910
 * transformation is done.
6911
 *
6912
 * Returns a new XSLT stylesheet structure or NULL if not found.
6913
 */
6914
xsltStylesheetPtr
6915
0
xsltLoadStylesheetPI(xmlDocPtr doc) {
6916
0
    xmlNodePtr child;
6917
0
    xsltStylesheetPtr ret = NULL;
6918
0
    xmlChar *href = NULL;
6919
0
    xmlURIPtr URI;
6920
6921
0
    xsltInitGlobals();
6922
6923
0
    if (doc == NULL)
6924
0
  return(NULL);
6925
6926
    /*
6927
     * Find the text/xml stylesheet PI id any before the root
6928
     */
6929
0
    child = doc->children;
6930
0
    while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
6931
0
  if ((child->type == XML_PI_NODE) &&
6932
0
      (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
6933
0
      href = xsltParseStylesheetPI(child->content);
6934
0
      if (href != NULL)
6935
0
    break;
6936
0
  }
6937
0
  child = child->next;
6938
0
    }
6939
6940
    /*
6941
     * If found check the href to select processing
6942
     */
6943
0
    if (href != NULL) {
6944
#ifdef WITH_XSLT_DEBUG_PARSING
6945
  xsltGenericDebug(xsltGenericDebugContext,
6946
    "xsltLoadStylesheetPI : found PI href=%s\n", href);
6947
#endif
6948
0
  URI = xmlParseURI((const char *) href);
6949
0
  if (URI == NULL) {
6950
0
      xsltTransformError(NULL, NULL, child,
6951
0
        "xml-stylesheet : href %s is not valid\n", href);
6952
0
      xmlFree(href);
6953
0
      return(NULL);
6954
0
  }
6955
0
  if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
6956
0
            (URI->opaque == NULL) && (URI->authority == NULL) &&
6957
0
            (URI->server == NULL) && (URI->user == NULL) &&
6958
0
            (URI->path == NULL) && (URI->query == NULL)) {
6959
0
      xmlAttrPtr ID;
6960
6961
#ifdef WITH_XSLT_DEBUG_PARSING
6962
      xsltGenericDebug(xsltGenericDebugContext,
6963
        "xsltLoadStylesheetPI : Reference to ID %s\n", href);
6964
#endif
6965
0
      if (URI->fragment[0] == '#')
6966
0
    ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
6967
0
      else
6968
0
    ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
6969
0
      if (ID == NULL) {
6970
0
    xsltTransformError(NULL, NULL, child,
6971
0
        "xml-stylesheet : no ID %s found\n", URI->fragment);
6972
0
      } else {
6973
0
    xmlDocPtr fake;
6974
0
    xmlNodePtr subtree, newtree;
6975
0
    xmlNsPtr ns;
6976
6977
#ifdef WITH_XSLT_DEBUG
6978
    xsltGenericDebug(xsltGenericDebugContext,
6979
        "creating new document from %s for embedded stylesheet\n",
6980
        doc->URL);
6981
#endif
6982
    /*
6983
     * move the subtree in a new document passed to
6984
     * the stylesheet analyzer
6985
     */
6986
0
    subtree = ID->parent;
6987
0
    fake = xmlNewDoc(NULL);
6988
0
    if (fake != NULL) {
6989
        /*
6990
        * Should the dictionary still be shared even though
6991
        * the nodes are being copied rather than moved?
6992
        */
6993
0
        fake->dict = doc->dict;
6994
0
        xmlDictReference(doc->dict);
6995
#ifdef WITH_XSLT_DEBUG
6996
        xsltGenericDebug(xsltGenericDebugContext,
6997
      "reusing dictionary from %s for embedded stylesheet\n",
6998
      doc->URL);
6999
#endif
7000
7001
0
        newtree = xmlDocCopyNode(subtree, fake, 1);
7002
7003
0
        fake->URL = xmlNodeGetBase(doc, subtree->parent);
7004
#ifdef WITH_XSLT_DEBUG
7005
        xsltGenericDebug(xsltGenericDebugContext,
7006
      "set base URI for embedded stylesheet as %s\n",
7007
      fake->URL);
7008
#endif
7009
7010
        /*
7011
        * Add all namespaces in scope of embedded stylesheet to
7012
        * root element of newly created stylesheet document
7013
        */
7014
0
        while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
7015
0
      for (ns = subtree->ns; ns; ns = ns->next) {
7016
0
          xmlNewNs(newtree,  ns->href, ns->prefix);
7017
0
      }
7018
0
        }
7019
7020
0
        xmlAddChild((xmlNodePtr)fake, newtree);
7021
0
        ret = xsltParseStylesheetDoc(fake);
7022
0
        if (ret == NULL)
7023
0
      xmlFreeDoc(fake);
7024
0
    }
7025
0
      }
7026
0
  } else {
7027
0
      xmlChar *URL, *base;
7028
7029
      /*
7030
       * Reference to an external stylesheet
7031
       */
7032
7033
0
      base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
7034
0
      URL = xmlBuildURI(href, base);
7035
0
      if (URL != NULL) {
7036
#ifdef WITH_XSLT_DEBUG_PARSING
7037
    xsltGenericDebug(xsltGenericDebugContext,
7038
      "xsltLoadStylesheetPI : fetching %s\n", URL);
7039
#endif
7040
0
    ret = xsltParseStylesheetFile(URL);
7041
0
    xmlFree(URL);
7042
0
      } else {
7043
#ifdef WITH_XSLT_DEBUG_PARSING
7044
    xsltGenericDebug(xsltGenericDebugContext,
7045
      "xsltLoadStylesheetPI : fetching %s\n", href);
7046
#endif
7047
0
    ret = xsltParseStylesheetFile(href);
7048
0
      }
7049
0
      if (base != NULL)
7050
0
    xmlFree(base);
7051
0
  }
7052
0
  xmlFreeURI(URI);
7053
0
  xmlFree(href);
7054
0
    }
7055
0
    return(ret);
7056
0
}