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