Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenattrvt.c
Go to the documentation of this file.
00001 /* 00002 * attrvt.c: Implementation of the XSL Transformation 1.0 engine 00003 * attribute value template handling part. 00004 * 00005 * References: 00006 * http://www.w3.org/TR/1999/REC-xslt-19991116 00007 * 00008 * Michael Kay "XSLT Programmer's Reference" pp 637-643 00009 * Writing Multiple Output Files 00010 * 00011 * See Copyright for the status of this software. 00012 * 00013 * daniel@veillard.com 00014 */ 00015 00016 #define IN_LIBXSLT 00017 #include "libxslt.h" 00018 00019 #include <string.h> 00020 00021 #include <libxml/xmlmemory.h> 00022 #include <libxml/tree.h> 00023 #include <libxml/xpath.h> 00024 #include <libxml/xpathInternals.h> 00025 #include "xslt.h" 00026 #include "xsltutils.h" 00027 #include "xsltInternals.h" 00028 #include "templates.h" 00029 00030 #ifdef WITH_XSLT_DEBUG 00031 #define WITH_XSLT_DEBUG_AVT 00032 #endif 00033 00034 #define MAX_AVT_SEG 10 00035 00036 typedef struct _xsltAttrVT xsltAttrVT; 00037 typedef xsltAttrVT *xsltAttrVTPtr; 00038 struct _xsltAttrVT { 00039 struct _xsltAttrVT *next; /* next xsltAttrVT */ 00040 int nb_seg; /* Number of segments */ 00041 int max_seg; /* max capacity before re-alloc needed */ 00042 int strstart; /* is the start a string */ 00043 /* 00044 * the namespaces in scope 00045 */ 00046 xmlNsPtr *nsList; 00047 int nsNr; 00048 /* 00049 * the content is an alternate of string and xmlXPathCompExprPtr 00050 */ 00051 void *segments[MAX_AVT_SEG]; 00052 }; 00053 00062 static xsltAttrVTPtr 00063 xsltNewAttrVT(xsltStylesheetPtr style) { 00064 xsltAttrVTPtr cur; 00065 00066 cur = (xsltAttrVTPtr) xmlMalloc(sizeof(xsltAttrVT)); 00067 if (cur == NULL) { 00068 xsltTransformError(NULL, style, NULL, 00069 "xsltNewAttrVTPtr : malloc failed\n"); 00070 if (style != NULL) style->errors++; 00071 return(NULL); 00072 } 00073 memset(cur, 0, sizeof(xsltAttrVT)); 00074 00075 cur->nb_seg = 0; 00076 cur->max_seg = MAX_AVT_SEG; 00077 cur->strstart = 0; 00078 cur->next = style->attVTs; 00079 /* 00080 * Note: this pointer may be changed by a re-alloc within xsltCompileAttr, 00081 * so that code may change the stylesheet pointer also! 00082 */ 00083 style->attVTs = (xsltAttrVTPtr) cur; 00084 00085 return(cur); 00086 } 00087 00094 static void 00095 xsltFreeAttrVT(xsltAttrVTPtr avt) { 00096 int i; 00097 00098 if (avt == NULL) return; 00099 00100 if (avt->strstart == 1) { 00101 for (i = 0;i < avt->nb_seg; i += 2) 00102 if (avt->segments[i] != NULL) 00103 xmlFree((xmlChar *) avt->segments[i]); 00104 for (i = 1;i < avt->nb_seg; i += 2) 00105 xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]); 00106 } else { 00107 for (i = 0;i < avt->nb_seg; i += 2) 00108 xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]); 00109 for (i = 1;i < avt->nb_seg; i += 2) 00110 if (avt->segments[i] != NULL) 00111 xmlFree((xmlChar *) avt->segments[i]); 00112 } 00113 if (avt->nsList != NULL) 00114 xmlFree(avt->nsList); 00115 xmlFree(avt); 00116 } 00117 00124 void 00125 xsltFreeAVTList(void *avt) { 00126 xsltAttrVTPtr cur = (xsltAttrVTPtr) avt, next; 00127 00128 while (cur != NULL) { 00129 next = cur->next; 00130 xsltFreeAttrVT(cur); 00131 cur = next; 00132 } 00133 } 00146 static xsltAttrVTPtr 00147 xsltSetAttrVTsegment(xsltAttrVTPtr avt, void *val) { 00148 if (avt->nb_seg >= avt->max_seg) { 00149 avt = (xsltAttrVTPtr) xmlRealloc(avt, sizeof(xsltAttrVT) + 00150 avt->max_seg * sizeof(void *)); 00151 if (avt == NULL) { 00152 return NULL; 00153 } 00154 memset(&avt->segments[avt->nb_seg], 0, MAX_AVT_SEG*sizeof(void *)); 00155 avt->max_seg += MAX_AVT_SEG; 00156 } 00157 avt->segments[avt->nb_seg++] = val; 00158 return avt; 00159 } 00160 00170 void 00171 xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) { 00172 const xmlChar *str; 00173 const xmlChar *cur; 00174 xmlChar *ret = NULL; 00175 xmlChar *expr = NULL; 00176 xsltAttrVTPtr avt; 00177 int i = 0, lastavt = 0; 00178 00179 if ((style == NULL) || (attr == NULL) || (attr->children == NULL)) 00180 return; 00181 if ((attr->children->type != XML_TEXT_NODE) || 00182 (attr->children->next != NULL)) { 00183 xsltTransformError(NULL, style, attr->parent, 00184 "Attribute '%s': The content is expected to be a single text " 00185 "node when compiling an AVT.\n", attr->name); 00186 style->errors++; 00187 return; 00188 } 00189 str = attr->children->content; 00190 if ((xmlStrchr(str, '{') == NULL) && 00191 (xmlStrchr(str, '}') == NULL)) return; 00192 00193 #ifdef WITH_XSLT_DEBUG_AVT 00194 xsltGenericDebug(xsltGenericDebugContext, 00195 "Found AVT %s: %s\n", attr->name, str); 00196 #endif 00197 if (attr->psvi != NULL) { 00198 #ifdef WITH_XSLT_DEBUG_AVT 00199 xsltGenericDebug(xsltGenericDebugContext, 00200 "AVT %s: already compiled\n", attr->name); 00201 #endif 00202 return; 00203 } 00204 /* 00205 * Create a new AVT object. 00206 */ 00207 avt = xsltNewAttrVT(style); 00208 if (avt == NULL) 00209 return; 00210 attr->psvi = avt; 00211 00212 avt->nsList = xmlGetNsList(attr->doc, attr->parent); 00213 if (avt->nsList != NULL) { 00214 while (avt->nsList[i] != NULL) 00215 i++; 00216 } 00217 avt->nsNr = i; 00218 00219 cur = str; 00220 while (*cur != 0) { 00221 if (*cur == '{') { 00222 if (*(cur+1) == '{') { /* escaped '{' */ 00223 cur++; 00224 ret = xmlStrncat(ret, str, cur - str); 00225 cur++; 00226 str = cur; 00227 continue; 00228 } 00229 if (*(cur+1) == '}') { /* skip empty AVT */ 00230 ret = xmlStrncat(ret, str, cur - str); 00231 cur += 2; 00232 str = cur; 00233 continue; 00234 } 00235 if ((ret != NULL) || (cur - str > 0)) { 00236 ret = xmlStrncat(ret, str, cur - str); 00237 str = cur; 00238 if (avt->nb_seg == 0) 00239 avt->strstart = 1; 00240 if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL) 00241 goto error; 00242 ret = NULL; 00243 lastavt = 0; 00244 } 00245 00246 cur++; 00247 while ((*cur != 0) && (*cur != '}')) { 00248 /* Need to check for literal (bug539741) */ 00249 if ((*cur == '\'') || (*cur == '"')) { 00250 char delim = *(cur++); 00251 while ((*cur != 0) && (*cur != delim)) 00252 cur++; 00253 if (*cur != 0) 00254 cur++; /* skip the ending delimiter */ 00255 } else 00256 cur++; 00257 } 00258 if (*cur == 0) { 00259 xsltTransformError(NULL, style, attr->parent, 00260 "Attribute '%s': The AVT has an unmatched '{'.\n", 00261 attr->name); 00262 style->errors++; 00263 goto error; 00264 } 00265 str++; 00266 expr = xmlStrndup(str, cur - str); 00267 if (expr == NULL) { 00268 /* 00269 * TODO: What needs to be done here? 00270 */ 00271 XSLT_TODO 00272 goto error; 00273 } else { 00274 xmlXPathCompExprPtr comp; 00275 00276 comp = xsltXPathCompile(style, expr); 00277 if (comp == NULL) { 00278 xsltTransformError(NULL, style, attr->parent, 00279 "Attribute '%s': Failed to compile the expression " 00280 "'%s' in the AVT.\n", attr->name, expr); 00281 style->errors++; 00282 goto error; 00283 } 00284 if (avt->nb_seg == 0) 00285 avt->strstart = 0; 00286 if (lastavt == 1) { 00287 if ((avt = xsltSetAttrVTsegment(avt, NULL)) == NULL) 00288 goto error; 00289 } 00290 if ((avt = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL) 00291 goto error; 00292 lastavt = 1; 00293 xmlFree(expr); 00294 expr = NULL; 00295 } 00296 cur++; 00297 str = cur; 00298 } else if (*cur == '}') { 00299 cur++; 00300 if (*cur == '}') { /* escaped '}' */ 00301 ret = xmlStrncat(ret, str, cur - str); 00302 cur++; 00303 str = cur; 00304 continue; 00305 } else { 00306 xsltTransformError(NULL, style, attr->parent, 00307 "Attribute '%s': The AVT has an unmatched '}'.\n", 00308 attr->name); 00309 goto error; 00310 } 00311 } else 00312 cur++; 00313 } 00314 if ((ret != NULL) || (cur - str > 0)) { 00315 ret = xmlStrncat(ret, str, cur - str); 00316 str = cur; 00317 if (avt->nb_seg == 0) 00318 avt->strstart = 1; 00319 if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL) 00320 goto error; 00321 ret = NULL; 00322 } 00323 00324 error: 00325 if (avt == NULL) { 00326 xsltTransformError(NULL, style, attr->parent, 00327 "xsltCompileAttr: malloc problem\n"); 00328 } else { 00329 if (attr->psvi != avt) { /* may have changed from realloc */ 00330 attr->psvi = avt; 00331 /* 00332 * This is a "hack", but I can't see any clean method of 00333 * doing it. If a re-alloc has taken place, then the pointer 00334 * for this AVT may have changed. style->attVTs was set by 00335 * xsltNewAttrVT, so it needs to be re-set to the new value! 00336 */ 00337 style->attVTs = avt; 00338 } 00339 } 00340 if (ret != NULL) 00341 xmlFree(ret); 00342 if (expr != NULL) 00343 xmlFree(expr); 00344 } 00345 00346 00358 xmlChar * 00359 xsltEvalAVT(xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node) { 00360 xmlChar *ret = NULL, *tmp; 00361 xmlXPathCompExprPtr comp; 00362 xsltAttrVTPtr cur = (xsltAttrVTPtr) avt; 00363 int i; 00364 int str; 00365 00366 if ((ctxt == NULL) || (avt == NULL) || (node == NULL)) 00367 return(NULL); 00368 str = cur->strstart; 00369 for (i = 0;i < cur->nb_seg;i++) { 00370 if (str) { 00371 ret = xmlStrcat(ret, (const xmlChar *) cur->segments[i]); 00372 } else { 00373 comp = (xmlXPathCompExprPtr) cur->segments[i]; 00374 tmp = xsltEvalXPathStringNs(ctxt, comp, cur->nsNr, cur->nsList); 00375 if (tmp != NULL) { 00376 if (ret != NULL) { 00377 ret = xmlStrcat(ret, tmp); 00378 xmlFree(tmp); 00379 } else { 00380 ret = tmp; 00381 } 00382 } 00383 } 00384 str = !str; 00385 } 00386 return(ret); 00387 } Generated on Sun May 27 2012 04:19:35 for ReactOS by
1.7.6.1
|