Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xslt/libxslt/xslt.c
4393 views
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
* [email protected]
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
#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
103
((c) == 0x0D))
104
105
#ifdef IS_BLANK_NODE
106
#undef IS_BLANK_NODE
107
#endif
108
#define IS_BLANK_NODE(n) \
109
(((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
{
123
if ((style == NULL) || (node == NULL))
124
return;
125
126
if (IS_XSLT_ELEM(node))
127
xsltTransformError(NULL, style, node,
128
"The XSLT-element '%s' is not allowed at this position.\n",
129
node->name);
130
else
131
xsltTransformError(NULL, style, node,
132
"The element '%s' is not allowed at this position.\n",
133
node->name);
134
style->errors++;
135
}
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
{
152
xmlChar *value;
153
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
value = (xmlChar *) xmlDictLookup(style->dict, orig, -1);
161
if (value == NULL)
162
return(-1);
163
164
/* do not push duplicates */
165
for (i = 0;i < style->exclPrefixNr;i++) {
166
if (xmlStrEqual(style->exclPrefixTab[i], value))
167
return(-1);
168
}
169
if (style->exclPrefixNr >= style->exclPrefixMax) {
170
xmlChar **tmp;
171
size_t max = style->exclPrefixMax ? style->exclPrefixMax * 2 : 4;
172
173
tmp = xmlRealloc(style->exclPrefixTab,
174
max * sizeof(style->exclPrefixTab[0]));
175
if (tmp == NULL) {
176
xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
177
return (-1);
178
}
179
style->exclPrefixTab = tmp;
180
style->exclPrefixMax = max;
181
}
182
style->exclPrefixTab[style->exclPrefixNr] = value;
183
style->exclPrefix = value;
184
return (style->exclPrefixNr++);
185
}
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
{
197
xmlChar *ret;
198
199
if (style->exclPrefixNr <= 0)
200
return (0);
201
style->exclPrefixNr--;
202
if (style->exclPrefixNr > 0)
203
style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
204
else
205
style->exclPrefix = NULL;
206
ret = style->exclPrefixTab[style->exclPrefixNr];
207
style->exclPrefixTab[style->exclPrefixNr] = 0;
208
return (ret);
209
}
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
xsltInit (void) {
227
if (initialized == 0) {
228
initialized = 1;
229
#ifdef XSLT_LOCALE_WINAPI
230
xsltLocaleMutex = xmlNewRMutex();
231
#endif
232
xsltRegisterAllExtras();
233
}
234
}
235
236
/**
237
* xsltUninit:
238
*
239
* Uninitializes the processor.
240
*/
241
void
242
xsltUninit (void) {
243
#ifdef XSLT_LOCALE_WINAPI
244
xmlFreeRMutex(xsltLocaleMutex);
245
xsltLocaleMutex = NULL;
246
#endif
247
initialized = 0;
248
}
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
xsltIsBlank(xmlChar *str) {
260
if (str == NULL)
261
return(1);
262
while (*str != 0) {
263
if (!(IS_BLANK(*str))) return(0);
264
str++;
265
}
266
return(1);
267
}
268
269
/************************************************************************
270
* *
271
* Routines to handle XSLT data structures *
272
* *
273
************************************************************************/
274
static xsltDecimalFormatPtr
275
xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name)
276
{
277
xsltDecimalFormatPtr self;
278
/* UTF-8 for 0x2030 */
279
static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
280
281
self = xmlMalloc(sizeof(xsltDecimalFormat));
282
if (self != NULL) {
283
self->next = NULL;
284
self->nsUri = nsUri;
285
self->name = name;
286
287
/* Default values */
288
self->digit = xmlStrdup(BAD_CAST("#"));
289
self->patternSeparator = xmlStrdup(BAD_CAST(";"));
290
self->decimalPoint = xmlStrdup(BAD_CAST("."));
291
self->grouping = xmlStrdup(BAD_CAST(","));
292
self->percent = xmlStrdup(BAD_CAST("%"));
293
self->permille = xmlStrdup(BAD_CAST(permille));
294
self->zeroDigit = xmlStrdup(BAD_CAST("0"));
295
self->minusSign = xmlStrdup(BAD_CAST("-"));
296
self->infinity = xmlStrdup(BAD_CAST("Infinity"));
297
self->noNumber = xmlStrdup(BAD_CAST("NaN"));
298
}
299
return self;
300
}
301
302
static void
303
xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
304
{
305
if (self != NULL) {
306
if (self->digit)
307
xmlFree(self->digit);
308
if (self->patternSeparator)
309
xmlFree(self->patternSeparator);
310
if (self->decimalPoint)
311
xmlFree(self->decimalPoint);
312
if (self->grouping)
313
xmlFree(self->grouping);
314
if (self->percent)
315
xmlFree(self->percent);
316
if (self->permille)
317
xmlFree(self->permille);
318
if (self->zeroDigit)
319
xmlFree(self->zeroDigit);
320
if (self->minusSign)
321
xmlFree(self->minusSign);
322
if (self->infinity)
323
xmlFree(self->infinity);
324
if (self->noNumber)
325
xmlFree(self->noNumber);
326
if (self->name)
327
xmlFree(self->name);
328
xmlFree(self);
329
}
330
}
331
332
static void
333
xsltFreeDecimalFormatList(xsltStylesheetPtr self)
334
{
335
xsltDecimalFormatPtr iter;
336
xsltDecimalFormatPtr tmp;
337
338
if (self == NULL)
339
return;
340
341
iter = self->decimalFormat;
342
while (iter != NULL) {
343
tmp = iter->next;
344
xsltFreeDecimalFormat(iter);
345
iter = tmp;
346
}
347
}
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
{
361
xsltDecimalFormatPtr result = NULL;
362
363
if (name == NULL)
364
return style->decimalFormat;
365
366
while (style != NULL) {
367
for (result = style->decimalFormat->next;
368
result != NULL;
369
result = result->next) {
370
if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
371
return result;
372
}
373
style = xsltNextImport(style);
374
}
375
return result;
376
}
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
{
392
xsltDecimalFormatPtr result = NULL;
393
394
if (name == NULL)
395
return style->decimalFormat;
396
397
while (style != NULL) {
398
for (result = style->decimalFormat->next;
399
result != NULL;
400
result = result->next) {
401
if (xmlStrEqual(nsUri, result->nsUri) &&
402
xmlStrEqual(name, result->name))
403
return result;
404
}
405
style = xsltNextImport(style);
406
}
407
return result;
408
}
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
xsltNewTemplate(void) {
420
xsltTemplatePtr cur;
421
422
cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
423
if (cur == NULL) {
424
xsltTransformError(NULL, NULL, NULL,
425
"xsltNewTemplate : malloc failed\n");
426
return(NULL);
427
}
428
memset(cur, 0, sizeof(xsltTemplate));
429
cur->priority = XSLT_PAT_NO_PRIORITY;
430
return(cur);
431
}
432
433
/**
434
* xsltFreeTemplate:
435
* @template: an XSLT template
436
*
437
* Free up the memory allocated by @template
438
*/
439
static void
440
xsltFreeTemplate(xsltTemplatePtr template) {
441
if (template == NULL)
442
return;
443
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
if (template->inheritedNs) xmlFree(template->inheritedNs);
454
455
/* free profiling data */
456
if (template->templCalledTab) xmlFree(template->templCalledTab);
457
if (template->templCountTab) xmlFree(template->templCountTab);
458
459
memset(template, -1, sizeof(xsltTemplate));
460
xmlFree(template);
461
}
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
xsltFreeTemplateList(xsltTemplatePtr template) {
471
xsltTemplatePtr cur;
472
473
while (template != NULL) {
474
cur = template;
475
template = template->next;
476
xsltFreeTemplate(cur);
477
}
478
}
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
xsltNewStylesheetInternal(xsltStylesheetPtr parent) {
756
xsltStylesheetPtr ret = NULL;
757
758
ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
759
if (ret == NULL) {
760
xsltTransformError(NULL, NULL, NULL,
761
"xsltNewStylesheet : malloc failed\n");
762
goto internal_err;
763
}
764
memset(ret, 0, sizeof(xsltStylesheet));
765
766
ret->parent = parent;
767
ret->omitXmlDeclaration = -1;
768
ret->standalone = -1;
769
ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
770
ret->indent = -1;
771
ret->errors = 0;
772
ret->warnings = 0;
773
ret->exclPrefixNr = 0;
774
ret->exclPrefixMax = 0;
775
ret->exclPrefixTab = NULL;
776
ret->extInfos = NULL;
777
ret->extrasNr = 0;
778
ret->internalized = 1;
779
ret->literal_result = 0;
780
ret->forwards_compatible = 0;
781
ret->dict = xmlDictCreate();
782
#ifdef WITH_XSLT_DEBUG
783
xsltGenericDebug(xsltGenericDebugContext,
784
"creating dictionary for stylesheet\n");
785
#endif
786
787
if (parent == NULL) {
788
ret->principal = ret;
789
790
ret->xpathCtxt = xmlXPathNewContext(NULL);
791
if (ret->xpathCtxt == NULL) {
792
xsltTransformError(NULL, NULL, NULL,
793
"xsltNewStylesheet: xmlXPathNewContext failed\n");
794
goto internal_err;
795
}
796
if (xmlXPathContextSetCache(ret->xpathCtxt, 1, -1, 0) == -1)
797
goto internal_err;
798
} else {
799
ret->principal = parent->principal;
800
}
801
802
xsltInit();
803
804
return(ret);
805
806
internal_err:
807
if (ret != NULL)
808
xsltFreeStylesheet(ret);
809
return(NULL);
810
}
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
xsltNewStylesheet(void) {
821
return xsltNewStylesheetInternal(NULL);
822
}
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
{
836
return(style->extrasNr++);
837
}
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
{
852
if (ctxt->extrasNr >= ctxt->extrasMax) {
853
int i;
854
if (ctxt->extrasNr == 0) {
855
ctxt->extrasMax = 20;
856
ctxt->extras = (xsltRuntimeExtraPtr)
857
xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
858
if (ctxt->extras == NULL) {
859
xsltTransformError(ctxt, NULL, NULL,
860
"xsltAllocateExtraCtxt: out of memory\n");
861
return(0);
862
}
863
for (i = 0;i < ctxt->extrasMax;i++) {
864
ctxt->extras[i].info = NULL;
865
ctxt->extras[i].deallocate = NULL;
866
ctxt->extras[i].val.ptr = NULL;
867
}
868
869
} else {
870
xsltRuntimeExtraPtr tmp;
871
872
ctxt->extrasMax += 100;
873
tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
874
ctxt->extrasMax * sizeof(xsltRuntimeExtra));
875
if (tmp == NULL) {
876
xsltTransformError(ctxt, NULL, NULL,
877
"xsltAllocateExtraCtxt: out of memory\n");
878
return(0);
879
}
880
ctxt->extras = tmp;
881
for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
882
ctxt->extras[i].info = NULL;
883
ctxt->extras[i].deallocate = NULL;
884
ctxt->extras[i].val.ptr = NULL;
885
}
886
}
887
}
888
return(ctxt->extrasNr++);
889
}
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
xsltFreeStylesheetList(xsltStylesheetPtr style) {
899
xsltStylesheetPtr next;
900
901
while (style != NULL) {
902
next = style->next;
903
xsltFreeStylesheet(style);
904
style = next;
905
}
906
}
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
{
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
return(0);
966
}
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
{
977
if (style == NULL)
978
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
if ((style->parent == NULL) && (style->doc))
1003
xsltCleanupStylesheetTree(style->doc,
1004
xmlDocGetRootElement(style->doc));
1005
#endif /* XSLT_REFACTORED */
1006
1007
xsltFreeKeys(style);
1008
xsltFreeExts(style);
1009
xsltFreeTemplateHashes(style);
1010
xsltFreeDecimalFormatList(style);
1011
xsltFreeTemplateList(style->templates);
1012
xsltFreeAttributeSetsHashes(style);
1013
xsltFreeNamespaceAliasHashes(style);
1014
xsltFreeStylePreComps(style);
1015
/*
1016
* Free documents of all included stylsheet modules of this
1017
* stylesheet level.
1018
*/
1019
xsltFreeStyleDocuments(style);
1020
/*
1021
* TODO: Best time to shutdown extension stuff?
1022
*/
1023
xsltShutdownExts(style);
1024
1025
if (style->variables != NULL)
1026
xsltFreeStackElemList(style->variables);
1027
if (style->cdataSection != NULL)
1028
xmlHashFree(style->cdataSection, NULL);
1029
if (style->stripSpaces != NULL)
1030
xmlHashFree(style->stripSpaces, NULL);
1031
if (style->nsHash != NULL)
1032
xmlHashFree(style->nsHash, NULL);
1033
if (style->exclPrefixTab != NULL)
1034
xmlFree(style->exclPrefixTab);
1035
if (style->method != NULL)
1036
xmlFree(style->method);
1037
if (style->methodURI != NULL)
1038
xmlFree(style->methodURI);
1039
if (style->version != NULL)
1040
xmlFree(style->version);
1041
if (style->encoding != NULL)
1042
xmlFree(style->encoding);
1043
if (style->doctypePublic != NULL)
1044
xmlFree(style->doctypePublic);
1045
if (style->doctypeSystem != NULL)
1046
xmlFree(style->doctypeSystem);
1047
if (style->mediaType != NULL)
1048
xmlFree(style->mediaType);
1049
if (style->attVTs)
1050
xsltFreeAVTList(style->attVTs);
1051
if (style->imports != NULL)
1052
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
if (style->doc != NULL) {
1071
xmlFreeDoc(style->doc);
1072
}
1073
1074
#ifdef WITH_XSLT_DEBUG
1075
xsltGenericDebug(xsltGenericDebugContext,
1076
"freeing dictionary from stylesheet\n");
1077
#endif
1078
xmlDictFree(style->dict);
1079
1080
if (style->xpathCtxt != NULL)
1081
xmlXPathFreeContext(style->xpathCtxt);
1082
1083
memset(style, -1, sizeof(xsltStylesheet));
1084
xmlFree(style);
1085
}
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
{
1115
xmlNsPtr cur;
1116
xmlNsPtr *ret = NULL, *tmp;
1117
int nbns = 0;
1118
int maxns = 0;
1119
int i;
1120
1121
if ((style == NULL) || (template == NULL) || (node == NULL) ||
1122
(template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
1123
return(0);
1124
while (node != NULL) {
1125
if (node->type == XML_ELEMENT_NODE) {
1126
cur = node->nsDef;
1127
while (cur != NULL) {
1128
if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
1129
goto skip_ns;
1130
1131
if ((cur->prefix != NULL) &&
1132
(xsltCheckExtPrefix(style, cur->prefix)))
1133
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
for (i = 0;i < style->exclPrefixNr;i++) {
1140
if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
1141
goto skip_ns;
1142
}
1143
/*
1144
* Skip shadowed namespace bindings.
1145
*/
1146
for (i = 0; i < nbns; i++) {
1147
if ((cur->prefix == ret[i]->prefix) ||
1148
(xmlStrEqual(cur->prefix, ret[i]->prefix)))
1149
break;
1150
}
1151
if (i >= nbns) {
1152
if (nbns >= maxns) {
1153
maxns = (maxns == 0) ? 10 : 2 * maxns;
1154
tmp = (xmlNsPtr *) xmlRealloc(ret,
1155
(maxns + 1) * sizeof(xmlNsPtr));
1156
if (tmp == NULL) {
1157
xmlGenericError(xmlGenericErrorContext,
1158
"xsltGetInheritedNsList : realloc failed!\n");
1159
xmlFree(ret);
1160
return(0);
1161
}
1162
ret = tmp;
1163
}
1164
ret[nbns++] = cur;
1165
ret[nbns] = NULL;
1166
}
1167
skip_ns:
1168
cur = cur->next;
1169
}
1170
}
1171
node = node->parent;
1172
}
1173
if (nbns != 0) {
1174
#ifdef WITH_XSLT_DEBUG_PARSING
1175
xsltGenericDebug(xsltGenericDebugContext,
1176
"template has %d inherited namespaces\n", nbns);
1177
#endif
1178
template->inheritedNsNr = nbns;
1179
template->inheritedNs = ret;
1180
}
1181
return (nbns);
1182
}
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
{
1197
xmlChar *elements,
1198
*prop;
1199
xmlChar *element,
1200
*end;
1201
1202
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1203
return;
1204
1205
prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
1206
if (prop != NULL) {
1207
if (style->version != NULL)
1208
xmlFree(style->version);
1209
style->version = prop;
1210
}
1211
1212
prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
1213
if (prop != NULL) {
1214
if (style->encoding != NULL)
1215
xmlFree(style->encoding);
1216
style->encoding = prop;
1217
}
1218
1219
/* relaxed to support xt:document
1220
* TODO KB: What does "relaxed to support xt:document" mean?
1221
*/
1222
prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
1223
if (prop != NULL) {
1224
const xmlChar *URI;
1225
1226
if (style->method != NULL)
1227
xmlFree(style->method);
1228
style->method = NULL;
1229
if (style->methodURI != NULL)
1230
xmlFree(style->methodURI);
1231
style->methodURI = NULL;
1232
1233
/*
1234
* TODO: Don't use xsltGetQNameURI().
1235
*/
1236
URI = xsltGetQNameURI(cur, &prop);
1237
if (prop == NULL) {
1238
if (style != NULL) style->errors++;
1239
} else if (URI == NULL) {
1240
if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1241
(xmlStrEqual(prop, (const xmlChar *) "html")) ||
1242
(xmlStrEqual(prop, (const xmlChar *) "text"))) {
1243
style->method = prop;
1244
} else {
1245
xsltTransformError(NULL, style, cur,
1246
"invalid value for method: %s\n", prop);
1247
if (style != NULL) style->warnings++;
1248
xmlFree(prop);
1249
}
1250
} else {
1251
style->method = prop;
1252
style->methodURI = xmlStrdup(URI);
1253
}
1254
}
1255
1256
prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
1257
if (prop != NULL) {
1258
if (style->doctypeSystem != NULL)
1259
xmlFree(style->doctypeSystem);
1260
style->doctypeSystem = prop;
1261
}
1262
1263
prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
1264
if (prop != NULL) {
1265
if (style->doctypePublic != NULL)
1266
xmlFree(style->doctypePublic);
1267
style->doctypePublic = prop;
1268
}
1269
1270
prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
1271
if (prop != NULL) {
1272
if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1273
style->standalone = 1;
1274
} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1275
style->standalone = 0;
1276
} else {
1277
xsltTransformError(NULL, style, cur,
1278
"invalid value for standalone: %s\n", prop);
1279
style->errors++;
1280
}
1281
xmlFree(prop);
1282
}
1283
1284
prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
1285
if (prop != NULL) {
1286
if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1287
style->indent = 1;
1288
} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1289
style->indent = 0;
1290
} else {
1291
xsltTransformError(NULL, style, cur,
1292
"invalid value for indent: %s\n", prop);
1293
style->errors++;
1294
}
1295
xmlFree(prop);
1296
}
1297
1298
prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
1299
if (prop != NULL) {
1300
if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1301
style->omitXmlDeclaration = 1;
1302
} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1303
style->omitXmlDeclaration = 0;
1304
} else {
1305
xsltTransformError(NULL, style, cur,
1306
"invalid value for omit-xml-declaration: %s\n",
1307
prop);
1308
style->errors++;
1309
}
1310
xmlFree(prop);
1311
}
1312
1313
elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
1314
NULL);
1315
if (elements != NULL) {
1316
if (style->cdataSection == NULL)
1317
style->cdataSection = xmlHashCreate(10);
1318
if (style->cdataSection == NULL) {
1319
xmlFree(elements);
1320
return;
1321
}
1322
1323
element = elements;
1324
while (*element != 0) {
1325
while (IS_BLANK(*element))
1326
element++;
1327
if (*element == 0)
1328
break;
1329
end = element;
1330
while ((*end != 0) && (!IS_BLANK(*end)))
1331
end++;
1332
element = xmlStrndup(element, end - element);
1333
if (element) {
1334
#ifdef WITH_XSLT_DEBUG_PARSING
1335
xsltGenericDebug(xsltGenericDebugContext,
1336
"add cdata section output element %s\n",
1337
element);
1338
#endif
1339
if (xmlValidateQName(BAD_CAST element, 0) != 0) {
1340
xsltTransformError(NULL, style, cur,
1341
"Attribute 'cdata-section-elements': The value "
1342
"'%s' is not a valid QName.\n", element);
1343
xmlFree(element);
1344
style->errors++;
1345
} else {
1346
const xmlChar *URI;
1347
1348
/*
1349
* TODO: Don't use xsltGetQNameURI().
1350
*/
1351
URI = xsltGetQNameURI(cur, &element);
1352
if (element == NULL) {
1353
/*
1354
* TODO: We'll report additionally an error
1355
* via the stylesheet's error handling.
1356
*/
1357
xsltTransformError(NULL, style, cur,
1358
"Attribute 'cdata-section-elements': "
1359
"Not a valid QName.\n");
1360
style->errors++;
1361
} else {
1362
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
if (URI == NULL) {
1373
ns = xmlSearchNs(style->doc, cur, NULL);
1374
if (ns != NULL)
1375
URI = ns->href;
1376
}
1377
xmlHashAddEntry2(style->cdataSection, element, URI,
1378
(void *) "cdata");
1379
xmlFree(element);
1380
}
1381
}
1382
}
1383
element = end;
1384
}
1385
xmlFree(elements);
1386
}
1387
1388
prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
1389
if (prop != NULL) {
1390
if (style->mediaType)
1391
xmlFree(style->mediaType);
1392
style->mediaType = prop;
1393
}
1394
if (cur->children != NULL) {
1395
xsltParseContentError(style, cur->children);
1396
}
1397
}
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
{
1417
xmlChar *prop;
1418
xsltDecimalFormatPtr format;
1419
xsltDecimalFormatPtr iter;
1420
1421
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1422
return;
1423
1424
format = style->decimalFormat;
1425
1426
prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
1427
if (prop != NULL) {
1428
const xmlChar *nsUri;
1429
1430
if (xmlValidateQName(prop, 0) != 0) {
1431
xsltTransformError(NULL, style, cur,
1432
"xsl:decimal-format: Invalid QName '%s'.\n", prop);
1433
style->warnings++;
1434
xmlFree(prop);
1435
return;
1436
}
1437
/*
1438
* TODO: Don't use xsltGetQNameURI().
1439
*/
1440
nsUri = xsltGetQNameURI(cur, &prop);
1441
if (prop == NULL) {
1442
style->warnings++;
1443
return;
1444
}
1445
format = xsltDecimalFormatGetByQName(style, nsUri, prop);
1446
if (format != NULL) {
1447
xsltTransformError(NULL, style, cur,
1448
"xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
1449
style->warnings++;
1450
xmlFree(prop);
1451
return;
1452
}
1453
format = xsltNewDecimalFormat(nsUri, prop);
1454
if (format == NULL) {
1455
xsltTransformError(NULL, style, cur,
1456
"xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1457
style->errors++;
1458
xmlFree(prop);
1459
return;
1460
}
1461
/* Append new decimal-format structure */
1462
for (iter = style->decimalFormat; iter->next; iter = iter->next)
1463
;
1464
if (iter)
1465
iter->next = format;
1466
}
1467
1468
prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
1469
if (prop != NULL) {
1470
if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
1471
format->decimalPoint = prop;
1472
}
1473
1474
prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
1475
if (prop != NULL) {
1476
if (format->grouping != NULL) xmlFree(format->grouping);
1477
format->grouping = prop;
1478
}
1479
1480
prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
1481
if (prop != NULL) {
1482
if (format->infinity != NULL) xmlFree(format->infinity);
1483
format->infinity = prop;
1484
}
1485
1486
prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
1487
if (prop != NULL) {
1488
if (format->minusSign != NULL) xmlFree(format->minusSign);
1489
format->minusSign = prop;
1490
}
1491
1492
prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
1493
if (prop != NULL) {
1494
if (format->noNumber != NULL) xmlFree(format->noNumber);
1495
format->noNumber = prop;
1496
}
1497
1498
prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
1499
if (prop != NULL) {
1500
if (format->percent != NULL) xmlFree(format->percent);
1501
format->percent = prop;
1502
}
1503
1504
prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
1505
if (prop != NULL) {
1506
if (format->permille != NULL) xmlFree(format->permille);
1507
format->permille = prop;
1508
}
1509
1510
prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
1511
if (prop != NULL) {
1512
if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
1513
format->zeroDigit = prop;
1514
}
1515
1516
prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
1517
if (prop != NULL) {
1518
if (format->digit != NULL) xmlFree(format->digit);
1519
format->digit = prop;
1520
}
1521
1522
prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
1523
if (prop != NULL) {
1524
if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
1525
format->patternSeparator = prop;
1526
}
1527
if (cur->children != NULL) {
1528
xsltParseContentError(style, cur->children);
1529
}
1530
}
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
xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1543
xmlChar *elements;
1544
xmlChar *element, *end;
1545
1546
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1547
return;
1548
1549
elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1550
if (elements == NULL) {
1551
xsltTransformError(NULL, style, cur,
1552
"xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1553
if (style != NULL) style->warnings++;
1554
return;
1555
}
1556
1557
if (style->stripSpaces == NULL)
1558
style->stripSpaces = xmlHashCreate(10);
1559
if (style->stripSpaces == NULL) {
1560
xmlFree(elements);
1561
return;
1562
}
1563
1564
element = elements;
1565
while (*element != 0) {
1566
while (IS_BLANK(*element)) element++;
1567
if (*element == 0)
1568
break;
1569
end = element;
1570
while ((*end != 0) && (!IS_BLANK(*end))) end++;
1571
element = xmlStrndup(element, end - element);
1572
if (element) {
1573
#ifdef WITH_XSLT_DEBUG_PARSING
1574
xsltGenericDebug(xsltGenericDebugContext,
1575
"add preserved space element %s\n", element);
1576
#endif
1577
if (xmlStrEqual(element, (const xmlChar *)"*")) {
1578
style->stripAll = -1;
1579
} else {
1580
const xmlChar *URI;
1581
1582
/*
1583
* TODO: Don't use xsltGetQNameURI().
1584
*/
1585
URI = xsltGetQNameURI(cur, &element);
1586
1587
xmlHashAddEntry2(style->stripSpaces, element, URI,
1588
(xmlChar *) "preserve");
1589
}
1590
xmlFree(element);
1591
}
1592
element = end;
1593
}
1594
xmlFree(elements);
1595
if (cur->children != NULL) {
1596
xsltParseContentError(style, cur->children);
1597
}
1598
}
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
int isXsltElem) {
1619
xmlChar *prefixes;
1620
xmlChar *prefix, *end;
1621
1622
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1623
return;
1624
1625
if (isXsltElem) {
1626
/* For xsl:stylesheet/xsl:transform. */
1627
prefixes = xmlGetNsProp(cur,
1628
(const xmlChar *)"extension-element-prefixes", NULL);
1629
} else {
1630
/* For literal result elements and extension instructions. */
1631
prefixes = xmlGetNsProp(cur,
1632
(const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
1633
}
1634
if (prefixes == NULL) {
1635
return;
1636
}
1637
1638
prefix = prefixes;
1639
while (*prefix != 0) {
1640
while (IS_BLANK(*prefix)) prefix++;
1641
if (*prefix == 0)
1642
break;
1643
end = prefix;
1644
while ((*end != 0) && (!IS_BLANK(*end))) end++;
1645
prefix = xmlStrndup(prefix, end - prefix);
1646
if (prefix) {
1647
xmlNsPtr ns;
1648
1649
if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1650
ns = xmlSearchNs(style->doc, cur, NULL);
1651
else
1652
ns = xmlSearchNs(style->doc, cur, prefix);
1653
if (ns == NULL) {
1654
xsltTransformError(NULL, style, cur,
1655
"xsl:extension-element-prefix : undefined namespace %s\n",
1656
prefix);
1657
if (style != NULL) style->warnings++;
1658
} else {
1659
#ifdef WITH_XSLT_DEBUG_PARSING
1660
xsltGenericDebug(xsltGenericDebugContext,
1661
"add extension prefix %s\n", prefix);
1662
#endif
1663
xsltRegisterExtPrefix(style, prefix, ns->href);
1664
}
1665
xmlFree(prefix);
1666
}
1667
prefix = end;
1668
}
1669
xmlFree(prefixes);
1670
}
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
xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1684
xmlChar *elements;
1685
xmlChar *element, *end;
1686
1687
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1688
return;
1689
1690
if (style->stripSpaces == NULL)
1691
style->stripSpaces = xmlHashCreate(10);
1692
if (style->stripSpaces == NULL)
1693
return;
1694
1695
elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1696
if (elements == NULL) {
1697
xsltTransformError(NULL, style, cur,
1698
"xsltParseStylesheetStripSpace: missing elements attribute\n");
1699
if (style != NULL) style->warnings++;
1700
return;
1701
}
1702
1703
element = elements;
1704
while (*element != 0) {
1705
while (IS_BLANK(*element)) element++;
1706
if (*element == 0)
1707
break;
1708
end = element;
1709
while ((*end != 0) && (!IS_BLANK(*end))) end++;
1710
element = xmlStrndup(element, end - element);
1711
if (element) {
1712
#ifdef WITH_XSLT_DEBUG_PARSING
1713
xsltGenericDebug(xsltGenericDebugContext,
1714
"add stripped space element %s\n", element);
1715
#endif
1716
if (xmlStrEqual(element, (const xmlChar *)"*")) {
1717
style->stripAll = 1;
1718
} else {
1719
const xmlChar *URI;
1720
1721
/*
1722
* TODO: Don't use xsltGetQNameURI().
1723
*/
1724
URI = xsltGetQNameURI(cur, &element);
1725
1726
xmlHashAddEntry2(style->stripSpaces, element, URI,
1727
(xmlChar *) "strip");
1728
}
1729
xmlFree(element);
1730
}
1731
element = end;
1732
}
1733
xmlFree(elements);
1734
if (cur->children != NULL) {
1735
xsltParseContentError(style, cur->children);
1736
}
1737
}
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
{
1756
int nb = 0;
1757
xmlChar *prefixes;
1758
xmlChar *prefix, *end;
1759
1760
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1761
return(0);
1762
1763
if (isXsltElem)
1764
prefixes = xmlGetNsProp(cur,
1765
(const xmlChar *)"exclude-result-prefixes", NULL);
1766
else
1767
prefixes = xmlGetNsProp(cur,
1768
(const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
1769
1770
if (prefixes == NULL) {
1771
return(0);
1772
}
1773
1774
prefix = prefixes;
1775
while (*prefix != 0) {
1776
while (IS_BLANK(*prefix)) prefix++;
1777
if (*prefix == 0)
1778
break;
1779
end = prefix;
1780
while ((*end != 0) && (!IS_BLANK(*end))) end++;
1781
prefix = xmlStrndup(prefix, end - prefix);
1782
if (prefix) {
1783
xmlNsPtr ns;
1784
1785
if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1786
ns = xmlSearchNs(style->doc, cur, NULL);
1787
else
1788
ns = xmlSearchNs(style->doc, cur, prefix);
1789
if (ns == NULL) {
1790
xsltTransformError(NULL, style, cur,
1791
"xsl:exclude-result-prefixes : undefined namespace %s\n",
1792
prefix);
1793
if (style != NULL) style->warnings++;
1794
} else {
1795
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
nb++;
1801
}
1802
}
1803
xmlFree(prefix);
1804
}
1805
prefix = end;
1806
}
1807
xmlFree(prefixes);
1808
return(nb);
1809
}
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
{
3489
xmlNodePtr deleteNode, styleelem;
3490
int internalize = 0;
3491
3492
if ((style == NULL) || (cur == NULL))
3493
return;
3494
3495
if ((cur->doc != NULL) && (style->dict != NULL) &&
3496
(cur->doc->dict == style->dict))
3497
internalize = 1;
3498
else
3499
style->internalized = 0;
3500
3501
if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
3502
(IS_XSLT_NAME(cur, "stylesheet"))) {
3503
styleelem = cur;
3504
} else {
3505
styleelem = NULL;
3506
}
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
deleteNode = NULL;
3514
while (cur != NULL) {
3515
if (deleteNode != NULL) {
3516
#ifdef WITH_XSLT_DEBUG_BLANKS
3517
xsltGenericDebug(xsltGenericDebugContext,
3518
"xsltPreprocessStylesheet: removing ignorable blank node\n");
3519
#endif
3520
xmlUnlinkNode(deleteNode);
3521
xmlFreeNode(deleteNode);
3522
deleteNode = NULL;
3523
}
3524
if (cur->type == XML_ELEMENT_NODE) {
3525
int exclPrefixes;
3526
/*
3527
* Internalize attributes values.
3528
*/
3529
if ((internalize) && (cur->properties != NULL)) {
3530
xmlAttrPtr attr = cur->properties;
3531
xmlNodePtr txt;
3532
3533
while (attr != NULL) {
3534
txt = attr->children;
3535
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
3536
(txt->content != NULL) &&
3537
(!xmlDictOwns(style->dict, txt->content)))
3538
{
3539
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
tmp = (xmlChar *) xmlDictLookup(style->dict,
3547
txt->content, -1);
3548
if (tmp != txt->content) {
3549
xmlNodeSetContent(txt, NULL);
3550
txt->content = tmp;
3551
}
3552
}
3553
attr = attr->next;
3554
}
3555
}
3556
if (IS_XSLT_ELEM(cur)) {
3557
exclPrefixes = 0;
3558
if (IS_XSLT_NAME(cur, "text")) {
3559
for (;exclPrefixes > 0;exclPrefixes--)
3560
exclPrefixPop(style);
3561
goto skip_children;
3562
}
3563
} else {
3564
exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
3565
}
3566
3567
if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
3568
xmlNsPtr ns = cur->nsDef, prev = NULL, next;
3569
xmlNodePtr root = NULL;
3570
int i, moved;
3571
3572
root = xmlDocGetRootElement(cur->doc);
3573
if ((root != NULL) && (root != cur)) {
3574
while (ns != NULL) {
3575
moved = 0;
3576
next = ns->next;
3577
for (i = 0;i < style->exclPrefixNr;i++) {
3578
if ((ns->prefix != NULL) &&
3579
(xmlStrEqual(ns->href,
3580
style->exclPrefixTab[i]))) {
3581
/*
3582
* Move the namespace definition on the root
3583
* element to avoid duplicating it without
3584
* loosing it.
3585
*/
3586
if (prev == NULL) {
3587
cur->nsDef = ns->next;
3588
} else {
3589
prev->next = ns->next;
3590
}
3591
ns->next = root->nsDef;
3592
root->nsDef = ns;
3593
moved = 1;
3594
break;
3595
}
3596
}
3597
if (moved == 0)
3598
prev = ns;
3599
ns = next;
3600
}
3601
}
3602
}
3603
/*
3604
* If we have prefixes locally, recurse and pop them up when
3605
* going back
3606
*/
3607
if (exclPrefixes > 0) {
3608
xsltPreprocessStylesheet(style, cur->children);
3609
for (;exclPrefixes > 0;exclPrefixes--)
3610
exclPrefixPop(style);
3611
goto skip_children;
3612
}
3613
} else if (cur->type == XML_TEXT_NODE) {
3614
if (IS_BLANK_NODE(cur)) {
3615
if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
3616
deleteNode = cur;
3617
}
3618
} else if ((cur->content != NULL) && (internalize) &&
3619
(!xmlDictOwns(style->dict, cur->content))) {
3620
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
tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
3628
xmlNodeSetContent(cur, NULL);
3629
cur->content = tmp;
3630
}
3631
} else if ((cur->type != XML_ELEMENT_NODE) &&
3632
(cur->type != XML_CDATA_SECTION_NODE)) {
3633
deleteNode = cur;
3634
goto skip_children;
3635
}
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
if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
3643
(styleelem != NULL) && (cur->parent == styleelem) &&
3644
(!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
3645
(!xsltCheckExtURI(style, cur->ns->href))) {
3646
goto skip_children;
3647
} else if (cur->children != NULL) {
3648
cur = cur->children;
3649
continue;
3650
}
3651
3652
skip_children:
3653
if (cur->next != NULL) {
3654
cur = cur->next;
3655
continue;
3656
}
3657
do {
3658
3659
cur = cur->parent;
3660
if (cur == NULL)
3661
break;
3662
if (cur == (xmlNodePtr) style->doc) {
3663
cur = NULL;
3664
break;
3665
}
3666
if (cur->next != NULL) {
3667
cur = cur->next;
3668
break;
3669
}
3670
} while (cur != NULL);
3671
}
3672
if (deleteNode != NULL) {
3673
#ifdef WITH_XSLT_DEBUG_PARSING
3674
xsltGenericDebug(xsltGenericDebugContext,
3675
"xsltPreprocessStylesheet: removing ignorable blank node\n");
3676
#endif
3677
xmlUnlinkNode(deleteNode);
3678
xmlFreeNode(deleteNode);
3679
}
3680
}
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
xsltGatherNamespaces(xsltStylesheetPtr style) {
3693
xmlNodePtr cur;
3694
const xmlChar *URI;
3695
3696
if (style == NULL)
3697
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
cur = xmlDocGetRootElement(style->doc);
3711
while (cur != NULL) {
3712
if (cur->type == XML_ELEMENT_NODE) {
3713
xmlNsPtr ns = cur->nsDef;
3714
while (ns != NULL) {
3715
if (ns->prefix != NULL) {
3716
if (style->nsHash == NULL) {
3717
style->nsHash = xmlHashCreate(10);
3718
if (style->nsHash == NULL) {
3719
xsltTransformError(NULL, style, cur,
3720
"xsltGatherNamespaces: failed to create hash table\n");
3721
style->errors++;
3722
return;
3723
}
3724
}
3725
URI = xmlHashLookup(style->nsHash, ns->prefix);
3726
if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3727
xsltTransformError(NULL, style, cur,
3728
"Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3729
style->warnings++;
3730
} else if (URI == NULL) {
3731
xmlHashUpdateEntry(style->nsHash, ns->prefix,
3732
(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
}
3739
}
3740
ns = ns->next;
3741
}
3742
}
3743
3744
/*
3745
* Skip to next node
3746
*/
3747
if (cur->children != NULL) {
3748
if (cur->children->type != XML_ENTITY_DECL) {
3749
cur = cur->children;
3750
continue;
3751
}
3752
}
3753
if (cur->next != NULL) {
3754
cur = cur->next;
3755
continue;
3756
}
3757
3758
do {
3759
cur = cur->parent;
3760
if (cur == NULL)
3761
break;
3762
if (cur == (xmlNodePtr) style->doc) {
3763
cur = NULL;
3764
break;
3765
}
3766
if (cur->next != NULL) {
3767
cur = cur->next;
3768
break;
3769
}
3770
} while (cur != NULL);
3771
}
3772
}
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
xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4905
xmlNodePtr cur, delete;
4906
4907
if ((style == NULL) || (templ == NULL) ||
4908
(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
cur = templ->children;
4916
delete = NULL;
4917
while (cur != NULL) {
4918
style->principal->opCount += 1;
4919
4920
if (delete != NULL) {
4921
#ifdef WITH_XSLT_DEBUG_BLANKS
4922
xsltGenericDebug(xsltGenericDebugContext,
4923
"xsltParseTemplateContent: removing text\n");
4924
#endif
4925
xmlUnlinkNode(delete);
4926
xmlFreeNode(delete);
4927
delete = NULL;
4928
}
4929
if (IS_XSLT_ELEM(cur)) {
4930
xsltStylePreCompute(style, cur);
4931
4932
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
if (cur->children != NULL) {
4941
xmlChar *prop;
4942
xmlNodePtr text = cur->children, next;
4943
int noesc = 0;
4944
4945
prop = xmlGetNsProp(cur,
4946
(const xmlChar *)"disable-output-escaping",
4947
NULL);
4948
if (prop != NULL) {
4949
#ifdef WITH_XSLT_DEBUG_PARSING
4950
xsltGenericDebug(xsltGenericDebugContext,
4951
"Disable escaping: %s\n", text->content);
4952
#endif
4953
if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
4954
noesc = 1;
4955
} else if (!xmlStrEqual(prop,
4956
(const xmlChar *)"no")){
4957
xsltTransformError(NULL, style, cur,
4958
"xsl:text: disable-output-escaping allows only yes or no\n");
4959
style->warnings++;
4960
4961
}
4962
xmlFree(prop);
4963
}
4964
4965
while (text != NULL) {
4966
if (text->type == XML_COMMENT_NODE) {
4967
text = text->next;
4968
continue;
4969
}
4970
if ((text->type != XML_TEXT_NODE) &&
4971
(text->type != XML_CDATA_SECTION_NODE)) {
4972
xsltTransformError(NULL, style, cur,
4973
"xsltParseTemplateContent: xslt:text content problem\n");
4974
style->errors++;
4975
break;
4976
}
4977
if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
4978
text->name = xmlStringTextNoenc;
4979
text = text->next;
4980
}
4981
4982
/*
4983
* replace xsl:text by the list of childs
4984
*/
4985
if (text == NULL) {
4986
text = cur->children;
4987
while (text != NULL) {
4988
if ((style->internalized) &&
4989
(text->content != NULL) &&
4990
(!xmlDictOwns(style->dict, text->content))) {
4991
4992
/*
4993
* internalize the text string
4994
*/
4995
if (text->doc->dict != NULL) {
4996
const xmlChar *tmp;
4997
4998
tmp = xmlDictLookup(text->doc->dict,
4999
text->content, -1);
5000
if (tmp != text->content) {
5001
xmlNodeSetContent(text, NULL);
5002
text->content = (xmlChar *) tmp;
5003
}
5004
}
5005
}
5006
5007
next = text->next;
5008
xmlUnlinkNode(text);
5009
if (xmlAddPrevSibling(cur, text) == NULL) {
5010
xsltTransformError(NULL, style, NULL,
5011
"out of memory\n");
5012
xmlFreeNode(text);
5013
}
5014
text = next;
5015
}
5016
}
5017
}
5018
delete = cur;
5019
goto skip_children;
5020
}
5021
}
5022
else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
5023
(xsltCheckExtPrefix(style, cur->ns->prefix)))
5024
{
5025
/*
5026
* okay this is an extension element compile it too
5027
*/
5028
xsltStylePreCompute(style, cur);
5029
}
5030
else if (cur->type == XML_ELEMENT_NODE)
5031
{
5032
/*
5033
* This is an element which will be output as part of the
5034
* template exectution, precompile AVT if found.
5035
*/
5036
if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
5037
cur->ns = xmlSearchNsByHref(cur->doc, cur,
5038
style->defaultAlias);
5039
}
5040
if (cur->properties != NULL) {
5041
xmlAttrPtr attr = cur->properties;
5042
5043
while (attr != NULL) {
5044
xsltCompileAttr(style, attr);
5045
attr = attr->next;
5046
}
5047
}
5048
}
5049
/*
5050
* Skip to next node
5051
*/
5052
if (cur->children != NULL) {
5053
if (cur->children->type != XML_ENTITY_DECL) {
5054
cur = cur->children;
5055
continue;
5056
}
5057
}
5058
skip_children:
5059
if (cur->next != NULL) {
5060
cur = cur->next;
5061
continue;
5062
}
5063
5064
do {
5065
cur = cur->parent;
5066
if (cur == NULL)
5067
break;
5068
if (cur == templ) {
5069
cur = NULL;
5070
break;
5071
}
5072
if (cur->next != NULL) {
5073
cur = cur->next;
5074
break;
5075
}
5076
} while (cur != NULL);
5077
}
5078
if (delete != NULL) {
5079
#ifdef WITH_XSLT_DEBUG_PARSING
5080
xsltGenericDebug(xsltGenericDebugContext,
5081
"xsltParseTemplateContent: removing text\n");
5082
#endif
5083
xmlUnlinkNode(delete);
5084
xmlFreeNode(delete);
5085
delete = NULL;
5086
}
5087
5088
/*
5089
* Skip the first params
5090
*/
5091
cur = templ->children;
5092
while (cur != NULL) {
5093
if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
5094
break;
5095
cur = cur->next;
5096
}
5097
5098
/*
5099
* Browse the remainder of the template
5100
*/
5101
while (cur != NULL) {
5102
if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
5103
xmlNodePtr param = cur;
5104
5105
xsltTransformError(NULL, style, cur,
5106
"xsltParseTemplateContent: ignoring misplaced param element\n");
5107
if (style != NULL) style->warnings++;
5108
cur = cur->next;
5109
xmlUnlinkNode(param);
5110
xmlFreeNode(param);
5111
} else
5112
break;
5113
}
5114
}
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
xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
5131
xmlChar *prop = NULL;
5132
xmlChar *use = NULL;
5133
xmlChar *match = NULL;
5134
xmlChar *name = NULL;
5135
xmlChar *nameURI = NULL;
5136
5137
if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
5138
return;
5139
5140
/*
5141
* Get arguments
5142
*/
5143
prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
5144
if (prop != NULL) {
5145
const xmlChar *URI;
5146
5147
/*
5148
* TODO: Don't use xsltGetQNameURI().
5149
*/
5150
URI = xsltGetQNameURI(key, &prop);
5151
if (prop == NULL) {
5152
if (style != NULL) style->errors++;
5153
goto error;
5154
} else {
5155
name = prop;
5156
if (URI != NULL)
5157
nameURI = xmlStrdup(URI);
5158
}
5159
#ifdef WITH_XSLT_DEBUG_PARSING
5160
xsltGenericDebug(xsltGenericDebugContext,
5161
"xsltParseStylesheetKey: name %s\n", name);
5162
#endif
5163
} else {
5164
xsltTransformError(NULL, style, key,
5165
"xsl:key : error missing name\n");
5166
if (style != NULL) style->errors++;
5167
goto error;
5168
}
5169
5170
match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
5171
if (match == NULL) {
5172
xsltTransformError(NULL, style, key,
5173
"xsl:key : error missing match\n");
5174
if (style != NULL) style->errors++;
5175
goto error;
5176
}
5177
5178
use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
5179
if (use == NULL) {
5180
xsltTransformError(NULL, style, key,
5181
"xsl:key : error missing use\n");
5182
if (style != NULL) style->errors++;
5183
goto error;
5184
}
5185
5186
/*
5187
* register the keys
5188
*/
5189
xsltAddKey(style, name, nameURI, match, use, key);
5190
5191
5192
error:
5193
if (use != NULL)
5194
xmlFree(use);
5195
if (match != NULL)
5196
xmlFree(match);
5197
if (name != NULL)
5198
xmlFree(name);
5199
if (nameURI != NULL)
5200
xmlFree(nameURI);
5201
5202
if (key->children != NULL) {
5203
xsltParseContentError(style, key->children);
5204
}
5205
}
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
xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
5383
xsltTemplatePtr ret;
5384
xmlChar *prop;
5385
xmlChar *mode = NULL;
5386
xmlChar *modeURI = NULL;
5387
double priority;
5388
5389
if ((style == NULL) || (template == NULL) ||
5390
(template->type != XML_ELEMENT_NODE))
5391
return;
5392
5393
if (style->principal->opLimit > 0) {
5394
if (style->principal->opCount > style->principal->opLimit) {
5395
xsltTransformError(NULL, style, NULL,
5396
"XSLT parser operation limit exceeded\n");
5397
style->errors++;
5398
return;
5399
}
5400
}
5401
5402
/*
5403
* Create and link the structure
5404
*/
5405
ret = xsltNewTemplate();
5406
if (ret == NULL)
5407
return;
5408
ret->next = style->templates;
5409
style->templates = ret;
5410
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
xsltGetInheritedNsList(style, ret, template);
5420
5421
/*
5422
* Get arguments
5423
*/
5424
prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
5425
if (prop != NULL) {
5426
const xmlChar *URI;
5427
5428
/*
5429
* TODO: Don't use xsltGetQNameURI().
5430
*/
5431
URI = xsltGetQNameURI(template, &prop);
5432
if (prop == NULL) {
5433
if (style != NULL) style->errors++;
5434
goto error;
5435
} else {
5436
mode = prop;
5437
if (URI != NULL)
5438
modeURI = xmlStrdup(URI);
5439
}
5440
ret->mode = xmlDictLookup(style->dict, mode, -1);
5441
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
if (mode != NULL) xmlFree(mode);
5447
if (modeURI != NULL) xmlFree(modeURI);
5448
}
5449
prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
5450
if (prop != NULL) {
5451
if (ret->match != NULL) xmlFree(ret->match);
5452
ret->match = prop;
5453
}
5454
5455
prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
5456
if (prop != NULL) {
5457
priority = xmlXPathStringEvalNumber(prop);
5458
ret->priority = (float) priority;
5459
xmlFree(prop);
5460
}
5461
5462
prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
5463
if (prop != NULL) {
5464
const xmlChar *URI;
5465
5466
/*
5467
* TODO: Don't use xsltGetQNameURI().
5468
*/
5469
URI = xsltGetQNameURI(template, &prop);
5470
if (prop == NULL) {
5471
if (style != NULL) style->errors++;
5472
goto error;
5473
} else {
5474
if (xmlValidateNCName(prop,0)) {
5475
xsltTransformError(NULL, style, template,
5476
"xsl:template : error invalid name '%s'\n", prop);
5477
if (style != NULL) style->errors++;
5478
xmlFree(prop);
5479
goto error;
5480
}
5481
ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
5482
xmlFree(prop);
5483
prop = NULL;
5484
if (URI != NULL)
5485
ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
5486
else
5487
ret->nameURI = NULL;
5488
}
5489
}
5490
5491
/*
5492
* parse the content and register the pattern
5493
*/
5494
xsltParseTemplateContent(style, template);
5495
ret->elem = template;
5496
ret->content = template->children;
5497
xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
5498
5499
error:
5500
return;
5501
}
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
xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
6117
xmlNodePtr cur;
6118
xmlChar *prop;
6119
#ifdef WITH_XSLT_DEBUG_PARSING
6120
int templates = 0;
6121
#endif
6122
6123
if ((top == NULL) || (top->type != XML_ELEMENT_NODE))
6124
return;
6125
6126
if (style->principal->opLimit > 0) {
6127
if (style->principal->opCount > style->principal->opLimit) {
6128
xsltTransformError(NULL, style, NULL,
6129
"XSLT parser operation limit exceeded\n");
6130
style->errors++;
6131
return;
6132
}
6133
}
6134
6135
prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
6136
if (prop == NULL) {
6137
xsltTransformError(NULL, style, top,
6138
"xsl:version is missing: document may not be a stylesheet\n");
6139
if (style != NULL) style->warnings++;
6140
} else {
6141
if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6142
(!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6143
xsltTransformError(NULL, style, top,
6144
"xsl:version: only 1.1 features are supported\n");
6145
if (style != NULL) {
6146
style->forwards_compatible = 1;
6147
style->warnings++;
6148
}
6149
}
6150
xmlFree(prop);
6151
}
6152
6153
/*
6154
* process xsl:import elements
6155
*/
6156
cur = top->children;
6157
while (cur != NULL) {
6158
style->principal->opCount += 1;
6159
6160
if (IS_BLANK_NODE(cur)) {
6161
cur = cur->next;
6162
continue;
6163
}
6164
if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
6165
if (xsltParseStylesheetImport(style, cur) != 0)
6166
if (style != NULL) style->errors++;
6167
} else
6168
break;
6169
cur = cur->next;
6170
}
6171
6172
/*
6173
* process other top-level elements
6174
*/
6175
while (cur != NULL) {
6176
style->principal->opCount += 1;
6177
6178
if (IS_BLANK_NODE(cur)) {
6179
cur = cur->next;
6180
continue;
6181
}
6182
if (cur->type == XML_TEXT_NODE) {
6183
if (cur->content != NULL) {
6184
xsltTransformError(NULL, style, cur,
6185
"misplaced text node: '%s'\n", cur->content);
6186
}
6187
if (style != NULL) style->errors++;
6188
cur = cur->next;
6189
continue;
6190
}
6191
if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
6192
xsltGenericError(xsltGenericErrorContext,
6193
"Found a top-level element %s with null namespace URI\n",
6194
cur->name);
6195
if (style != NULL) style->errors++;
6196
cur = cur->next;
6197
continue;
6198
}
6199
if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
6200
xsltTopLevelFunction function;
6201
6202
function = xsltExtModuleTopLevelLookup(cur->name,
6203
cur->ns->href);
6204
if (function != NULL)
6205
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
cur = cur->next;
6213
continue;
6214
}
6215
if (IS_XSLT_NAME(cur, "import")) {
6216
xsltTransformError(NULL, style, cur,
6217
"xsltParseStylesheetTop: ignoring misplaced import element\n");
6218
if (style != NULL) style->errors++;
6219
} else if (IS_XSLT_NAME(cur, "include")) {
6220
if (xsltParseStylesheetInclude(style, cur) != 0)
6221
if (style != NULL) style->errors++;
6222
} else if (IS_XSLT_NAME(cur, "strip-space")) {
6223
xsltParseStylesheetStripSpace(style, cur);
6224
} else if (IS_XSLT_NAME(cur, "preserve-space")) {
6225
xsltParseStylesheetPreserveSpace(style, cur);
6226
} else if (IS_XSLT_NAME(cur, "output")) {
6227
xsltParseStylesheetOutput(style, cur);
6228
} else if (IS_XSLT_NAME(cur, "key")) {
6229
xsltParseStylesheetKey(style, cur);
6230
} else if (IS_XSLT_NAME(cur, "decimal-format")) {
6231
xsltParseStylesheetDecimalFormat(style, cur);
6232
} else if (IS_XSLT_NAME(cur, "attribute-set")) {
6233
xsltParseStylesheetAttributeSet(style, cur);
6234
} else if (IS_XSLT_NAME(cur, "variable")) {
6235
xsltParseGlobalVariable(style, cur);
6236
} else if (IS_XSLT_NAME(cur, "param")) {
6237
xsltParseGlobalParam(style, cur);
6238
} else if (IS_XSLT_NAME(cur, "template")) {
6239
#ifdef WITH_XSLT_DEBUG_PARSING
6240
templates++;
6241
#endif
6242
xsltParseStylesheetTemplate(style, cur);
6243
} else if (IS_XSLT_NAME(cur, "namespace-alias")) {
6244
xsltNamespaceAlias(style, cur);
6245
} else {
6246
if ((style != NULL) && (style->forwards_compatible == 0)) {
6247
xsltTransformError(NULL, style, cur,
6248
"xsltParseStylesheetTop: unknown %s element\n",
6249
cur->name);
6250
if (style != NULL) style->errors++;
6251
}
6252
}
6253
cur = cur->next;
6254
}
6255
#ifdef WITH_XSLT_DEBUG_PARSING
6256
xsltGenericDebug(xsltGenericDebugContext,
6257
"parsed %d templates\n", templates);
6258
#endif
6259
}
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
xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
6458
xmlNodePtr cur;
6459
6460
xsltInitGlobals();
6461
6462
if (doc == NULL)
6463
return(NULL);
6464
if (ret == NULL)
6465
return(ret);
6466
6467
/*
6468
* First steps, remove blank nodes,
6469
* locate the xsl:stylesheet element and the
6470
* namespace declaration.
6471
*/
6472
cur = xmlDocGetRootElement(doc);
6473
if (cur == NULL) {
6474
xsltTransformError(NULL, ret, (xmlNodePtr) doc,
6475
"xsltParseStylesheetProcess : empty stylesheet\n");
6476
return(NULL);
6477
}
6478
6479
if ((IS_XSLT_ELEM(cur)) &&
6480
((IS_XSLT_NAME(cur, "stylesheet")) ||
6481
(IS_XSLT_NAME(cur, "transform")))) {
6482
#ifdef WITH_XSLT_DEBUG_PARSING
6483
xsltGenericDebug(xsltGenericDebugContext,
6484
"xsltParseStylesheetProcess : found stylesheet\n");
6485
#endif
6486
ret->literal_result = 0;
6487
xsltParseStylesheetExcludePrefix(ret, cur, 1);
6488
xsltParseStylesheetExtPrefix(ret, cur, 1);
6489
} else {
6490
xsltParseStylesheetExcludePrefix(ret, cur, 0);
6491
xsltParseStylesheetExtPrefix(ret, cur, 0);
6492
ret->literal_result = 1;
6493
}
6494
if (!ret->nopreproc) {
6495
xsltPreprocessStylesheet(ret, cur);
6496
}
6497
if (ret->literal_result == 0) {
6498
xsltParseStylesheetTop(ret, cur);
6499
} else {
6500
xmlChar *prop;
6501
xsltTemplatePtr template;
6502
6503
/*
6504
* the document itself might be the template, check xsl:version
6505
*/
6506
prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
6507
if (prop == NULL) {
6508
xsltTransformError(NULL, ret, cur,
6509
"xsltParseStylesheetProcess : document is not a stylesheet\n");
6510
return(NULL);
6511
}
6512
6513
#ifdef WITH_XSLT_DEBUG_PARSING
6514
xsltGenericDebug(xsltGenericDebugContext,
6515
"xsltParseStylesheetProcess : document is stylesheet\n");
6516
#endif
6517
6518
if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6519
(!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6520
xsltTransformError(NULL, ret, cur,
6521
"xsl:version: only 1.1 features are supported\n");
6522
ret->forwards_compatible = 1;
6523
ret->warnings++;
6524
}
6525
xmlFree(prop);
6526
6527
/*
6528
* Create and link the template
6529
*/
6530
template = xsltNewTemplate();
6531
if (template == NULL) {
6532
return(NULL);
6533
}
6534
template->next = ret->templates;
6535
ret->templates = template;
6536
template->match = xmlStrdup((const xmlChar *)"/");
6537
6538
/*
6539
* parse the content and register the pattern
6540
*/
6541
xsltParseTemplateContent(ret, (xmlNodePtr) doc);
6542
template->elem = (xmlNodePtr) doc;
6543
template->content = doc->children;
6544
xsltAddTemplate(ret, template, NULL, NULL);
6545
ret->literal_result = 1;
6546
}
6547
6548
return(ret);
6549
}
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
xsltStylesheetPtr parentStyle) {
6567
xsltStylesheetPtr retStyle;
6568
6569
if (doc == NULL)
6570
return(NULL);
6571
6572
retStyle = xsltNewStylesheetInternal(parentStyle);
6573
if (retStyle == NULL)
6574
return(NULL);
6575
6576
if (xsltParseStylesheetUser(retStyle, doc) != 0) {
6577
xsltFreeStylesheet(retStyle);
6578
return(NULL);
6579
}
6580
6581
return(retStyle);
6582
}
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
xsltParseStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc) {
6595
if ((style == NULL) || (doc == NULL))
6596
return(-1);
6597
6598
/*
6599
* Adjust the string dict.
6600
*/
6601
if (doc->dict != NULL) {
6602
xmlDictFree(style->dict);
6603
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
xmlDictReference(style->dict);
6610
}
6611
6612
/*
6613
* TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6614
* the stylesheet to containt distinct namespace prefixes.
6615
*/
6616
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
style->doc = doc;
6706
if (xsltParseStylesheetProcess(style, doc) == NULL) {
6707
style->doc = NULL;
6708
return(-1);
6709
}
6710
#endif /* else of XSLT_REFACTORED */
6711
6712
if (style->parent == NULL)
6713
xsltResolveStylesheetAttributeSet(style);
6714
6715
if (style->errors != 0) {
6716
/*
6717
* Detach the doc from the stylesheet; otherwise the doc
6718
* will be freed in xsltFreeStylesheet().
6719
*/
6720
style->doc = NULL;
6721
/*
6722
* Cleanup the doc if its the main stylesheet.
6723
*/
6724
if (style->parent == NULL)
6725
xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
6726
return(-1);
6727
}
6728
6729
return(0);
6730
}
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
xsltParseStylesheetDoc(xmlDocPtr doc) {
6747
xsltInitGlobals();
6748
6749
return(xsltParseStylesheetImportedDoc(doc, NULL));
6750
}
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
xsltParseStylesheetFile(const xmlChar* filename) {
6763
xsltSecurityPrefsPtr sec;
6764
xsltStylesheetPtr ret;
6765
xmlDocPtr doc;
6766
6767
xsltInitGlobals();
6768
6769
if (filename == NULL)
6770
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
sec = xsltGetDefaultSecurityPrefs();
6781
if (sec != NULL) {
6782
int res;
6783
6784
res = xsltCheckRead(sec, NULL, filename);
6785
if (res <= 0) {
6786
if (res == 0)
6787
xsltTransformError(NULL, NULL, NULL,
6788
"xsltParseStylesheetFile: read rights for %s denied\n",
6789
filename);
6790
return(NULL);
6791
}
6792
}
6793
6794
doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
6795
NULL, XSLT_LOAD_START);
6796
if (doc == NULL) {
6797
xsltTransformError(NULL, NULL, NULL,
6798
"xsltParseStylesheetFile : cannot parse %s\n", filename);
6799
return(NULL);
6800
}
6801
ret = xsltParseStylesheetDoc(doc);
6802
if (ret == NULL) {
6803
xmlFreeDoc(doc);
6804
return(NULL);
6805
}
6806
6807
return(ret);
6808
}
6809
6810
/************************************************************************
6811
* *
6812
* Handling of Stylesheet PI *
6813
* *
6814
************************************************************************/
6815
6816
#define CUR (*cur)
6817
#define SKIP(val) cur += (val)
6818
#define NXT(val) cur[(val)]
6819
#define SKIP_BLANKS \
6820
while (IS_BLANK(CUR)) NEXT
6821
#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
xsltParseStylesheetPI(const xmlChar *value) {
6835
const xmlChar *cur;
6836
const xmlChar *start;
6837
xmlChar *val;
6838
xmlChar tmp;
6839
xmlChar *href = NULL;
6840
int isXml = 0;
6841
6842
if (value == NULL)
6843
return(NULL);
6844
6845
cur = value;
6846
while (CUR != 0) {
6847
SKIP_BLANKS;
6848
if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6849
(NXT(3) == 'e')) {
6850
SKIP(4);
6851
SKIP_BLANKS;
6852
if (CUR != '=')
6853
continue;
6854
NEXT;
6855
if ((CUR != '\'') && (CUR != '"'))
6856
continue;
6857
tmp = CUR;
6858
NEXT;
6859
start = cur;
6860
while ((CUR != 0) && (CUR != tmp))
6861
NEXT;
6862
if (CUR != tmp)
6863
continue;
6864
val = xmlStrndup(start, cur - start);
6865
NEXT;
6866
if (val == NULL)
6867
return(NULL);
6868
if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
6869
(xmlStrcasecmp(val, BAD_CAST "text/xsl")) &&
6870
(xmlStrcasecmp(val, BAD_CAST "application/xslt+xml"))) {
6871
xmlFree(val);
6872
break;
6873
}
6874
isXml = 1;
6875
xmlFree(val);
6876
} else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6877
(NXT(3) == 'f')) {
6878
SKIP(4);
6879
SKIP_BLANKS;
6880
if (CUR != '=')
6881
continue;
6882
NEXT;
6883
if ((CUR != '\'') && (CUR != '"'))
6884
continue;
6885
tmp = CUR;
6886
NEXT;
6887
start = cur;
6888
while ((CUR != 0) && (CUR != tmp))
6889
NEXT;
6890
if (CUR != tmp)
6891
continue;
6892
if (href == NULL)
6893
href = xmlStrndup(start, cur - start);
6894
NEXT;
6895
} else {
6896
while ((CUR != 0) && (!IS_BLANK(CUR)))
6897
NEXT;
6898
}
6899
6900
}
6901
6902
if (!isXml) {
6903
if (href != NULL)
6904
xmlFree(href);
6905
href = NULL;
6906
}
6907
return(href);
6908
}
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
xsltLoadStylesheetPI(xmlDocPtr doc) {
6926
xmlNodePtr child;
6927
xsltStylesheetPtr ret = NULL;
6928
xmlChar *href = NULL;
6929
xmlURIPtr URI;
6930
6931
xsltInitGlobals();
6932
6933
if (doc == NULL)
6934
return(NULL);
6935
6936
/*
6937
* Find the text/xml stylesheet PI id any before the root
6938
*/
6939
child = doc->children;
6940
while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
6941
if ((child->type == XML_PI_NODE) &&
6942
(xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
6943
href = xsltParseStylesheetPI(child->content);
6944
if (href != NULL)
6945
break;
6946
}
6947
child = child->next;
6948
}
6949
6950
/*
6951
* If found check the href to select processing
6952
*/
6953
if (href != NULL) {
6954
#ifdef WITH_XSLT_DEBUG_PARSING
6955
xsltGenericDebug(xsltGenericDebugContext,
6956
"xsltLoadStylesheetPI : found PI href=%s\n", href);
6957
#endif
6958
URI = xmlParseURI((const char *) href);
6959
if (URI == NULL) {
6960
xsltTransformError(NULL, NULL, child,
6961
"xml-stylesheet : href %s is not valid\n", href);
6962
xmlFree(href);
6963
return(NULL);
6964
}
6965
if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
6966
(URI->opaque == NULL) && (URI->authority == NULL) &&
6967
(URI->server == NULL) && (URI->user == NULL) &&
6968
(URI->path == NULL) && (URI->query == NULL)) {
6969
xmlAttrPtr ID;
6970
6971
#ifdef WITH_XSLT_DEBUG_PARSING
6972
xsltGenericDebug(xsltGenericDebugContext,
6973
"xsltLoadStylesheetPI : Reference to ID %s\n", href);
6974
#endif
6975
if (URI->fragment[0] == '#')
6976
ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
6977
else
6978
ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
6979
if (ID == NULL) {
6980
xsltTransformError(NULL, NULL, child,
6981
"xml-stylesheet : no ID %s found\n", URI->fragment);
6982
} else {
6983
xmlDocPtr fake;
6984
xmlNodePtr subtree, newtree;
6985
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
subtree = ID->parent;
6997
fake = xmlNewDoc(NULL);
6998
if (fake != NULL) {
6999
/*
7000
* Should the dictionary still be shared even though
7001
* the nodes are being copied rather than moved?
7002
*/
7003
fake->dict = doc->dict;
7004
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
newtree = xmlDocCopyNode(subtree, fake, 1);
7012
7013
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
while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
7025
for (ns = subtree->ns; ns; ns = ns->next) {
7026
xmlNewNs(newtree, ns->href, ns->prefix);
7027
}
7028
}
7029
7030
xmlAddChild((xmlNodePtr)fake, newtree);
7031
ret = xsltParseStylesheetDoc(fake);
7032
if (ret == NULL)
7033
xmlFreeDoc(fake);
7034
}
7035
}
7036
} else {
7037
xmlChar *URL, *base;
7038
7039
/*
7040
* Reference to an external stylesheet
7041
*/
7042
7043
base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
7044
URL = xmlBuildURI(href, base);
7045
if (URL != NULL) {
7046
#ifdef WITH_XSLT_DEBUG_PARSING
7047
xsltGenericDebug(xsltGenericDebugContext,
7048
"xsltLoadStylesheetPI : fetching %s\n", URL);
7049
#endif
7050
ret = xsltParseStylesheetFile(URL);
7051
xmlFree(URL);
7052
} else {
7053
#ifdef WITH_XSLT_DEBUG_PARSING
7054
xsltGenericDebug(xsltGenericDebugContext,
7055
"xsltLoadStylesheetPI : fetching %s\n", href);
7056
#endif
7057
ret = xsltParseStylesheetFile(href);
7058
}
7059
if (base != NULL)
7060
xmlFree(base);
7061
}
7062
xmlFreeURI(URI);
7063
xmlFree(href);
7064
}
7065
return(ret);
7066
}
7067
7068