1 /* 2 * imports.c: Implementation of the XSLT imports 3 * 4 * Reference: 5 * http://www.w3.org/TR/1999/REC-xslt-19991116 6 * 7 * See Copyright for the status of this software. 8 * 9 * daniel@veillard.com 10 */ 11 12 #include "precomp.h" 13 14 /************************************************************************ 15 * * 16 * Module interfaces * 17 * * 18 ************************************************************************/ 19 /** 20 * xsltFixImportedCompSteps: 21 * @master: the "master" stylesheet 22 * @style: the stylesheet being imported by the master 23 * 24 * normalize the comp steps for the stylesheet being imported 25 * by the master, together with any imports within that. 26 * 27 */ 28 static void xsltFixImportedCompSteps(xsltStylesheetPtr master, 29 xsltStylesheetPtr style) { 30 xsltStylesheetPtr res; 31 xmlHashScan(style->templatesHash, 32 (xmlHashScanner) xsltNormalizeCompSteps, master); 33 master->extrasNr += style->extrasNr; 34 for (res = style->imports; res != NULL; res = res->next) { 35 xsltFixImportedCompSteps(master, res); 36 } 37 } 38 39 /** 40 * xsltParseStylesheetImport: 41 * @style: the XSLT stylesheet 42 * @cur: the import element 43 * 44 * parse an XSLT stylesheet import element 45 * 46 * Returns 0 in case of success -1 in case of failure. 47 */ 48 49 int 50 xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) { 51 int ret = -1; 52 xmlDocPtr import = NULL; 53 xmlChar *base = NULL; 54 xmlChar *uriRef = NULL; 55 xmlChar *URI = NULL; 56 xsltStylesheetPtr res; 57 xsltSecurityPrefsPtr sec; 58 59 if ((cur == NULL) || (style == NULL)) 60 return (ret); 61 62 uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL); 63 if (uriRef == NULL) { 64 xsltTransformError(NULL, style, cur, 65 "xsl:import : missing href attribute\n"); 66 goto error; 67 } 68 69 base = xmlNodeGetBase(style->doc, cur); 70 URI = xmlBuildURI(uriRef, base); 71 if (URI == NULL) { 72 xsltTransformError(NULL, style, cur, 73 "xsl:import : invalid URI reference %s\n", uriRef); 74 goto error; 75 } 76 77 res = style; 78 while (res != NULL) { 79 if (res->doc == NULL) 80 break; 81 if (xmlStrEqual(res->doc->URL, URI)) { 82 xsltTransformError(NULL, style, cur, 83 "xsl:import : recursion detected on imported URL %s\n", URI); 84 goto error; 85 } 86 res = res->parent; 87 } 88 89 /* 90 * Security framework check 91 */ 92 sec = xsltGetDefaultSecurityPrefs(); 93 if (sec != NULL) { 94 int secres; 95 96 secres = xsltCheckRead(sec, NULL, URI); 97 if (secres == 0) { 98 xsltTransformError(NULL, NULL, NULL, 99 "xsl:import: read rights for %s denied\n", 100 URI); 101 goto error; 102 } 103 } 104 105 import = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, 106 (void *) style, XSLT_LOAD_STYLESHEET); 107 if (import == NULL) { 108 xsltTransformError(NULL, style, cur, 109 "xsl:import : unable to load %s\n", URI); 110 goto error; 111 } 112 113 res = xsltParseStylesheetImportedDoc(import, style); 114 if (res != NULL) { 115 res->next = style->imports; 116 style->imports = res; 117 if (style->parent == NULL) { 118 xsltFixImportedCompSteps(style, res); 119 } 120 ret = 0; 121 } else { 122 xmlFreeDoc(import); 123 } 124 125 error: 126 if (uriRef != NULL) 127 xmlFree(uriRef); 128 if (base != NULL) 129 xmlFree(base); 130 if (URI != NULL) 131 xmlFree(URI); 132 133 return (ret); 134 } 135 136 /** 137 * xsltParseStylesheetInclude: 138 * @style: the XSLT stylesheet 139 * @cur: the include node 140 * 141 * parse an XSLT stylesheet include element 142 * 143 * Returns 0 in case of success -1 in case of failure 144 */ 145 146 int 147 xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) { 148 int ret = -1; 149 xmlDocPtr oldDoc; 150 xmlChar *base = NULL; 151 xmlChar *uriRef = NULL; 152 xmlChar *URI = NULL; 153 xsltStylesheetPtr result; 154 xsltDocumentPtr include; 155 xsltDocumentPtr docptr; 156 int oldNopreproc; 157 158 if ((cur == NULL) || (style == NULL)) 159 return (ret); 160 161 uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL); 162 if (uriRef == NULL) { 163 xsltTransformError(NULL, style, cur, 164 "xsl:include : missing href attribute\n"); 165 goto error; 166 } 167 168 base = xmlNodeGetBase(style->doc, cur); 169 URI = xmlBuildURI(uriRef, base); 170 if (URI == NULL) { 171 xsltTransformError(NULL, style, cur, 172 "xsl:include : invalid URI reference %s\n", uriRef); 173 goto error; 174 } 175 176 /* 177 * in order to detect recursion, we check all previously included 178 * stylesheets. 179 */ 180 docptr = style->includes; 181 while (docptr != NULL) { 182 if (xmlStrEqual(docptr->doc->URL, URI)) { 183 xsltTransformError(NULL, style, cur, 184 "xsl:include : recursion detected on included URL %s\n", URI); 185 goto error; 186 } 187 docptr = docptr->includes; 188 } 189 190 include = xsltLoadStyleDocument(style, URI); 191 if (include == NULL) { 192 xsltTransformError(NULL, style, cur, 193 "xsl:include : unable to load %s\n", URI); 194 goto error; 195 } 196 #ifdef XSLT_REFACTORED 197 if (IS_XSLT_ELEM_FAST(cur) && (cur->psvi != NULL)) { 198 ((xsltStyleItemIncludePtr) cur->psvi)->include = include; 199 } else { 200 xsltTransformError(NULL, style, cur, 201 "Internal error: (xsltParseStylesheetInclude) " 202 "The xsl:include element was not compiled.\n", URI); 203 style->errors++; 204 } 205 #endif 206 oldDoc = style->doc; 207 style->doc = include->doc; 208 /* chain to stylesheet for recursion checking */ 209 include->includes = style->includes; 210 style->includes = include; 211 oldNopreproc = style->nopreproc; 212 style->nopreproc = include->preproc; 213 /* 214 * TODO: This will change some values of the 215 * including stylesheet with every included module 216 * (e.g. excluded-result-prefixes) 217 * We need to strictly seperate such stylesheet-owned values. 218 */ 219 result = xsltParseStylesheetProcess(style, include->doc); 220 style->nopreproc = oldNopreproc; 221 include->preproc = 1; 222 style->includes = include->includes; 223 style->doc = oldDoc; 224 if (result == NULL) { 225 ret = -1; 226 goto error; 227 } 228 ret = 0; 229 230 error: 231 if (uriRef != NULL) 232 xmlFree(uriRef); 233 if (base != NULL) 234 xmlFree(base); 235 if (URI != NULL) 236 xmlFree(URI); 237 238 return (ret); 239 } 240 241 /** 242 * xsltNextImport: 243 * @cur: the current XSLT stylesheet 244 * 245 * Find the next stylesheet in import precedence. 246 * 247 * Returns the next stylesheet or NULL if it was the last one 248 */ 249 250 xsltStylesheetPtr 251 xsltNextImport(xsltStylesheetPtr cur) { 252 if (cur == NULL) 253 return(NULL); 254 if (cur->imports != NULL) 255 return(cur->imports); 256 if (cur->next != NULL) 257 return(cur->next) ; 258 do { 259 cur = cur->parent; 260 if (cur == NULL) break; 261 if (cur->next != NULL) return(cur->next); 262 } while (cur != NULL); 263 return(cur); 264 } 265 266 /** 267 * xsltNeedElemSpaceHandling: 268 * @ctxt: an XSLT transformation context 269 * 270 * Checks whether that stylesheet requires white-space stripping 271 * 272 * Returns 1 if space should be stripped, 0 if not 273 */ 274 275 int 276 xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt) { 277 xsltStylesheetPtr style; 278 279 if (ctxt == NULL) 280 return(0); 281 style = ctxt->style; 282 while (style != NULL) { 283 if (style->stripSpaces != NULL) 284 return(1); 285 style = xsltNextImport(style); 286 } 287 return(0); 288 } 289 290 /** 291 * xsltFindElemSpaceHandling: 292 * @ctxt: an XSLT transformation context 293 * @node: an XML node 294 * 295 * Find strip-space or preserve-space informations for an element 296 * respect the import precedence or the wildcards 297 * 298 * Returns 1 if space should be stripped, 0 if not, and 2 if everything 299 * should be CDTATA wrapped. 300 */ 301 302 int 303 xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) { 304 xsltStylesheetPtr style; 305 const xmlChar *val; 306 307 if ((ctxt == NULL) || (node == NULL)) 308 return(0); 309 style = ctxt->style; 310 while (style != NULL) { 311 if (node->ns != NULL) { 312 val = (const xmlChar *) 313 xmlHashLookup2(style->stripSpaces, node->name, node->ns->href); 314 if (val == NULL) { 315 val = (const xmlChar *) 316 xmlHashLookup2(style->stripSpaces, BAD_CAST "*", 317 node->ns->href); 318 } 319 } else { 320 val = (const xmlChar *) 321 xmlHashLookup2(style->stripSpaces, node->name, NULL); 322 } 323 if (val != NULL) { 324 if (xmlStrEqual(val, (xmlChar *) "strip")) 325 return(1); 326 if (xmlStrEqual(val, (xmlChar *) "preserve")) 327 return(0); 328 } 329 if (style->stripAll == 1) 330 return(1); 331 if (style->stripAll == -1) 332 return(0); 333 334 style = xsltNextImport(style); 335 } 336 return(0); 337 } 338 339 /** 340 * xsltFindTemplate: 341 * @ctxt: an XSLT transformation context 342 * @name: the template name 343 * @nameURI: the template name URI 344 * 345 * Finds the named template, apply import precedence rule. 346 * REVISIT TODO: We'll change the nameURI fields of 347 * templates to be in the string dict, so if the 348 * specified @nameURI is in the same dict, then use pointer 349 * comparison. Check if this can be done in a sane way. 350 * Maybe this function is not needed internally at 351 * transformation-time if we hard-wire the called templates 352 * to the caller. 353 * 354 * Returns the xsltTemplatePtr or NULL if not found 355 */ 356 xsltTemplatePtr 357 xsltFindTemplate(xsltTransformContextPtr ctxt, const xmlChar *name, 358 const xmlChar *nameURI) { 359 xsltTemplatePtr cur; 360 xsltStylesheetPtr style; 361 362 if ((ctxt == NULL) || (name == NULL)) 363 return(NULL); 364 style = ctxt->style; 365 while (style != NULL) { 366 if (style->namedTemplates != NULL) { 367 cur = (xsltTemplatePtr) 368 xmlHashLookup2(style->namedTemplates, name, nameURI); 369 if (cur != NULL) 370 return(cur); 371 } 372 373 style = xsltNextImport(style); 374 } 375 return(NULL); 376 } 377 378