Coverage Report

Created: 2025-06-22 06:55

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