2 * attributes.c: Implementation of the XSLT attributes handling
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
9 * Daniel.Veillard@imag.fr
12 #include "xsltconfig.h"
16 #ifdef HAVE_SYS_TYPES_H
17 #include <sys/types.h>
35 #include <libxml/xmlmemory.h>
36 #include <libxml/tree.h>
37 #include <libxml/hash.h>
38 #include <libxml/xmlerror.h>
39 #include <libxml/uri.h>
41 #include "xsltInternals.h"
42 #include "xsltutils.h"
43 #include "attributes.h"
44 #include "namespaces.h"
45 #include "templates.h"
51 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
54 #define IS_BLANK_NODE(n) \
55 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
59 * The in-memory structure corresponding to an XSLT Attribute in
63 typedef struct _xsltAttrElem xsltAttrElem;
64 typedef xsltAttrElem *xsltAttrElemPtr;
65 struct _xsltAttrElem {
66 struct _xsltAttrElem *next;/* chained list */
67 xmlNodePtr attr; /* the xsl:attribute definition */
70 /************************************************************************
72 * XSLT Attribute handling *
74 ************************************************************************/
78 * @attr: the new xsl:attribute node
80 * Create a new XSLT AttrElem
82 * Returns the newly allocated xsltAttrElemPtr or NULL in case of error
85 xsltNewAttrElem(xmlNodePtr attr) {
88 cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem));
90 xsltGenericError(xsltGenericErrorContext,
91 "xsltNewAttrElem : malloc failed\n");
94 memset(cur, 0, sizeof(xsltAttrElem));
101 * @attr: an XSLT AttrElem
103 * Free up the memory allocated by @attr
106 xsltFreeAttrElem(xsltAttrElemPtr attr) {
107 memset(attr, -1, sizeof(xsltAttrElem));
112 * xsltFreeAttrElemList:
113 * @list: an XSLT AttrElem list
115 * Free up the memory allocated by @list
118 xsltFreeAttrElemList(xsltAttrElemPtr list) {
119 xsltAttrElemPtr next;
121 while (list != NULL) {
123 xsltFreeAttrElem(list);
129 * xsltAddAttrElemList:
130 * @list: an XSLT AttrElem list
131 * @attr: the new xsl:attribute node
133 * Add the new attribute to the list.
135 * Returns the new list pointer
138 xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
139 xsltAttrElemPtr next;
143 while (list != NULL) {
145 if (list->attr == attr)
148 list->next = xsltNewAttrElem(attr);
153 return(xsltNewAttrElem(attr));
155 /************************************************************************
157 * Module interfaces *
159 ************************************************************************/
162 * xsltParseStylesheetAttributeSet:
163 * @style: the XSLT stylesheet
164 * @template: the "preserve-space" element
166 * parse an XSLT stylesheet preserve-space element and record
167 * elements needing preserving
171 xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
172 xmlChar *prop = NULL;
173 xmlChar *ncname = NULL;
174 xmlChar *prefix = NULL;
176 xmlChar *attribute, *end;
177 xmlNodePtr list, delete;
178 xsltAttrElemPtr values;
180 if ((cur == NULL) || (style == NULL))
183 prop = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
185 xsltGenericError(xsltGenericErrorContext,
186 "xslt:attribute-set : name is missing\n");
190 ncname = xmlSplitQName2(prop, &prefix);
191 if (ncname == NULL) {
197 if (style->attributeSets == NULL)
198 style->attributeSets = xmlHashCreate(10);
199 if (style->attributeSets == NULL)
202 values = xmlHashLookup2(style->attributeSets, ncname, prefix);
205 * check the children list
207 list = cur->children;
209 while (list != NULL) {
210 if (IS_XSLT_ELEM(cur)) {
211 if (!IS_XSLT_NAME(cur, "attribute")) {
212 xsltGenericError(xsltGenericErrorContext,
213 "xslt:attribute-set : unexpected child xsl:%s\n",
218 xsltGenericDebug(xsltGenericDebugContext,
219 "add attribute to list %s\n", ncname);
221 values = xsltAddAttrElemList(values, cur);
224 xsltGenericError(xsltGenericErrorContext,
225 "xslt:attribute-set : unexpected child %s\n", cur->name);
232 * Check a possible use-attribute-sets definition
234 /* TODO check recursion */
236 attributes = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets",
238 if (attributes == NULL) {
242 attribute = attributes;
243 while (*attribute != 0) {
244 while (IS_BLANK(*attribute)) attribute++;
248 while ((*end != 0) && (!IS_BLANK(*end))) end++;
249 attribute = xmlStrndup(attribute, end - attribute);
252 xsltGenericDebug(xsltGenericDebugContext,
253 "xslt:attribute-set : %s adds use %s\n", ncname);
255 TODO /* add use-attribute-sets support to atribute-set */
265 xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, values, NULL);
267 xsltGenericDebug(xsltGenericDebugContext,
268 "updated attribute list %s\n", ncname);
282 * @ctxt: a XSLT process context
283 * @node: the node in the source tree.
284 * @inst: the xslt attribute node
286 * Process the xslt attribute node on the source node
289 xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
291 xmlChar *prop = NULL;
292 xmlChar *ncname = NULL;
293 xmlChar *prefix = NULL;
294 xmlChar *value = NULL;
299 if (ctxt->insert == NULL)
301 if (ctxt->insert->children != NULL) {
302 xsltGenericError(xsltGenericErrorContext,
303 "xslt:attribute : node has already children\n");
306 prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name");
308 xsltGenericError(xsltGenericErrorContext,
309 "xslt:attribute : name is missing\n");
313 ncname = xmlSplitQName2(prop, &prefix);
314 if (ncname == NULL) {
319 if (xmlStrEqual(ncname, (const xmlChar *) "xmlns")) {
320 xsltGenericError(xsltGenericErrorContext,
321 "xslt:attribute : xmlns forbidden\n");
324 prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace");
326 TODO /* xsl:attribute namespace */
330 if (prefix != NULL) {
331 ns = xmlSearchNs(inst->doc, inst, prefix);
333 xsltGenericError(xsltGenericErrorContext,
334 "no namespace bound to prefix %s\n", prefix);
336 ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert);
342 value = xsltEvalTemplateString(ctxt, node, inst);
345 attr = xmlSetNsProp(ctxt->insert, ns, ncname,
346 (const xmlChar *)"");
348 attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
351 attr = xmlSetNsProp(ctxt->insert, ns, ncname, value);
353 attr = xmlSetProp(ctxt->insert, ncname, value);
369 * xsltApplyAttributeSet:
370 * @ctxt: the XSLT stylesheet
371 * @node: the node in the source tree.
372 * @inst: the xslt attribute node
373 * @attributes: the set list.
375 * Apply the xsl:use-attribute-sets
379 xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
380 xmlNodePtr inst, xmlChar *attributes) {
381 xmlChar *ncname = NULL;
382 xmlChar *prefix = NULL;
383 xmlChar *attribute, *end;
384 xsltAttrElemPtr values;
386 if (attributes == NULL) {
390 attribute = attributes;
391 while (*attribute != 0) {
392 while (IS_BLANK(*attribute)) attribute++;
396 while ((*end != 0) && (!IS_BLANK(*end))) end++;
397 attribute = xmlStrndup(attribute, end - attribute);
400 xsltGenericDebug(xsltGenericDebugContext,
401 "apply attribute set %s\n", attribute);
403 ncname = xmlSplitQName2(attribute, &prefix);
404 if (ncname == NULL) {
410 /* TODO: apply cascade */
411 values = xmlHashLookup2(ctxt->style->attributeSets, ncname, prefix);
412 while (values != NULL) {
413 xsltAttribute(ctxt, node, values->attr);
414 values = values->next;
416 if (attribute != NULL)
428 * xsltFreeAttributeSetsHashes:
429 * @style: an XSLT stylesheet
431 * Free up the memory used by attribute sets
434 xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {
435 if (style->attributeSets != NULL)
436 xmlHashFree((xmlHashTablePtr) style->attributeSets,
437 (xmlHashDeallocator) xsltFreeAttrElemList);
438 style->attributeSets = NULL;