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