Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xslt/libxslt/templates.c
4389 views
1
/*
2
* templates.c: Implementation of the template processing
3
*
4
* Reference:
5
* http://www.w3.org/TR/1999/REC-xslt-19991116
6
*
7
* See Copyright for the status of this software.
8
*
9
* [email protected]
10
*/
11
12
#define IN_LIBXSLT
13
#include "libxslt.h"
14
15
#include <string.h>
16
17
#include <libxml/xmlmemory.h>
18
#include <libxml/globals.h>
19
#include <libxml/xmlerror.h>
20
#include <libxml/tree.h>
21
#include <libxml/dict.h>
22
#include <libxml/xpathInternals.h>
23
#include <libxml/parserInternals.h>
24
#include "xslt.h"
25
#include "xsltInternals.h"
26
#include "xsltutils.h"
27
#include "variables.h"
28
#include "functions.h"
29
#include "templates.h"
30
#include "transform.h"
31
#include "namespaces.h"
32
#include "attributes.h"
33
34
#ifdef WITH_XSLT_DEBUG
35
#define WITH_XSLT_DEBUG_TEMPLATES
36
#endif
37
38
/************************************************************************
39
* *
40
* Module interfaces *
41
* *
42
************************************************************************/
43
44
/**
45
* xsltEvalXPathPredicate:
46
* @ctxt: the XSLT transformation context
47
* @comp: the XPath compiled expression
48
* @nsList: the namespaces in scope
49
* @nsNr: the number of namespaces in scope
50
*
51
* Process the expression using XPath and evaluate the result as
52
* an XPath predicate
53
*
54
* Returns 1 is the predicate was true, 0 otherwise
55
*/
56
int
57
xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
58
xmlNsPtr *nsList, int nsNr) {
59
int ret;
60
xmlXPathObjectPtr res;
61
int oldNsNr;
62
xmlNsPtr *oldNamespaces;
63
xmlNodePtr oldInst;
64
xmlNodePtr oldNode;
65
int oldProximityPosition, oldContextSize;
66
67
if ((ctxt == NULL) || (ctxt->inst == NULL)) {
68
xsltTransformError(ctxt, NULL, NULL,
69
"xsltEvalXPathPredicate: No context or instruction\n");
70
return(0);
71
}
72
73
oldNode = ctxt->xpathCtxt->node;
74
oldContextSize = ctxt->xpathCtxt->contextSize;
75
oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
76
oldNsNr = ctxt->xpathCtxt->nsNr;
77
oldNamespaces = ctxt->xpathCtxt->namespaces;
78
oldInst = ctxt->inst;
79
80
ctxt->xpathCtxt->node = ctxt->node;
81
ctxt->xpathCtxt->namespaces = nsList;
82
ctxt->xpathCtxt->nsNr = nsNr;
83
84
res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
85
86
if (res != NULL) {
87
ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res);
88
xmlXPathFreeObject(res);
89
#ifdef WITH_XSLT_DEBUG_TEMPLATES
90
XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
91
"xsltEvalXPathPredicate: returns %d\n", ret));
92
#endif
93
} else {
94
#ifdef WITH_XSLT_DEBUG_TEMPLATES
95
XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
96
"xsltEvalXPathPredicate: failed\n"));
97
#endif
98
ctxt->state = XSLT_STATE_STOPPED;
99
ret = 0;
100
}
101
102
ctxt->xpathCtxt->node = oldNode;
103
ctxt->xpathCtxt->nsNr = oldNsNr;
104
ctxt->xpathCtxt->namespaces = oldNamespaces;
105
ctxt->inst = oldInst;
106
ctxt->xpathCtxt->contextSize = oldContextSize;
107
ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
108
109
return(ret);
110
}
111
112
/**
113
* xsltEvalXPathStringNs:
114
* @ctxt: the XSLT transformation context
115
* @comp: the compiled XPath expression
116
* @nsNr: the number of namespaces in the list
117
* @nsList: the list of in-scope namespaces to use
118
*
119
* Process the expression using XPath, allowing to pass a namespace mapping
120
* context and get a string
121
*
122
* Returns the computed string value or NULL, must be deallocated by the
123
* caller.
124
*/
125
xmlChar *
126
xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
127
int nsNr, xmlNsPtr *nsList) {
128
xmlChar *ret = NULL;
129
xmlXPathObjectPtr res;
130
xmlNodePtr oldInst;
131
xmlNodePtr oldNode;
132
int oldPos, oldSize;
133
int oldNsNr;
134
xmlNsPtr *oldNamespaces;
135
136
if ((ctxt == NULL) || (ctxt->inst == NULL)) {
137
xsltTransformError(ctxt, NULL, NULL,
138
"xsltEvalXPathStringNs: No context or instruction\n");
139
return(0);
140
}
141
142
oldInst = ctxt->inst;
143
oldNode = ctxt->xpathCtxt->node;
144
oldPos = ctxt->xpathCtxt->proximityPosition;
145
oldSize = ctxt->xpathCtxt->contextSize;
146
oldNsNr = ctxt->xpathCtxt->nsNr;
147
oldNamespaces = ctxt->xpathCtxt->namespaces;
148
149
ctxt->xpathCtxt->node = ctxt->node;
150
/* TODO: do we need to propagate the namespaces here ? */
151
ctxt->xpathCtxt->namespaces = nsList;
152
ctxt->xpathCtxt->nsNr = nsNr;
153
res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
154
if (res != NULL) {
155
if (res->type != XPATH_STRING)
156
res = xmlXPathConvertString(res);
157
if ((res != NULL) && (res->type == XPATH_STRING)) {
158
ret = res->stringval;
159
res->stringval = NULL;
160
} else {
161
xsltTransformError(ctxt, NULL, NULL,
162
"xpath : string() function didn't return a String\n");
163
}
164
xmlXPathFreeObject(res);
165
} else {
166
ctxt->state = XSLT_STATE_STOPPED;
167
}
168
#ifdef WITH_XSLT_DEBUG_TEMPLATES
169
XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
170
"xsltEvalXPathString: returns %s\n", ret));
171
#endif
172
ctxt->inst = oldInst;
173
ctxt->xpathCtxt->node = oldNode;
174
ctxt->xpathCtxt->contextSize = oldSize;
175
ctxt->xpathCtxt->proximityPosition = oldPos;
176
ctxt->xpathCtxt->nsNr = oldNsNr;
177
ctxt->xpathCtxt->namespaces = oldNamespaces;
178
return(ret);
179
}
180
181
/**
182
* xsltEvalXPathString:
183
* @ctxt: the XSLT transformation context
184
* @comp: the compiled XPath expression
185
*
186
* Process the expression using XPath and get a string
187
*
188
* Returns the computed string value or NULL, must be deallocated by the
189
* caller.
190
*/
191
xmlChar *
192
xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
193
return(xsltEvalXPathStringNs(ctxt, comp, 0, NULL));
194
}
195
196
/**
197
* xsltEvalTemplateString:
198
* @ctxt: the XSLT transformation context
199
* @contextNode: the current node in the source tree
200
* @inst: the XSLT instruction (xsl:comment, xsl:processing-instruction)
201
*
202
* Processes the sequence constructor of the given instruction on
203
* @contextNode and converts the resulting tree to a string.
204
* This is needed by e.g. xsl:comment and xsl:processing-instruction.
205
*
206
* Returns the computed string value or NULL; it's up to the caller to
207
* free the result.
208
*/
209
xmlChar *
210
xsltEvalTemplateString(xsltTransformContextPtr ctxt,
211
xmlNodePtr contextNode,
212
xmlNodePtr inst)
213
{
214
xmlNodePtr oldInsert, insert = NULL;
215
xmlChar *ret;
216
const xmlChar *oldLastText;
217
int oldLastTextSize, oldLastTextUse;
218
219
if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) ||
220
(inst->type != XML_ELEMENT_NODE))
221
return(NULL);
222
223
if (inst->children == NULL)
224
return(NULL);
225
226
/*
227
* This creates a temporary element-node to add the resulting
228
* text content to.
229
* OPTIMIZE TODO: Keep such an element-node in the transformation
230
* context to avoid creating it every time.
231
*/
232
insert = xmlNewDocNode(ctxt->output, NULL,
233
(const xmlChar *)"fake", NULL);
234
if (insert == NULL) {
235
xsltTransformError(ctxt, NULL, inst,
236
"Failed to create temporary node\n");
237
return(NULL);
238
}
239
oldInsert = ctxt->insert;
240
ctxt->insert = insert;
241
oldLastText = ctxt->lasttext;
242
oldLastTextSize = ctxt->lasttsize;
243
oldLastTextUse = ctxt->lasttuse;
244
/*
245
* OPTIMIZE TODO: if inst->children consists only of text-nodes.
246
*/
247
xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL);
248
249
ctxt->insert = oldInsert;
250
ctxt->lasttext = oldLastText;
251
ctxt->lasttsize = oldLastTextSize;
252
ctxt->lasttuse = oldLastTextUse;
253
254
ret = xmlNodeGetContent(insert);
255
if (insert != NULL)
256
xmlFreeNode(insert);
257
return(ret);
258
}
259
260
/**
261
* xsltAttrTemplateValueProcessNode:
262
* @ctxt: the XSLT transformation context
263
* @str: the attribute template node value
264
* @inst: the instruction (or LRE) in the stylesheet holding the
265
* attribute with an AVT
266
*
267
* Process the given string, allowing to pass a namespace mapping
268
* context and return the new string value.
269
*
270
* Called by:
271
* - xsltAttrTemplateValueProcess() (templates.c)
272
* - xsltEvalAttrValueTemplate() (templates.c)
273
*
274
* QUESTION: Why is this function public? It is not used outside
275
* of templates.c.
276
*
277
* Returns the computed string value or NULL, must be deallocated by the
278
* caller.
279
*/
280
xmlChar *
281
xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
282
const xmlChar *str, xmlNodePtr inst)
283
{
284
xmlChar *ret = NULL;
285
const xmlChar *cur;
286
xmlChar *expr, *val;
287
xmlNsPtr *nsList = NULL;
288
int nsNr = 0;
289
290
if (str == NULL) return(NULL);
291
if (*str == 0)
292
return(xmlStrndup((xmlChar *)"", 0));
293
294
cur = str;
295
while (*cur != 0) {
296
if (*cur == '{') {
297
if (*(cur+1) == '{') { /* escaped '{' */
298
cur++;
299
ret = xmlStrncat(ret, str, cur - str);
300
cur++;
301
str = cur;
302
continue;
303
}
304
ret = xmlStrncat(ret, str, cur - str);
305
str = cur;
306
cur++;
307
while ((*cur != 0) && (*cur != '}')) {
308
/* Need to check for literal (bug539741) */
309
if ((*cur == '\'') || (*cur == '"')) {
310
char delim = *(cur++);
311
while ((*cur != 0) && (*cur != delim))
312
cur++;
313
if (*cur != 0)
314
cur++; /* skip the ending delimiter */
315
} else
316
cur++;
317
}
318
if (*cur == 0) {
319
xsltTransformError(ctxt, NULL, inst,
320
"xsltAttrTemplateValueProcessNode: unmatched '{'\n");
321
ret = xmlStrncat(ret, str, cur - str);
322
goto exit;
323
}
324
str++;
325
expr = xmlStrndup(str, cur - str);
326
if (expr == NULL)
327
goto exit;
328
else if (*expr == '{') {
329
ret = xmlStrcat(ret, expr);
330
xmlFree(expr);
331
} else {
332
xmlXPathCompExprPtr comp;
333
/*
334
* TODO: keep precompiled form around
335
*/
336
if ((nsList == NULL) && (inst != NULL)) {
337
int i = 0;
338
339
nsList = xmlGetNsList(inst->doc, inst);
340
if (nsList != NULL) {
341
while (nsList[i] != NULL)
342
i++;
343
nsNr = i;
344
}
345
}
346
comp = xmlXPathCtxtCompile(ctxt->xpathCtxt, expr);
347
val = xsltEvalXPathStringNs(ctxt, comp, nsNr, nsList);
348
xmlXPathFreeCompExpr(comp);
349
xmlFree(expr);
350
if (val != NULL) {
351
ret = xmlStrcat(ret, val);
352
xmlFree(val);
353
}
354
}
355
cur++;
356
str = cur;
357
} else if (*cur == '}') {
358
cur++;
359
if (*cur == '}') { /* escaped '}' */
360
ret = xmlStrncat(ret, str, cur - str);
361
cur++;
362
str = cur;
363
continue;
364
} else {
365
xsltTransformError(ctxt, NULL, inst,
366
"xsltAttrTemplateValueProcessNode: unmatched '}'\n");
367
}
368
} else
369
cur++;
370
}
371
if (cur != str) {
372
ret = xmlStrncat(ret, str, cur - str);
373
}
374
375
exit:
376
if (nsList != NULL)
377
xmlFree(nsList);
378
379
return(ret);
380
}
381
382
/**
383
* xsltAttrTemplateValueProcess:
384
* @ctxt: the XSLT transformation context
385
* @str: the attribute template node value
386
*
387
* Process the given node and return the new string value.
388
*
389
* Returns the computed string value or NULL, must be deallocated by the
390
* caller.
391
*/
392
xmlChar *
393
xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {
394
return(xsltAttrTemplateValueProcessNode(ctxt, str, NULL));
395
}
396
397
/**
398
* xsltEvalAttrValueTemplate:
399
* @ctxt: the XSLT transformation context
400
* @inst: the instruction (or LRE) in the stylesheet holding the
401
* attribute with an AVT
402
* @name: the attribute QName
403
* @ns: the attribute namespace URI
404
*
405
* Evaluate a attribute value template, i.e. the attribute value can
406
* contain expressions contained in curly braces ({}) and those are
407
* substituted by they computed value.
408
*
409
* Returns the computed string value or NULL, must be deallocated by the
410
* caller.
411
*/
412
xmlChar *
413
xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst,
414
const xmlChar *name, const xmlChar *ns)
415
{
416
xmlChar *ret;
417
xmlChar *expr;
418
419
if ((ctxt == NULL) || (inst == NULL) || (name == NULL) ||
420
(inst->type != XML_ELEMENT_NODE))
421
return(NULL);
422
423
expr = xsltGetNsProp(inst, name, ns);
424
if (expr == NULL)
425
return(NULL);
426
427
/*
428
* TODO: though now {} is detected ahead, it would still be good to
429
* optimize both functions to keep the splitted value if the
430
* attribute content and the XPath precompiled expressions around
431
*/
432
433
ret = xsltAttrTemplateValueProcessNode(ctxt, expr, inst);
434
#ifdef WITH_XSLT_DEBUG_TEMPLATES
435
XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
436
"xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret));
437
#endif
438
if (expr != NULL)
439
xmlFree(expr);
440
return(ret);
441
}
442
443
/**
444
* xsltEvalStaticAttrValueTemplate:
445
* @style: the XSLT stylesheet
446
* @inst: the instruction (or LRE) in the stylesheet holding the
447
* attribute with an AVT
448
* @name: the attribute Name
449
* @ns: the attribute namespace URI
450
* @found: indicator whether the attribute is present
451
*
452
* Check if an attribute value template has a static value, i.e. the
453
* attribute value does not contain expressions contained in curly braces ({})
454
*
455
* Returns the static string value or NULL, must be deallocated by the
456
* caller.
457
*/
458
const xmlChar *
459
xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst,
460
const xmlChar *name, const xmlChar *ns, int *found) {
461
const xmlChar *ret;
462
xmlChar *expr;
463
464
if ((style == NULL) || (inst == NULL) || (name == NULL) ||
465
(inst->type != XML_ELEMENT_NODE))
466
return(NULL);
467
468
expr = xsltGetNsProp(inst, name, ns);
469
if (expr == NULL) {
470
*found = 0;
471
return(NULL);
472
}
473
*found = 1;
474
475
ret = xmlStrchr(expr, '{');
476
if (ret != NULL) {
477
xmlFree(expr);
478
return(NULL);
479
}
480
ret = xmlDictLookup(style->dict, expr, -1);
481
xmlFree(expr);
482
return(ret);
483
}
484
485
/**
486
* xsltAttrTemplateProcess:
487
* @ctxt: the XSLT transformation context
488
* @target: the element where the attribute will be grafted
489
* @attr: the attribute node of a literal result element
490
*
491
* Process one attribute of a Literal Result Element (in the stylesheet).
492
* Evaluates Attribute Value Templates and copies the attribute over to
493
* the result element.
494
* This does *not* process attribute sets (xsl:use-attribute-set).
495
*
496
*
497
* Returns the generated attribute node.
498
*/
499
xmlAttrPtr
500
xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
501
xmlAttrPtr attr)
502
{
503
const xmlChar *value;
504
xmlAttrPtr ret;
505
506
if ((ctxt == NULL) || (attr == NULL) || (target == NULL) ||
507
(target->type != XML_ELEMENT_NODE))
508
return(NULL);
509
510
if (attr->type != XML_ATTRIBUTE_NODE)
511
return(NULL);
512
513
/*
514
* Skip all XSLT attributes.
515
*/
516
#ifdef XSLT_REFACTORED
517
if (attr->psvi == xsltXSLTAttrMarker)
518
return(NULL);
519
#else
520
if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
521
return(NULL);
522
#endif
523
/*
524
* Get the value.
525
*/
526
if (attr->children != NULL) {
527
if ((attr->children->type != XML_TEXT_NODE) ||
528
(attr->children->next != NULL))
529
{
530
xsltTransformError(ctxt, NULL, attr->parent,
531
"Internal error: The children of an attribute node of a "
532
"literal result element are not in the expected form.\n");
533
return(NULL);
534
}
535
value = attr->children->content;
536
if (value == NULL)
537
value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
538
} else
539
value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
540
/*
541
* Overwrite duplicates.
542
*/
543
ret = target->properties;
544
while (ret != NULL) {
545
if (((attr->ns != NULL) == (ret->ns != NULL)) &&
546
xmlStrEqual(ret->name, attr->name) &&
547
((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href)))
548
{
549
break;
550
}
551
ret = ret->next;
552
}
553
if (ret != NULL) {
554
/* free the existing value */
555
xmlFreeNodeList(ret->children);
556
ret->children = ret->last = NULL;
557
/*
558
* Adjust ns-prefix if needed.
559
*/
560
if ((ret->ns != NULL) &&
561
(! xmlStrEqual(ret->ns->prefix, attr->ns->prefix)))
562
{
563
ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);
564
}
565
} else {
566
/* create a new attribute */
567
if (attr->ns != NULL)
568
ret = xmlNewNsProp(target,
569
xsltGetNamespace(ctxt, attr->parent, attr->ns, target),
570
attr->name, NULL);
571
else
572
ret = xmlNewNsProp(target, NULL, attr->name, NULL);
573
}
574
/*
575
* Set the value.
576
*/
577
if (ret != NULL) {
578
xmlNodePtr text;
579
580
text = xmlNewText(NULL);
581
if (text != NULL) {
582
ret->last = ret->children = text;
583
text->parent = (xmlNodePtr) ret;
584
text->doc = ret->doc;
585
586
if (attr->psvi != NULL) {
587
/*
588
* Evaluate the Attribute Value Template.
589
*/
590
xmlChar *val;
591
val = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
592
if (val == NULL) {
593
/*
594
* TODO: Damn, we need an easy mechanism to report
595
* qualified names!
596
*/
597
if (attr->ns) {
598
xsltTransformError(ctxt, NULL, attr->parent,
599
"Internal error: Failed to evaluate the AVT "
600
"of attribute '{%s}%s'.\n",
601
attr->ns->href, attr->name);
602
} else {
603
xsltTransformError(ctxt, NULL, attr->parent,
604
"Internal error: Failed to evaluate the AVT "
605
"of attribute '%s'.\n",
606
attr->name);
607
}
608
text->content = xmlStrdup(BAD_CAST "");
609
} else {
610
text->content = val;
611
}
612
} else if ((ctxt->internalized) && (target != NULL) &&
613
(target->doc != NULL) &&
614
(target->doc->dict == ctxt->dict) &&
615
xmlDictOwns(ctxt->dict, value)) {
616
text->content = (xmlChar *) value;
617
} else {
618
text->content = xmlStrdup(value);
619
}
620
}
621
} else {
622
if (attr->ns) {
623
xsltTransformError(ctxt, NULL, attr->parent,
624
"Internal error: Failed to create attribute '{%s}%s'.\n",
625
attr->ns->href, attr->name);
626
} else {
627
xsltTransformError(ctxt, NULL, attr->parent,
628
"Internal error: Failed to create attribute '%s'.\n",
629
attr->name);
630
}
631
}
632
return(ret);
633
}
634
635
636
/**
637
* xsltAttrListTemplateProcess:
638
* @ctxt: the XSLT transformation context
639
* @target: the element where the attributes will be grafted
640
* @attrs: the first attribute
641
*
642
* Processes all attributes of a Literal Result Element.
643
* Attribute references are applied via xsl:use-attribute-set
644
* attributes.
645
* Copies all non XSLT-attributes over to the @target element
646
* and evaluates Attribute Value Templates.
647
*
648
* Called by xsltApplySequenceConstructor() (transform.c).
649
*
650
* Returns a new list of attribute nodes, or NULL in case of error.
651
* (Don't assign the result to @target->properties; if
652
* the result is NULL, you'll get memory leaks, since the
653
* attributes will be disattached.)
654
*/
655
xmlAttrPtr
656
xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt,
657
xmlNodePtr target, xmlAttrPtr attrs)
658
{
659
xmlAttrPtr attr, copy, last = NULL;
660
xmlNodePtr oldInsert, text;
661
xmlNsPtr origNs = NULL, copyNs = NULL;
662
const xmlChar *value;
663
xmlChar *valueAVT;
664
int hasAttr = 0;
665
666
if ((ctxt == NULL) || (target == NULL) || (attrs == NULL) ||
667
(target->type != XML_ELEMENT_NODE))
668
return(NULL);
669
670
oldInsert = ctxt->insert;
671
ctxt->insert = target;
672
673
/*
674
* Apply attribute-sets.
675
*/
676
attr = attrs;
677
do {
678
#ifdef XSLT_REFACTORED
679
if ((attr->psvi == xsltXSLTAttrMarker) &&
680
xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets"))
681
{
682
xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
683
}
684
#else
685
if ((attr->ns != NULL) &&
686
xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets") &&
687
xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
688
{
689
xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
690
}
691
#endif
692
attr = attr->next;
693
} while (attr != NULL);
694
695
if (target->properties != NULL) {
696
hasAttr = 1;
697
}
698
699
/*
700
* Instantiate LRE-attributes.
701
*/
702
attr = attrs;
703
do {
704
/*
705
* Skip XSLT attributes.
706
*/
707
#ifdef XSLT_REFACTORED
708
if (attr->psvi == xsltXSLTAttrMarker) {
709
goto next_attribute;
710
}
711
#else
712
if ((attr->ns != NULL) &&
713
xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
714
{
715
goto next_attribute;
716
}
717
#endif
718
/*
719
* Get the value.
720
*/
721
if (attr->children != NULL) {
722
if ((attr->children->type != XML_TEXT_NODE) ||
723
(attr->children->next != NULL))
724
{
725
xsltTransformError(ctxt, NULL, attr->parent,
726
"Internal error: The children of an attribute node of a "
727
"literal result element are not in the expected form.\n");
728
goto error;
729
}
730
value = attr->children->content;
731
if (value == NULL)
732
value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
733
} else
734
value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
735
736
/*
737
* Get the namespace. Avoid lookups of same namespaces.
738
*/
739
if (attr->ns != origNs) {
740
origNs = attr->ns;
741
if (attr->ns != NULL) {
742
#ifdef XSLT_REFACTORED
743
copyNs = xsltGetSpecialNamespace(ctxt, attr->parent,
744
attr->ns->href, attr->ns->prefix, target);
745
#else
746
copyNs = xsltGetNamespace(ctxt, attr->parent,
747
attr->ns, target);
748
#endif
749
if (copyNs == NULL)
750
goto error;
751
} else
752
copyNs = NULL;
753
}
754
/*
755
* Create a new attribute.
756
*/
757
if (hasAttr) {
758
copy = xmlSetNsProp(target, copyNs, attr->name, NULL);
759
} else {
760
/*
761
* Avoid checking for duplicate attributes if there aren't
762
* any attribute sets.
763
*/
764
copy = xmlNewDocProp(target->doc, attr->name, NULL);
765
766
if (copy != NULL) {
767
copy->ns = copyNs;
768
769
/*
770
* Attach it to the target element.
771
*/
772
copy->parent = target;
773
if (last == NULL) {
774
target->properties = copy;
775
last = copy;
776
} else {
777
last->next = copy;
778
copy->prev = last;
779
last = copy;
780
}
781
}
782
}
783
if (copy == NULL) {
784
if (attr->ns) {
785
xsltTransformError(ctxt, NULL, attr->parent,
786
"Internal error: Failed to create attribute '{%s}%s'.\n",
787
attr->ns->href, attr->name);
788
} else {
789
xsltTransformError(ctxt, NULL, attr->parent,
790
"Internal error: Failed to create attribute '%s'.\n",
791
attr->name);
792
}
793
goto error;
794
}
795
796
/*
797
* Set the value.
798
*/
799
text = xmlNewText(NULL);
800
if (text != NULL) {
801
copy->last = copy->children = text;
802
text->parent = (xmlNodePtr) copy;
803
text->doc = copy->doc;
804
805
if (attr->psvi != NULL) {
806
/*
807
* Evaluate the Attribute Value Template.
808
*/
809
valueAVT = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
810
if (valueAVT == NULL) {
811
/*
812
* TODO: Damn, we need an easy mechanism to report
813
* qualified names!
814
*/
815
if (attr->ns) {
816
xsltTransformError(ctxt, NULL, attr->parent,
817
"Internal error: Failed to evaluate the AVT "
818
"of attribute '{%s}%s'.\n",
819
attr->ns->href, attr->name);
820
} else {
821
xsltTransformError(ctxt, NULL, attr->parent,
822
"Internal error: Failed to evaluate the AVT "
823
"of attribute '%s'.\n",
824
attr->name);
825
}
826
text->content = xmlStrdup(BAD_CAST "");
827
goto error;
828
} else {
829
text->content = valueAVT;
830
}
831
} else if ((ctxt->internalized) &&
832
(target->doc != NULL) &&
833
(target->doc->dict == ctxt->dict) &&
834
xmlDictOwns(ctxt->dict, value))
835
{
836
text->content = (xmlChar *) value;
837
} else {
838
text->content = xmlStrdup(value);
839
}
840
if ((copy != NULL) && (text != NULL) &&
841
(xmlIsID(copy->doc, copy->parent, copy)))
842
xmlAddID(NULL, copy->doc, text->content, copy);
843
}
844
845
next_attribute:
846
attr = attr->next;
847
} while (attr != NULL);
848
849
ctxt->insert = oldInsert;
850
return(target->properties);
851
852
error:
853
ctxt->insert = oldInsert;
854
return(NULL);
855
}
856
857
858
/**
859
* xsltTemplateProcess:
860
* @ctxt: the XSLT transformation context
861
* @node: the attribute template node
862
*
863
* Obsolete. Don't use it.
864
*
865
* Returns NULL.
866
*/
867
xmlNodePtr *
868
xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {
869
if (node == NULL)
870
return(NULL);
871
872
return(0);
873
}
874
875