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