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