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