Coverage Report

Created: 2024-08-25 12:19

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