2 * templates.c: Implementation of the template processing
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
16 #include <libxml/xmlmemory.h>
17 #include <libxml/globals.h>
18 #include <libxml/xmlerror.h>
19 #include <libxml/tree.h>
20 #include <libxml/xpathInternals.h>
21 #include <libxml/parserInternals.h>
23 #include "xsltInternals.h"
24 #include "xsltutils.h"
25 #include "variables.h"
26 #include "functions.h"
27 #include "templates.h"
28 #include "transform.h"
29 #include "namespaces.h"
30 #include "attributes.h"
32 #ifdef WITH_XSLT_DEBUG
33 #define WITH_XSLT_DEBUG_TEMPLATES
36 /************************************************************************
40 ************************************************************************/
43 * xsltEvalXPathPredicate:
44 * @ctxt: the XSLT transformation context
45 * @comp: the XPath compiled expression
46 * @nsList: the namespaces in scope
47 * @nsNr: the number of namespaces in scope
49 * Process the expression using XPath and evaluate the result as
52 * Returns 1 is the predicate was true, 0 otherwise
55 xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
56 xmlNsPtr *nsList, int nsNr) {
58 xmlXPathObjectPtr res;
60 xmlNsPtr *oldNamespaces;
62 int oldProximityPosition, oldContextSize;
64 oldContextSize = ctxt->xpathCtxt->contextSize;
65 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
66 oldNsNr = ctxt->xpathCtxt->nsNr;
67 oldNamespaces = ctxt->xpathCtxt->namespaces;
70 ctxt->xpathCtxt->node = ctxt->node;
71 ctxt->xpathCtxt->namespaces = nsList;
72 ctxt->xpathCtxt->nsNr = nsNr;
74 res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
77 ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res);
78 xmlXPathFreeObject(res);
79 #ifdef WITH_XSLT_DEBUG_TEMPLATES
80 xsltGenericDebug(xsltGenericDebugContext,
81 "xsltEvalXPathPredicate: returns %d\n", ret);
84 #ifdef WITH_XSLT_DEBUG_TEMPLATES
85 xsltGenericDebug(xsltGenericDebugContext,
86 "xsltEvalXPathPredicate: failed\n");
88 ctxt->state = XSLT_STATE_STOPPED;
91 ctxt->xpathCtxt->nsNr = oldNsNr;
93 ctxt->xpathCtxt->namespaces = oldNamespaces;
95 ctxt->xpathCtxt->contextSize = oldContextSize;
96 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
102 * xsltEvalXPathString:
103 * @ctxt: the XSLT transformation context
104 * @comp: the compiled XPath expression
106 * Process the expression using XPath and get a string
108 * Returns the computed string value or NULL, must be deallocated by the
112 xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
114 xmlXPathObjectPtr res;
119 xmlNsPtr *oldNamespaces;
121 oldInst = ctxt->inst;
122 oldNode = ctxt->node;
123 oldPos = ctxt->xpathCtxt->proximityPosition;
124 oldSize = ctxt->xpathCtxt->contextSize;
125 oldNsNr = ctxt->xpathCtxt->nsNr;
126 oldNamespaces = ctxt->xpathCtxt->namespaces;
128 ctxt->xpathCtxt->node = ctxt->node;
129 /* TODO: do we need to propagate the namespaces here ? */
130 ctxt->xpathCtxt->namespaces = NULL;
131 ctxt->xpathCtxt->nsNr = 0;
132 res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
134 if (res->type != XPATH_STRING)
135 res = xmlXPathConvertString(res);
136 if (res->type == XPATH_STRING) {
137 ret = res->stringval;
138 res->stringval = NULL;
140 xsltPrintErrorContext(ctxt, NULL, NULL);
141 xsltGenericError(xsltGenericErrorContext,
142 "xpath : string() function didn't return a String\n");
144 xmlXPathFreeObject(res);
146 ctxt->state = XSLT_STATE_STOPPED;
148 #ifdef WITH_XSLT_DEBUG_TEMPLATES
149 xsltGenericDebug(xsltGenericDebugContext,
150 "xsltEvalXPathString: returns %s\n", ret);
152 ctxt->inst = oldInst;
153 ctxt->node = oldNode;
154 ctxt->xpathCtxt->contextSize = oldSize;
155 ctxt->xpathCtxt->proximityPosition = oldPos;
156 ctxt->xpathCtxt->nsNr = oldNsNr;
157 ctxt->xpathCtxt->namespaces = oldNamespaces;
162 * xsltEvalTemplateString:
163 * @ctxt: the XSLT transformation context
164 * @node: the stylesheet node
165 * @parent: the content parent
167 * Evaluate a template string value, i.e. the parent list is interpreter
168 * as template content and the resulting tree string value is returned
169 * This is needed for example by xsl:comment and xsl:processing-instruction
171 * Returns the computed string value or NULL, must be deallocated by the
175 xsltEvalTemplateString(xsltTransformContextPtr ctxt, xmlNodePtr node,
177 xmlNodePtr oldInsert, insert = NULL;
180 if ((ctxt == NULL) || (node == NULL) || (parent == NULL))
183 if (parent->children == NULL)
186 insert = xmlNewDocNode(ctxt->output, NULL,
187 (const xmlChar *)"fake", NULL);
190 oldInsert = ctxt->insert;
191 ctxt->insert = insert;
193 xsltApplyOneTemplate(ctxt, node, parent->children, NULL, NULL);
195 ctxt->insert = oldInsert;
197 ret = xmlNodeGetContent(insert);
204 * xsltAttrTemplateValueProcess:
205 * @ctxt: the XSLT transformation context
206 * @str: the attribute template node value
208 * Process the given node and return the new string value.
210 * Returns the computed string value or NULL, must be deallocated by the
214 xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {
219 if (str == NULL) return(NULL);
221 return(xmlStrndup((xmlChar *)"", 0));
226 ret = xmlStrncat(ret, str, cur - str);
229 while ((*cur != 0) && (*cur != '}')) cur++;
231 ret = xmlStrncat(ret, str, cur - str);
235 expr = xmlStrndup(str, cur - str);
238 else if (*expr == '{') {
239 ret = xmlStrcat(ret, expr);
242 xmlXPathCompExprPtr comp;
244 * TODO: keep precompiled form around
246 comp = xmlXPathCompile(expr);
247 val = xsltEvalXPathString(ctxt, comp);
248 xmlXPathFreeCompExpr(comp);
251 ret = xmlStrcat(ret, val);
261 ret = xmlStrncat(ret, str, cur - str);
268 * xsltEvalAttrValueTemplate:
269 * @ctxt: the XSLT transformation context
270 * @node: the stylesheet node
271 * @name: the attribute QName
272 * @ns: the attribute namespace URI
274 * Evaluate a attribute value template, i.e. the attribute value can
275 * contain expressions contained in curly braces ({}) and those are
276 * substituted by they computed value.
278 * Returns the computed string value or NULL, must be deallocated by the
282 xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
283 const xmlChar *name, const xmlChar *ns) {
287 if ((ctxt == NULL) || (node == NULL) || (name == NULL))
290 expr = xsltGetNsProp(node, name, ns);
295 * TODO: though now {} is detected ahead, it would still be good to
296 * optimize both functions to keep the splitted value if the
297 * attribute content and the XPath precompiled expressions around
300 ret = xsltAttrTemplateValueProcess(ctxt, expr);
301 #ifdef WITH_XSLT_DEBUG_TEMPLATES
302 xsltGenericDebug(xsltGenericDebugContext,
303 "xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret);
311 * xsltEvalStaticAttrValueTemplate:
312 * @style: the XSLT stylesheet
313 * @node: the stylesheet node
314 * @name: the attribute Name
315 * @ns: the attribute namespace URI
316 * @found: indicator whether the attribute is present
318 * Check if an attribute value template has a static value, i.e. the
319 * attribute value does not contain expressions contained in curly braces ({})
321 * Returns the static string value or NULL, must be deallocated by the
325 xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr node,
326 const xmlChar *name, const xmlChar *ns, int *found) {
330 if ((style == NULL) || (node == NULL) || (name == NULL))
333 expr = xsltGetNsProp(node, name, ns);
340 ret = xmlStrchr(expr, '{');
349 * xsltAttrTemplateProcess:
350 * @ctxt: the XSLT transformation context
351 * @target: the result node
352 * @cur: the attribute template node
354 * Process the given attribute and return the new processed copy.
356 * Returns the attribute replacement.
359 xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
363 if ((ctxt == NULL) || (cur == NULL))
366 if (cur->type != XML_ATTRIBUTE_NODE)
369 if ((cur->ns != NULL) &&
370 (xmlStrEqual(cur->ns->href, XSLT_NAMESPACE))) {
371 if (xmlStrEqual(cur->name, (const xmlChar *)"use-attribute-sets")) {
374 in = xmlNodeListGetString(ctxt->document->doc, cur->children, 1);
376 xsltApplyAttributeSet(ctxt, ctxt->node, NULL, in);
383 ns = xsltGetNamespace(ctxt, cur->parent, cur->ns, target);
387 if (cur->children != NULL) {
388 xmlChar *in = xmlNodeListGetString(ctxt->document->doc,
392 /* TODO: optimize if no template value was detected */
394 out = xsltAttrTemplateValueProcess(ctxt, in);
395 ret = xmlSetNsProp(target, ns, cur->name, out);
400 ret = xmlSetNsProp(target, ns, cur->name, (const xmlChar *)"");
403 ret = xmlSetNsProp(target, ns, cur->name, (const xmlChar *)"");
409 * xsltAttrListTemplateProcess:
410 * @ctxt: the XSLT transformation context
411 * @target: the element where the attributes will be grafted
412 * @cur: the first attribute
414 * Do a copy of an attribute list with attribute template processing
416 * Returns: a new xmlAttrPtr, or NULL in case of error.
419 xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt,
420 xmlNodePtr target, xmlAttrPtr cur) {
421 xmlAttrPtr ret = NULL;
423 xmlNodePtr oldInsert;
425 oldInsert = ctxt->insert;
426 ctxt->insert = target;
427 while (cur != NULL) {
428 q = xsltAttrTemplateProcess(ctxt, target, cur);
431 q->doc = ctxt->output;
438 ctxt->insert = oldInsert;
444 * xsltTemplateProcess:
445 * @ctxt: the XSLT transformation context
446 * @node: the attribute template node
448 * Process the given node and return the new string value.
450 * Returns the computed tree replacement
453 xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {