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