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