1 /* 2 * documents.c: Implementation of the documents handling 3 * 4 * See Copyright for the status of this software. 5 * 6 * daniel@veillard.com 7 */ 8 9 #include "precomp.h" 10 11 #ifdef LIBXML_XINCLUDE_ENABLED 12 #include <libxml/xinclude.h> 13 #endif 14 15 #define WITH_XSLT_DEBUG_DOCUMENTS 16 17 #ifdef WITH_XSLT_DEBUG 18 #define WITH_XSLT_DEBUG_DOCUMENTS 19 #endif 20 21 /************************************************************************ 22 * * 23 * Hooks for the document loader * 24 * * 25 ************************************************************************/ 26 27 /** 28 * xsltDocDefaultLoaderFunc: 29 * @URI: the URI of the document to load 30 * @dict: the dictionary to use when parsing that document 31 * @options: parsing options, a set of xmlParserOption 32 * @ctxt: the context, either a stylesheet or a transformation context 33 * @type: the xsltLoadType indicating the kind of loading required 34 * 35 * Default function to load document not provided by the compilation or 36 * transformation API themselve, for example when an xsl:import, 37 * xsl:include is found at compilation time or when a document() 38 * call is made at runtime. 39 * 40 * Returns the pointer to the document (which will be modified and 41 * freed by the engine later), or NULL in case of error. 42 */ 43 static xmlDocPtr 44 xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options, 45 void *ctxt ATTRIBUTE_UNUSED, 46 xsltLoadType type ATTRIBUTE_UNUSED) 47 { 48 xmlParserCtxtPtr pctxt; 49 xmlParserInputPtr inputStream; 50 xmlDocPtr doc; 51 52 pctxt = xmlNewParserCtxt(); 53 if (pctxt == NULL) 54 return(NULL); 55 if ((dict != NULL) && (pctxt->dict != NULL)) { 56 xmlDictFree(pctxt->dict); 57 pctxt->dict = NULL; 58 } 59 if (dict != NULL) { 60 pctxt->dict = dict; 61 xmlDictReference(pctxt->dict); 62 #ifdef WITH_XSLT_DEBUG 63 xsltGenericDebug(xsltGenericDebugContext, 64 "Reusing dictionary for document\n"); 65 #endif 66 } 67 xmlCtxtUseOptions(pctxt, options); 68 inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt); 69 if (inputStream == NULL) { 70 xmlFreeParserCtxt(pctxt); 71 return(NULL); 72 } 73 inputPush(pctxt, inputStream); 74 if (pctxt->directory == NULL) 75 pctxt->directory = xmlParserGetDirectory((const char *) URI); 76 77 xmlParseDocument(pctxt); 78 79 if (pctxt->wellFormed) { 80 doc = pctxt->myDoc; 81 } 82 else { 83 doc = NULL; 84 xmlFreeDoc(pctxt->myDoc); 85 pctxt->myDoc = NULL; 86 } 87 xmlFreeParserCtxt(pctxt); 88 89 return(doc); 90 } 91 92 93 xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; 94 95 /** 96 * xsltSetLoaderFunc: 97 * @f: the new function to handle document loading. 98 * 99 * Set the new function to load document, if NULL it resets it to the 100 * default function. 101 */ 102 103 void 104 xsltSetLoaderFunc(xsltDocLoaderFunc f) { 105 if (f == NULL) 106 xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; 107 else 108 xsltDocDefaultLoader = f; 109 } 110 111 /************************************************************************ 112 * * 113 * Module interfaces * 114 * * 115 ************************************************************************/ 116 117 /** 118 * xsltNewDocument: 119 * @ctxt: an XSLT transformation context (or NULL) 120 * @doc: a parsed XML document 121 * 122 * Register a new document, apply key computations 123 * 124 * Returns a handler to the document 125 */ 126 xsltDocumentPtr 127 xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) { 128 xsltDocumentPtr cur; 129 130 cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); 131 if (cur == NULL) { 132 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, 133 "xsltNewDocument : malloc failed\n"); 134 return(NULL); 135 } 136 memset(cur, 0, sizeof(xsltDocument)); 137 cur->doc = doc; 138 if (ctxt != NULL) { 139 if (! XSLT_IS_RES_TREE_FRAG(doc)) { 140 cur->next = ctxt->docList; 141 ctxt->docList = cur; 142 } 143 /* 144 * A key with a specific name for a specific document 145 * will only be computed if there's a call to the key() 146 * function using that specific name for that specific 147 * document. I.e. computation of keys will be done in 148 * xsltGetKey() (keys.c) on an on-demand basis. 149 * 150 * xsltInitCtxtKeys(ctxt, cur); not called here anymore 151 */ 152 } 153 return(cur); 154 } 155 156 /** 157 * xsltNewStyleDocument: 158 * @style: an XSLT style sheet 159 * @doc: a parsed XML document 160 * 161 * Register a new document, apply key computations 162 * 163 * Returns a handler to the document 164 */ 165 xsltDocumentPtr 166 xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) { 167 xsltDocumentPtr cur; 168 169 cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); 170 if (cur == NULL) { 171 xsltTransformError(NULL, style, (xmlNodePtr) doc, 172 "xsltNewStyleDocument : malloc failed\n"); 173 return(NULL); 174 } 175 memset(cur, 0, sizeof(xsltDocument)); 176 cur->doc = doc; 177 if (style != NULL) { 178 cur->next = style->docList; 179 style->docList = cur; 180 } 181 return(cur); 182 } 183 184 /** 185 * xsltFreeStyleDocuments: 186 * @style: an XSLT stylesheet (representing a stylesheet-level) 187 * 188 * Frees the node-trees (and xsltDocument structures) of all 189 * stylesheet-modules of the stylesheet-level represented by 190 * the given @style. 191 */ 192 void 193 xsltFreeStyleDocuments(xsltStylesheetPtr style) { 194 xsltDocumentPtr doc, cur; 195 #ifdef XSLT_REFACTORED_XSLT_NSCOMP 196 xsltNsMapPtr nsMap; 197 #endif 198 199 if (style == NULL) 200 return; 201 202 #ifdef XSLT_REFACTORED_XSLT_NSCOMP 203 if (XSLT_HAS_INTERNAL_NSMAP(style)) 204 nsMap = XSLT_GET_INTERNAL_NSMAP(style); 205 else 206 nsMap = NULL; 207 #endif 208 209 cur = style->docList; 210 while (cur != NULL) { 211 doc = cur; 212 cur = cur->next; 213 #ifdef XSLT_REFACTORED_XSLT_NSCOMP 214 /* 215 * Restore all changed namespace URIs of ns-decls. 216 */ 217 if (nsMap) 218 xsltRestoreDocumentNamespaces(nsMap, doc->doc); 219 #endif 220 xsltFreeDocumentKeys(doc); 221 if (!doc->main) 222 xmlFreeDoc(doc->doc); 223 xmlFree(doc); 224 } 225 } 226 227 /** 228 * xsltFreeDocuments: 229 * @ctxt: an XSLT transformation context 230 * 231 * Free up all the space used by the loaded documents 232 */ 233 void 234 xsltFreeDocuments(xsltTransformContextPtr ctxt) { 235 xsltDocumentPtr doc, cur; 236 237 cur = ctxt->docList; 238 while (cur != NULL) { 239 doc = cur; 240 cur = cur->next; 241 xsltFreeDocumentKeys(doc); 242 if (!doc->main) 243 xmlFreeDoc(doc->doc); 244 xmlFree(doc); 245 } 246 cur = ctxt->styleList; 247 while (cur != NULL) { 248 doc = cur; 249 cur = cur->next; 250 xsltFreeDocumentKeys(doc); 251 if (!doc->main) 252 xmlFreeDoc(doc->doc); 253 xmlFree(doc); 254 } 255 } 256 257 /** 258 * xsltLoadDocument: 259 * @ctxt: an XSLT transformation context 260 * @URI: the computed URI of the document 261 * 262 * Try to load a document (not a stylesheet) 263 * within the XSLT transformation context 264 * 265 * Returns the new xsltDocumentPtr or NULL in case of error 266 */ 267 xsltDocumentPtr 268 xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) { 269 xsltDocumentPtr ret; 270 xmlDocPtr doc; 271 272 if ((ctxt == NULL) || (URI == NULL)) 273 return(NULL); 274 275 /* 276 * Security framework check 277 */ 278 if (ctxt->sec != NULL) { 279 int res; 280 281 res = xsltCheckRead(ctxt->sec, ctxt, URI); 282 if (res == 0) { 283 xsltTransformError(ctxt, NULL, NULL, 284 "xsltLoadDocument: read rights for %s denied\n", 285 URI); 286 return(NULL); 287 } 288 } 289 290 /* 291 * Walk the context list to find the document if preparsed 292 */ 293 ret = ctxt->docList; 294 while (ret != NULL) { 295 if ((ret->doc != NULL) && (ret->doc->URL != NULL) && 296 (xmlStrEqual(ret->doc->URL, URI))) 297 return(ret); 298 ret = ret->next; 299 } 300 301 doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions, 302 (void *) ctxt, XSLT_LOAD_DOCUMENT); 303 304 if (doc == NULL) 305 return(NULL); 306 307 if (ctxt->xinclude != 0) { 308 #ifdef LIBXML_XINCLUDE_ENABLED 309 #if LIBXML_VERSION >= 20603 310 xmlXIncludeProcessFlags(doc, ctxt->parserOptions); 311 #else 312 xmlXIncludeProcess(doc); 313 #endif 314 #else 315 xsltTransformError(ctxt, NULL, NULL, 316 "xsltLoadDocument(%s) : XInclude processing not compiled in\n", 317 URI); 318 #endif 319 } 320 /* 321 * Apply white-space stripping if asked for 322 */ 323 if (xsltNeedElemSpaceHandling(ctxt)) 324 xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); 325 if (ctxt->debugStatus == XSLT_DEBUG_NONE) 326 xmlXPathOrderDocElems(doc); 327 328 ret = xsltNewDocument(ctxt, doc); 329 return(ret); 330 } 331 332 /** 333 * xsltLoadStyleDocument: 334 * @style: an XSLT style sheet 335 * @URI: the computed URI of the document 336 * 337 * Try to load a stylesheet document within the XSLT transformation context 338 * 339 * Returns the new xsltDocumentPtr or NULL in case of error 340 */ 341 xsltDocumentPtr 342 xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) { 343 xsltDocumentPtr ret; 344 xmlDocPtr doc; 345 xsltSecurityPrefsPtr sec; 346 347 if ((style == NULL) || (URI == NULL)) 348 return(NULL); 349 350 /* 351 * Security framework check 352 */ 353 sec = xsltGetDefaultSecurityPrefs(); 354 if (sec != NULL) { 355 int res; 356 357 res = xsltCheckRead(sec, NULL, URI); 358 if (res == 0) { 359 xsltTransformError(NULL, NULL, NULL, 360 "xsltLoadStyleDocument: read rights for %s denied\n", 361 URI); 362 return(NULL); 363 } 364 } 365 366 /* 367 * Walk the context list to find the document if preparsed 368 */ 369 ret = style->docList; 370 while (ret != NULL) { 371 if ((ret->doc != NULL) && (ret->doc->URL != NULL) && 372 (xmlStrEqual(ret->doc->URL, URI))) 373 return(ret); 374 ret = ret->next; 375 } 376 377 doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, 378 (void *) style, XSLT_LOAD_STYLESHEET); 379 if (doc == NULL) 380 return(NULL); 381 382 ret = xsltNewStyleDocument(style, doc); 383 return(ret); 384 } 385 386 /** 387 * xsltFindDocument: 388 * @ctxt: an XSLT transformation context 389 * @doc: a parsed XML document 390 * 391 * Try to find a document within the XSLT transformation context. 392 * This will not find document infos for temporary 393 * Result Tree Fragments. 394 * 395 * Returns the desired xsltDocumentPtr or NULL in case of error 396 */ 397 xsltDocumentPtr 398 xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) { 399 xsltDocumentPtr ret; 400 401 if ((ctxt == NULL) || (doc == NULL)) 402 return(NULL); 403 404 /* 405 * Walk the context list to find the document 406 */ 407 ret = ctxt->docList; 408 while (ret != NULL) { 409 if (ret->doc == doc) 410 return(ret); 411 ret = ret->next; 412 } 413 if (doc == ctxt->style->doc) 414 return(ctxt->document); 415 return(NULL); 416 } 417 418