2 * attrvt.c: Implementation of the XSL Transformation 1.0 engine
3 * attribute value template handling part.
6 * http://www.w3.org/TR/1999/REC-xslt-19991116
8 * Michael Kay "XSLT Programmer's Reference" pp 637-643
9 * Writing Multiple Output Files
11 * See Copyright for the status of this software.
18 #ifdef WITH_XSLT_DEBUG
19 #define WITH_XSLT_DEBUG_AVT
22 #define MAX_AVT_SEG 10
24 typedef struct _xsltAttrVT xsltAttrVT
;
25 typedef xsltAttrVT
*xsltAttrVTPtr
;
27 struct _xsltAttrVT
*next
; /* next xsltAttrVT */
28 int nb_seg
; /* Number of segments */
29 int max_seg
; /* max capacity before re-alloc needed */
30 int strstart
; /* is the start a string */
32 * the namespaces in scope
37 * the content is an alternate of string and xmlXPathCompExprPtr
39 void *segments
[MAX_AVT_SEG
];
44 * @style: a XSLT process context
46 * Build a new xsltAttrVT structure
48 * Returns the structure or NULL in case of error
51 xsltNewAttrVT(xsltStylesheetPtr style
) {
54 cur
= (xsltAttrVTPtr
) xmlMalloc(sizeof(xsltAttrVT
));
56 xsltTransformError(NULL
, style
, NULL
,
57 "xsltNewAttrVTPtr : malloc failed\n");
58 if (style
!= NULL
) style
->errors
++;
61 memset(cur
, 0, sizeof(xsltAttrVT
));
64 cur
->max_seg
= MAX_AVT_SEG
;
66 cur
->next
= style
->attVTs
;
68 * Note: this pointer may be changed by a re-alloc within xsltCompileAttr,
69 * so that code may change the stylesheet pointer also!
71 style
->attVTs
= (xsltAttrVTPtr
) cur
;
78 * @avt: pointer to an xsltAttrVT structure
80 * Free up the memory associated to the attribute value template
83 xsltFreeAttrVT(xsltAttrVTPtr avt
) {
86 if (avt
== NULL
) return;
88 if (avt
->strstart
== 1) {
89 for (i
= 0;i
< avt
->nb_seg
; i
+= 2)
90 if (avt
->segments
[i
] != NULL
)
91 xmlFree((xmlChar
*) avt
->segments
[i
]);
92 for (i
= 1;i
< avt
->nb_seg
; i
+= 2)
93 xmlXPathFreeCompExpr((xmlXPathCompExprPtr
) avt
->segments
[i
]);
95 for (i
= 0;i
< avt
->nb_seg
; i
+= 2)
96 xmlXPathFreeCompExpr((xmlXPathCompExprPtr
) avt
->segments
[i
]);
97 for (i
= 1;i
< avt
->nb_seg
; i
+= 2)
98 if (avt
->segments
[i
] != NULL
)
99 xmlFree((xmlChar
*) avt
->segments
[i
]);
101 if (avt
->nsList
!= NULL
)
102 xmlFree(avt
->nsList
);
108 * @avt: pointer to an list of AVT structures
110 * Free up the memory associated to the attribute value templates
113 xsltFreeAVTList(void *avt
) {
114 xsltAttrVTPtr cur
= (xsltAttrVTPtr
) avt
, next
;
116 while (cur
!= NULL
) {
123 * xsltSetAttrVTsegment:
124 * @ avt: pointer to an xsltAttrVT structure
125 * @ val: the value to be set to the next available segment
127 * Within xsltCompileAttr there are several places where a value
128 * needs to be added to the 'segments' array within the xsltAttrVT
129 * structure, and at each place the allocated size may have to be
130 * re-allocated. This routine takes care of that situation.
132 * Returns the avt pointer, which may have been changed by a re-alloc
135 xsltSetAttrVTsegment(xsltAttrVTPtr avt
, void *val
) {
136 if (avt
->nb_seg
>= avt
->max_seg
) {
137 avt
= (xsltAttrVTPtr
) xmlRealloc(avt
, sizeof(xsltAttrVT
) +
138 avt
->max_seg
* sizeof(void *));
142 memset(&avt
->segments
[avt
->nb_seg
], 0, MAX_AVT_SEG
*sizeof(void *));
143 avt
->max_seg
+= MAX_AVT_SEG
;
145 avt
->segments
[avt
->nb_seg
++] = val
;
151 * @style: a XSLT process context
152 * @attr: the attribute coming from the stylesheet.
154 * Precompile an attribute in a stylesheet, basically it checks if it is
155 * an attrubute value template, and if yes establish some structures needed
156 * to process it at transformation time.
159 xsltCompileAttr(xsltStylesheetPtr style
, xmlAttrPtr attr
) {
163 xmlChar
*expr
= NULL
;
165 int i
= 0, lastavt
= 0;
167 if ((style
== NULL
) || (attr
== NULL
) || (attr
->children
== NULL
))
169 if ((attr
->children
->type
!= XML_TEXT_NODE
) ||
170 (attr
->children
->next
!= NULL
)) {
171 xsltTransformError(NULL
, style
, attr
->parent
,
172 "Attribute '%s': The content is expected to be a single text "
173 "node when compiling an AVT.\n", attr
->name
);
177 str
= attr
->children
->content
;
178 if ((xmlStrchr(str
, '{') == NULL
) &&
179 (xmlStrchr(str
, '}') == NULL
)) return;
181 #ifdef WITH_XSLT_DEBUG_AVT
182 xsltGenericDebug(xsltGenericDebugContext
,
183 "Found AVT %s: %s\n", attr
->name
, str
);
185 if (attr
->psvi
!= NULL
) {
186 #ifdef WITH_XSLT_DEBUG_AVT
187 xsltGenericDebug(xsltGenericDebugContext
,
188 "AVT %s: already compiled\n", attr
->name
);
193 * Create a new AVT object.
195 avt
= xsltNewAttrVT(style
);
200 avt
->nsList
= xmlGetNsList(attr
->doc
, attr
->parent
);
201 if (avt
->nsList
!= NULL
) {
202 while (avt
->nsList
[i
] != NULL
)
210 if (*(cur
+1) == '{') { /* escaped '{' */
212 ret
= xmlStrncat(ret
, str
, cur
- str
);
217 if (*(cur
+1) == '}') { /* skip empty AVT */
218 ret
= xmlStrncat(ret
, str
, cur
- str
);
223 if ((ret
!= NULL
) || (cur
- str
> 0)) {
224 ret
= xmlStrncat(ret
, str
, cur
- str
);
226 if (avt
->nb_seg
== 0)
228 if ((avt
= xsltSetAttrVTsegment(avt
, (void *) ret
)) == NULL
)
235 while ((*cur
!= 0) && (*cur
!= '}')) {
236 /* Need to check for literal (bug539741) */
237 if ((*cur
== '\'') || (*cur
== '"')) {
238 char delim
= *(cur
++);
239 while ((*cur
!= 0) && (*cur
!= delim
))
242 cur
++; /* skip the ending delimiter */
247 xsltTransformError(NULL
, style
, attr
->parent
,
248 "Attribute '%s': The AVT has an unmatched '{'.\n",
254 expr
= xmlStrndup(str
, cur
- str
);
257 * TODO: What needs to be done here?
262 xmlXPathCompExprPtr comp
;
264 comp
= xsltXPathCompile(style
, expr
);
266 xsltTransformError(NULL
, style
, attr
->parent
,
267 "Attribute '%s': Failed to compile the expression "
268 "'%s' in the AVT.\n", attr
->name
, expr
);
272 if (avt
->nb_seg
== 0)
275 if ((avt
= xsltSetAttrVTsegment(avt
, NULL
)) == NULL
)
278 if ((avt
= xsltSetAttrVTsegment(avt
, (void *) comp
)) == NULL
)
286 } else if (*cur
== '}') {
288 if (*cur
== '}') { /* escaped '}' */
289 ret
= xmlStrncat(ret
, str
, cur
- str
);
294 xsltTransformError(NULL
, style
, attr
->parent
,
295 "Attribute '%s': The AVT has an unmatched '}'.\n",
302 if ((ret
!= NULL
) || (cur
- str
> 0)) {
303 ret
= xmlStrncat(ret
, str
, cur
- str
);
305 if (avt
->nb_seg
== 0)
307 if ((avt
= xsltSetAttrVTsegment(avt
, (void *) ret
)) == NULL
)
314 xsltTransformError(NULL
, style
, attr
->parent
,
315 "xsltCompileAttr: malloc problem\n");
317 if (attr
->psvi
!= avt
) { /* may have changed from realloc */
320 * This is a "hack", but I can't see any clean method of
321 * doing it. If a re-alloc has taken place, then the pointer
322 * for this AVT may have changed. style->attVTs was set by
323 * xsltNewAttrVT, so it needs to be re-set to the new value!
337 * @ctxt: the XSLT transformation context
338 * @avt: the prevompiled attribute value template info
339 * @node: the node hosting the attribute
341 * Process the given AVT, and return the new string value.
343 * Returns the computed string value or NULL, must be deallocated by the
347 xsltEvalAVT(xsltTransformContextPtr ctxt
, void *avt
, xmlNodePtr node
) {
348 xmlChar
*ret
= NULL
, *tmp
;
349 xmlXPathCompExprPtr comp
;
350 xsltAttrVTPtr cur
= (xsltAttrVTPtr
) avt
;
354 if ((ctxt
== NULL
) || (avt
== NULL
) || (node
== NULL
))
357 for (i
= 0;i
< cur
->nb_seg
;i
++) {
359 ret
= xmlStrcat(ret
, (const xmlChar
*) cur
->segments
[i
]);
361 comp
= (xmlXPathCompExprPtr
) cur
->segments
[i
];
362 tmp
= xsltEvalXPathStringNs(ctxt
, comp
, cur
->nsNr
, cur
->nsList
);
365 ret
= xmlStrcat(ret
, tmp
);