blob: 12c6f2df94b9ca757d0a5165ffb43857f6d40bfc [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xinclude.c : Code to implement XInclude processing
3 *
Daniel Veillardbbd22452001-05-23 12:02:27 +00004 * World Wide Web Consortium W3C Last Call Working Draft 16 May 2001
5 * http://www.w3.org/TR/2001/WD-xinclude-20010516/
Owen Taylor3473f882001-02-23 17:55:21 +00006 *
7 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 */
11
12/*
13 * TODO: compute XPointers nodesets
Daniel Veillardd16df9f2001-05-23 13:44:21 +000014 * TODO: add an node intermediate API and handle recursion at this level
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21#include <libxml/xmlmemory.h>
22#include <libxml/tree.h>
23#include <libxml/parser.h>
24#include <libxml/uri.h>
25#include <libxml/xpointer.h>
26#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000027#include <libxml/xmlerror.h>
Daniel Veillardd076a202002-11-20 13:28:31 +000028#include <libxml/encoding.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000029#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000030
31#ifdef LIBXML_XINCLUDE_ENABLED
32#include <libxml/xinclude.h>
33
Daniel Veillardbbd22452001-05-23 12:02:27 +000034#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
Owen Taylor3473f882001-02-23 17:55:21 +000035#define XINCLUDE_NODE (const xmlChar *) "include"
Daniel Veillard58e44c92002-08-02 22:19:49 +000036#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
Owen Taylor3473f882001-02-23 17:55:21 +000037#define XINCLUDE_HREF (const xmlChar *) "href"
38#define XINCLUDE_PARSE (const xmlChar *) "parse"
39#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
40#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
Daniel Veillardd076a202002-11-20 13:28:31 +000041#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
Owen Taylor3473f882001-02-23 17:55:21 +000042
Daniel Veillardf4b4f982003-02-13 11:02:08 +000043#define XINCLUDE_MAX_DEPTH 40
44
Owen Taylor3473f882001-02-23 17:55:21 +000045/* #define DEBUG_XINCLUDE */
Daniel Veillard017b1082001-06-21 11:20:21 +000046#ifdef DEBUG_XINCLUDE
47#ifdef LIBXML_DEBUG_ENABLED
48#include <libxml/debugXML.h>
49#endif
50#endif
Owen Taylor3473f882001-02-23 17:55:21 +000051
52/************************************************************************
53 * *
54 * XInclude contexts handling *
55 * *
56 ************************************************************************/
57
58/*
59 * An XInclude context
60 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000061typedef xmlChar *xmlURL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +000062
63typedef struct _xmlXIncludeRef xmlXIncludeRef;
64typedef xmlXIncludeRef *xmlXIncludeRefPtr;
65struct _xmlXIncludeRef {
66 xmlChar *URI; /* the rully resolved resource URL */
67 xmlChar *fragment; /* the fragment in the URI */
68 xmlDocPtr doc; /* the parsed document */
69 xmlNodePtr ref; /* the node making the reference in the source */
70 xmlNodePtr inc; /* the included copy */
71 int xml; /* xml or txt */
72 int count; /* how many refs use that specific doc */
Daniel Veillardf4b4f982003-02-13 11:02:08 +000073 xmlXPathObjectPtr xptr; /* the xpointer if needed */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000074};
75
Owen Taylor3473f882001-02-23 17:55:21 +000076typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
77typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
78struct _xmlXIncludeCtxt {
79 xmlDocPtr doc; /* the source document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000080 int incBase; /* the first include for this document */
Owen Taylor3473f882001-02-23 17:55:21 +000081 int incNr; /* number of includes */
82 int incMax; /* size of includes tab */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000083 xmlXIncludeRefPtr *incTab; /* array of included references */
84
Owen Taylor3473f882001-02-23 17:55:21 +000085 int txtNr; /* number of unparsed documents */
86 int txtMax; /* size of unparsed documents tab */
87 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000088 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Daniel Veillardd581b7e2003-02-11 18:03:05 +000089
Daniel Veillardf4b4f982003-02-13 11:02:08 +000090 xmlChar * url; /* the current URL processed */
91 int urlNr; /* number of url stacked */
92 int urlMax; /* size of url stack */
93 xmlChar * *urlTab; /* url stack */
94
Daniel Veillardd581b7e2003-02-11 18:03:05 +000095 int nbErrors; /* the number of errors detected */
Owen Taylor3473f882001-02-23 17:55:21 +000096};
97
Daniel Veillardd16df9f2001-05-23 13:44:21 +000098static int
99xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
Owen Taylor3473f882001-02-23 17:55:21 +0000100
101/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000102 * xmlXIncludeFreeRef:
103 * @ref: the XInclude reference
104 *
105 * Free an XInclude reference
106 */
107static void
108xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
109 if (ref == NULL)
110 return;
111#ifdef DEBUG_XINCLUDE
112 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
113#endif
114 if (ref->doc != NULL) {
115#ifdef DEBUG_XINCLUDE
116 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
117#endif
118 xmlFreeDoc(ref->doc);
119 }
120 if (ref->URI != NULL)
121 xmlFree(ref->URI);
122 if (ref->fragment != NULL)
123 xmlFree(ref->fragment);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000124 if (ref->xptr != NULL)
125 xmlXPathFreeObject(ref->xptr);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000126 xmlFree(ref);
127}
128
129/**
130 * xmlXIncludeNewRef:
131 * @ctxt: the XInclude context
132 * @URI: the resource URI
133 *
134 * Creates a new reference within an XInclude context
135 *
136 * Returns the new set
137 */
138static xmlXIncludeRefPtr
139xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
140 xmlNodePtr ref) {
141 xmlXIncludeRefPtr ret;
142
143#ifdef DEBUG_XINCLUDE
144 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
145#endif
146 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
147 if (ret == NULL)
148 return(NULL);
149 memset(ret, 0, sizeof(xmlXIncludeRef));
150 if (URI == NULL)
151 ret->URI = NULL;
152 else
153 ret->URI = xmlStrdup(URI);
154 ret->fragment = NULL;
155 ret->ref = ref;
156 ret->doc = 0;
157 ret->count = 0;
158 ret->xml = 0;
159 ret->inc = NULL;
160 if (ctxt->incMax == 0) {
161 ctxt->incMax = 4;
162 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
163 sizeof(ctxt->incTab[0]));
164 if (ctxt->incTab == NULL) {
165 xmlGenericError(xmlGenericErrorContext,
166 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000167 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000168 xmlXIncludeFreeRef(ret);
169 return(NULL);
170 }
171 }
172 if (ctxt->incNr >= ctxt->incMax) {
173 ctxt->incMax *= 2;
174 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
175 ctxt->incMax * sizeof(ctxt->incTab[0]));
176 if (ctxt->incTab == NULL) {
177 xmlGenericError(xmlGenericErrorContext,
178 "realloc failed !\n");
179 xmlXIncludeFreeRef(ret);
180 return(NULL);
181 }
182 }
183 ctxt->incTab[ctxt->incNr++] = ret;
184 return(ret);
185}
186
187/**
Owen Taylor3473f882001-02-23 17:55:21 +0000188 * xmlXIncludeNewContext:
189 * @doc: an XML Document
190 *
191 * Creates a new XInclude context
192 *
193 * Returns the new set
194 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000195static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000196xmlXIncludeNewContext(xmlDocPtr doc) {
197 xmlXIncludeCtxtPtr ret;
198
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000199#ifdef DEBUG_XINCLUDE
200 xmlGenericError(xmlGenericErrorContext, "New context\n");
201#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000202 if (doc == NULL)
203 return(NULL);
204 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
205 if (ret == NULL)
206 return(NULL);
207 memset(ret, 0, sizeof(xmlXIncludeCtxt));
208 ret->doc = doc;
209 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000210 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000211 ret->incMax = 0;
212 ret->incTab = NULL;
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000213 ret->nbErrors = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000214 return(ret);
215}
216
217/**
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000218 * xmlXIncludeURLPush:
219 * @ctxt: the parser context
220 * @value: the url
221 *
222 * Pushes a new url on top of the url stack
223 *
224 * Returns -1 in case of error, the index in the stack otherwise
225 */
226static int
227xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
228 const xmlChar *value)
229{
230 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
231 xmlGenericError(xmlGenericErrorContext,
232 "XInclude: detected a recursion in %s\n",
233 value);
234 ctxt->nbErrors++;
235 return(-1);
236 }
237 if (ctxt->urlTab == NULL) {
238 ctxt->urlMax = 4;
239 ctxt->urlNr = 0;
240 ctxt->urlTab = (xmlChar * *) xmlMalloc(
241 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
242 if (ctxt->urlTab == NULL) {
243 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
244 return (-1);
245 }
246 }
247 if (ctxt->urlNr >= ctxt->urlMax) {
248 ctxt->urlMax *= 2;
249 ctxt->urlTab =
250 (xmlChar * *) xmlRealloc(ctxt->urlTab,
251 ctxt->urlMax *
252 sizeof(ctxt->urlTab[0]));
253 if (ctxt->urlTab == NULL) {
254 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
255 return (-1);
256 }
257 }
258 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
259 return (ctxt->urlNr++);
260}
261
262/**
263 * xmlXIncludeURLPop:
264 * @ctxt: the parser context
265 *
266 * Pops the top url from the url stack
267 */
268static void
269xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
270{
271 xmlChar * ret;
272
273 if (ctxt->urlNr <= 0)
274 return;
275 ctxt->urlNr--;
276 if (ctxt->urlNr > 0)
277 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
278 else
279 ctxt->url = NULL;
280 ret = ctxt->urlTab[ctxt->urlNr];
281 ctxt->urlTab[ctxt->urlNr] = 0;
282 if (ret != NULL)
283 xmlFree(ret);
284}
285
286/**
Owen Taylor3473f882001-02-23 17:55:21 +0000287 * xmlXIncludeFreeContext:
288 * @ctxt: the XInclude context
289 *
290 * Free an XInclude context
291 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000292static void
Owen Taylor3473f882001-02-23 17:55:21 +0000293xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
294 int i;
295
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000296#ifdef DEBUG_XINCLUDE
297 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
298#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000299 if (ctxt == NULL)
300 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000301 while (ctxt->urlNr > 0)
302 xmlXIncludeURLPop(ctxt);
303 if (ctxt->urlTab != NULL)
304 xmlFree(ctxt->urlTab);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000305 for (i = 0;i < ctxt->incNr;i++) {
306 if (ctxt->incTab[i] != NULL)
307 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000308 }
309 for (i = 0;i < ctxt->txtNr;i++) {
310 if (ctxt->txturlTab[i] != NULL)
311 xmlFree(ctxt->txturlTab[i]);
312 }
313 if (ctxt->incTab != NULL)
314 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000315 if (ctxt->txtTab != NULL)
316 xmlFree(ctxt->txtTab);
317 if (ctxt->txturlTab != NULL)
318 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000319 xmlFree(ctxt);
320}
321
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000322/**
323 * xmlXIncludeAddNode:
324 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000325 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000326 *
327 * Add a new node to process to an XInclude context
328 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000329static int
330xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
331 xmlXIncludeRefPtr ref;
332 xmlURIPtr uri;
333 xmlChar *URL;
334 xmlChar *fragment = NULL;
335 xmlChar *href;
336 xmlChar *parse;
337 xmlChar *base;
338 xmlChar *URI;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000339 int xml = 1, i; /* default Issue 64 */
340 int local = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000341
342
343 if (ctxt == NULL)
344 return(-1);
345 if (cur == NULL)
346 return(-1);
347
348#ifdef DEBUG_XINCLUDE
349 xmlGenericError(xmlGenericErrorContext, "Add node\n");
350#endif
351 /*
352 * read the attributes
353 */
354 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
355 if (href == NULL) {
356 href = xmlGetProp(cur, XINCLUDE_HREF);
357 if (href == NULL) {
358 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000359 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000360 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000361 }
362 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000363 if (href[0] == '#')
364 local = 1;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000365 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
366 if (parse == NULL) {
367 parse = xmlGetProp(cur, XINCLUDE_PARSE);
368 }
369 if (parse != NULL) {
370 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
371 xml = 1;
372 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
373 xml = 0;
374 else {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000375 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000376 "XInclude: invalid value %s for %s\n",
377 parse, XINCLUDE_PARSE);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000378 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000379 if (href != NULL)
380 xmlFree(href);
381 if (parse != NULL)
382 xmlFree(parse);
383 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000384 }
385 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000386
387 /*
388 * compute the URI
389 */
390 base = xmlNodeGetBase(ctxt->doc, cur);
391 if (base == NULL) {
392 URI = xmlBuildURI(href, ctxt->doc->URL);
393 } else {
394 URI = xmlBuildURI(href, base);
395 }
396 if (URI == NULL) {
397 xmlChar *escbase;
398 xmlChar *eschref;
399 /*
400 * Some escaping may be needed
401 */
402 escbase = xmlURIEscape(base);
403 eschref = xmlURIEscape(href);
404 URI = xmlBuildURI(eschref, escbase);
405 if (escbase != NULL)
406 xmlFree(escbase);
407 if (eschref != NULL)
408 xmlFree(eschref);
409 }
410 if (parse != NULL)
411 xmlFree(parse);
412 if (href != NULL)
413 xmlFree(href);
414 if (base != NULL)
415 xmlFree(base);
416 if (URI == NULL) {
417 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000418 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000419 return(-1);
420 }
421
422 /*
423 * Check the URL and remove any fragment identifier
424 */
425 uri = xmlParseURI((const char *)URI);
426 if (uri == NULL) {
427 xmlGenericError(xmlGenericErrorContext,
428 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000429 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000430 return(-1);
431 }
432 if (uri->fragment != NULL) {
433 fragment = (xmlChar *) uri->fragment;
434 uri->fragment = NULL;
435 }
436 URL = xmlSaveUri(uri);
437 xmlFreeURI(uri);
438 xmlFree(URI);
439 if (URL == NULL) {
440 xmlGenericError(xmlGenericErrorContext,
441 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000442 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000443 if (fragment != NULL)
444 xmlFree(fragment);
445 return(-1);
446 }
447
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000448 /*
449 * Check the URL against the stack for recursions
450 */
451 if (!local) {
452 for (i = 0;i < ctxt->urlNr;i++) {
453 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
454 xmlGenericError(xmlGenericErrorContext,
455 "XInclude: detected a recursion in %s\n",
456 URL);
457 ctxt->nbErrors++;
458 return(-1);
459 }
460 }
461 }
462
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000463 ref = xmlXIncludeNewRef(ctxt, URL, cur);
464 if (ref == NULL) {
465 return(-1);
466 }
467 ref->fragment = fragment;
468 ref->doc = NULL;
469 ref->xml = xml;
470 ref->count = 1;
471 xmlFree(URL);
472 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000473}
474
475/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000476 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000477 * @ctxt: the XInclude context
478 * @doc: the new document
479 * @url: the associated URL
480 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000481 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000482 */
483static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000484xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000485 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000486 xmlXIncludeCtxtPtr newctxt;
487 int i;
488
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000489 /*
490 * Avoid recursion in already substitued resources
491 for (i = 0;i < ctxt->urlNr;i++) {
492 if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
493 return;
494 }
495 */
496
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000497#ifdef DEBUG_XINCLUDE
498 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
499#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000500 /*
501 * Handle recursion here.
502 */
503
504 newctxt = xmlXIncludeNewContext(doc);
505 if (newctxt != NULL) {
506 /*
507 * Copy the existing document set
508 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000509 newctxt->incMax = ctxt->incMax;
510 newctxt->incNr = ctxt->incNr;
511 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
512 sizeof(newctxt->incTab[0]));
513 if (newctxt->incTab == NULL) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000514 xmlGenericError(xmlGenericErrorContext,
515 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000516 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000517 xmlFree(newctxt);
518 return;
519 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000520 /*
521 * copy the urlTab
522 */
523 newctxt->urlMax = ctxt->urlMax;
524 newctxt->urlNr = ctxt->urlNr;
525 newctxt->urlTab = ctxt->urlTab;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000526
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000527 /*
528 * Inherit the documents already in use by others includes
529 */
530 newctxt->incBase = ctxt->incNr;
531 for (i = 0;i < ctxt->incNr;i++) {
532 newctxt->incTab[i] = ctxt->incTab[i];
533 newctxt->incTab[i]->count++; /* prevent the recursion from
534 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000535 }
536 xmlXIncludeDoProcess(newctxt, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000537 for (i = 0;i < ctxt->incNr;i++) {
538 newctxt->incTab[i]->count--;
539 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000540 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000541 newctxt->urlMax = 0;
542 newctxt->urlNr = 0;
543 newctxt->urlTab = NULL;
544
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000545 xmlXIncludeFreeContext(newctxt);
546 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000547#ifdef DEBUG_XINCLUDE
548 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
549#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000550}
551
552/**
553 * xmlXIncludeAddTxt:
554 * @ctxt: the XInclude context
555 * @txt: the new text node
556 * @url: the associated URL
557 *
558 * Add a new txtument to the list
559 */
560static void
561xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000562#ifdef DEBUG_XINCLUDE
563 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
564#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000565 if (ctxt->txtMax == 0) {
566 ctxt->txtMax = 4;
567 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
568 sizeof(ctxt->txtTab[0]));
569 if (ctxt->txtTab == NULL) {
570 xmlGenericError(xmlGenericErrorContext,
571 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000572 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000573 return;
574 }
575 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
576 sizeof(ctxt->txturlTab[0]));
577 if (ctxt->txturlTab == NULL) {
578 xmlGenericError(xmlGenericErrorContext,
579 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000580 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000581 return;
582 }
583 }
584 if (ctxt->txtNr >= ctxt->txtMax) {
585 ctxt->txtMax *= 2;
586 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
587 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
588 if (ctxt->txtTab == NULL) {
589 xmlGenericError(xmlGenericErrorContext,
590 "realloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000591 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000592 return;
593 }
594 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000595 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000596 if (ctxt->txturlTab == NULL) {
597 xmlGenericError(xmlGenericErrorContext,
598 "realloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000599 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000600 return;
601 }
602 }
603 ctxt->txtTab[ctxt->txtNr] = txt;
604 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
605 ctxt->txtNr++;
606}
607
Owen Taylor3473f882001-02-23 17:55:21 +0000608/************************************************************************
609 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000610 * Node copy with specific semantic *
611 * *
612 ************************************************************************/
613
614/**
615 * xmlXIncludeCopyNode:
616 * @ctxt: the XInclude context
617 * @target: the document target
618 * @source: the document source
619 * @elem: the element
620 *
621 * Make a copy of the node while preserving the XInclude semantic
622 * of the Infoset copy
623 */
624static xmlNodePtr
625xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
626 xmlDocPtr source, xmlNodePtr elem) {
627 xmlNodePtr result = NULL;
628
629 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
630 (elem == NULL))
631 return(NULL);
632 if (elem->type == XML_DTD_NODE)
633 return(NULL);
634 result = xmlDocCopyNode(elem, target, 1);
635 return(result);
636}
637
638/**
639 * xmlXIncludeCopyNodeList:
640 * @ctxt: the XInclude context
641 * @target: the document target
642 * @source: the document source
643 * @elem: the element list
644 *
645 * Make a copy of the node list while preserving the XInclude semantic
646 * of the Infoset copy
647 */
648static xmlNodePtr
649xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
650 xmlDocPtr source, xmlNodePtr elem) {
651 xmlNodePtr cur, res, result = NULL, last = NULL;
652
653 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
654 (elem == NULL))
655 return(NULL);
656 cur = elem;
657 while (cur != NULL) {
658 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
659 if (res != NULL) {
660 if (result == NULL) {
661 result = last = res;
662 } else {
663 last->next = res;
664 res->prev = last;
665 last = res;
666 }
667 }
668 cur = cur->next;
669 }
670 return(result);
671}
672
673/**
674 * xmlXInclueGetNthChild:
675 * @cur: the node
676 * @no: the child number
677 *
678 * Returns the @no'th element child of @cur or NULL
679 */
680static xmlNodePtr
681xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
682 int i;
683 if (cur == NULL)
684 return(cur);
685 cur = cur->children;
686 for (i = 0;i <= no;cur = cur->next) {
687 if (cur == NULL)
688 return(cur);
689 if ((cur->type == XML_ELEMENT_NODE) ||
690 (cur->type == XML_DOCUMENT_NODE) ||
691 (cur->type == XML_HTML_DOCUMENT_NODE)) {
692 i++;
693 if (i == no)
694 break;
695 }
696 }
697 return(cur);
698}
699
700xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
701
702/**
703 * xmlXIncludeCopyRange:
704 * @ctxt: the XInclude context
705 * @target: the document target
706 * @source: the document source
707 * @obj: the XPointer result from the evaluation.
708 *
709 * Build a node list tree copy of the XPointer result.
710 *
711 * Returns an xmlNodePtr list or NULL.
712 * the caller has to free the node tree.
713 */
714static xmlNodePtr
715xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
716 xmlDocPtr source, xmlXPathObjectPtr range) {
717 /* pointers to generated nodes */
718 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
719 /* pointers to traversal nodes */
720 xmlNodePtr start, cur, end;
721 int index1, index2;
722
723 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
724 (range == NULL))
725 return(NULL);
726 if (range->type != XPATH_RANGE)
727 return(NULL);
728 start = (xmlNodePtr) range->user;
729
730 if (start == NULL)
731 return(NULL);
732 end = range->user2;
733 if (end == NULL)
734 return(xmlDocCopyNode(start, target, 1));
735
736 cur = start;
737 index1 = range->index;
738 index2 = range->index2;
739 while (cur != NULL) {
740 if (cur == end) {
741 if (cur->type == XML_TEXT_NODE) {
742 const xmlChar *content = cur->content;
743 int len;
744
745 if (content == NULL) {
746 tmp = xmlNewTextLen(NULL, 0);
747 } else {
748 len = index2;
749 if ((cur == start) && (index1 > 1)) {
750 content += (index1 - 1);
751 len -= (index1 - 1);
752 index1 = 0;
753 } else {
754 len = index2;
755 }
756 tmp = xmlNewTextLen(content, len);
757 }
758 /* single sub text node selection */
759 if (list == NULL)
760 return(tmp);
761 /* prune and return full set */
762 if (last != NULL)
763 xmlAddNextSibling(last, tmp);
764 else
765 xmlAddChild(parent, tmp);
766 return(list);
767 } else {
768 tmp = xmlDocCopyNode(cur, target, 0);
769 if (list == NULL)
770 list = tmp;
771 else {
772 if (last != NULL)
773 xmlAddNextSibling(last, tmp);
774 else
775 xmlAddChild(parent, tmp);
776 }
777 last = NULL;
778 parent = tmp;
779
780 if (index2 > 1) {
781 end = xmlXIncludeGetNthChild(cur, index2 - 1);
782 index2 = 0;
783 }
784 if ((cur == start) && (index1 > 1)) {
785 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
786 index1 = 0;
787 } else {
788 cur = cur->children;
789 }
790 /*
791 * Now gather the remaining nodes from cur to end
792 */
793 continue; /* while */
794 }
795 } else if ((cur == start) &&
796 (list == NULL) /* looks superfluous but ... */ ) {
797 if ((cur->type == XML_TEXT_NODE) ||
798 (cur->type == XML_CDATA_SECTION_NODE)) {
799 const xmlChar *content = cur->content;
800
801 if (content == NULL) {
802 tmp = xmlNewTextLen(NULL, 0);
803 } else {
804 if (index1 > 1) {
805 content += (index1 - 1);
806 }
807 tmp = xmlNewText(content);
808 }
809 last = list = tmp;
810 } else {
811 if ((cur == start) && (index1 > 1)) {
812 tmp = xmlDocCopyNode(cur, target, 0);
813 list = tmp;
814 parent = tmp;
815 last = NULL;
816 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
817 index1 = 0;
818 /*
819 * Now gather the remaining nodes from cur to end
820 */
821 continue; /* while */
822 }
823 tmp = xmlDocCopyNode(cur, target, 1);
824 list = tmp;
825 parent = NULL;
826 last = tmp;
827 }
828 } else {
829 tmp = NULL;
830 switch (cur->type) {
831 case XML_DTD_NODE:
832 case XML_ELEMENT_DECL:
833 case XML_ATTRIBUTE_DECL:
834 case XML_ENTITY_NODE:
835 /* Do not copy DTD informations */
836 break;
837 case XML_ENTITY_DECL:
838 /* handle crossing entities -> stack needed */
839 break;
840 case XML_XINCLUDE_START:
841 case XML_XINCLUDE_END:
842 /* don't consider it part of the tree content */
843 break;
844 case XML_ATTRIBUTE_NODE:
845 /* Humm, should not happen ! */
846 break;
847 default:
848 tmp = xmlDocCopyNode(cur, target, 1);
849 break;
850 }
851 if (tmp != NULL) {
852 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
853 return(NULL);
854 }
855 if (last != NULL)
856 xmlAddNextSibling(last, tmp);
857 else {
858 xmlAddChild(parent, tmp);
859 last = tmp;
860 }
861 }
862 }
863 /*
864 * Skip to next node in document order
865 */
866 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
867 return(NULL);
868 }
869 cur = xmlXPtrAdvanceNode(cur);
870 }
871 return(list);
872}
873
874/**
875 * xmlXIncludeBuildNodeList:
876 * @ctxt: the XInclude context
877 * @target: the document target
878 * @source: the document source
879 * @obj: the XPointer result from the evaluation.
880 *
881 * Build a node list tree copy of the XPointer result.
882 * This will drop Attributes and Namespace declarations.
883 *
884 * Returns an xmlNodePtr list or NULL.
885 * the caller has to free the node tree.
886 */
887static xmlNodePtr
888xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
889 xmlDocPtr source, xmlXPathObjectPtr obj) {
890 xmlNodePtr list = NULL, last = NULL;
891 int i;
892
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000893 if (source == NULL)
894 source = ctxt->doc;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000895 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
896 (obj == NULL))
897 return(NULL);
898 switch (obj->type) {
899 case XPATH_NODESET: {
900 xmlNodeSetPtr set = obj->nodesetval;
901 if (set == NULL)
902 return(NULL);
903 for (i = 0;i < set->nodeNr;i++) {
904 if (set->nodeTab[i] == NULL)
905 continue;
906 switch (set->nodeTab[i]->type) {
907 case XML_TEXT_NODE:
908 case XML_CDATA_SECTION_NODE:
909 case XML_ELEMENT_NODE:
910 case XML_ENTITY_REF_NODE:
911 case XML_ENTITY_NODE:
912 case XML_PI_NODE:
913 case XML_COMMENT_NODE:
914 case XML_DOCUMENT_NODE:
915 case XML_HTML_DOCUMENT_NODE:
916#ifdef LIBXML_DOCB_ENABLED
917 case XML_DOCB_DOCUMENT_NODE:
918#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000919 case XML_XINCLUDE_END:
920 break;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000921 case XML_XINCLUDE_START: {
922 xmlNodePtr tmp, cur = set->nodeTab[i];
923
924 cur = cur->next;
925 while (cur != NULL) {
926 switch(cur->type) {
927 case XML_TEXT_NODE:
928 case XML_CDATA_SECTION_NODE:
929 case XML_ELEMENT_NODE:
930 case XML_ENTITY_REF_NODE:
931 case XML_ENTITY_NODE:
932 case XML_PI_NODE:
933 case XML_COMMENT_NODE:
934 tmp = xmlXIncludeCopyNode(ctxt, target,
935 source, cur);
936 if (last == NULL) {
937 list = last = tmp;
938 } else {
939 xmlAddNextSibling(last, tmp);
940 last = tmp;
941 }
942 cur = cur->next;
943 continue;
944 default:
945 break;
946 }
947 break;
948 }
949 continue;
950 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000951 case XML_ATTRIBUTE_NODE:
952 case XML_NAMESPACE_DECL:
953 case XML_DOCUMENT_TYPE_NODE:
954 case XML_DOCUMENT_FRAG_NODE:
955 case XML_NOTATION_NODE:
956 case XML_DTD_NODE:
957 case XML_ELEMENT_DECL:
958 case XML_ATTRIBUTE_DECL:
959 case XML_ENTITY_DECL:
960 continue; /* for */
961 }
962 if (last == NULL)
963 list = last = xmlXIncludeCopyNode(ctxt, target, source,
964 set->nodeTab[i]);
965 else {
966 xmlAddNextSibling(last,
967 xmlXIncludeCopyNode(ctxt, target, source,
968 set->nodeTab[i]));
969 if (last->next != NULL)
970 last = last->next;
971 }
972 }
973 break;
974 }
975 case XPATH_LOCATIONSET: {
976 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
977 if (set == NULL)
978 return(NULL);
979 for (i = 0;i < set->locNr;i++) {
980 if (last == NULL)
981 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
982 set->locTab[i]);
983 else
984 xmlAddNextSibling(last,
985 xmlXIncludeCopyXPointer(ctxt, target, source,
986 set->locTab[i]));
987 if (last != NULL) {
988 while (last->next != NULL)
989 last = last->next;
990 }
991 }
992 break;
993 }
994 case XPATH_RANGE:
995 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
996 case XPATH_POINT:
997 /* points are ignored in XInclude */
998 break;
999 default:
1000 break;
1001 }
1002 return(list);
1003}
1004/************************************************************************
1005 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001006 * XInclude I/O handling *
1007 * *
1008 ************************************************************************/
1009
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001010typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1011typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1012struct _xmlXIncludeMergeData {
1013 xmlDocPtr doc;
1014 xmlXIncludeCtxtPtr ctxt;
1015};
1016
Owen Taylor3473f882001-02-23 17:55:21 +00001017/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001018 * xmlXIncludeMergeOneEntity:
1019 * @ent: the entity
1020 * @doc: the including doc
1021 * @nr: the entity name
1022 *
1023 * Inplements the merge of one entity
1024 */
1025static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001026xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001027 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001028 xmlEntityPtr ret, prev;
1029 xmlDocPtr doc;
1030 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001031
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001032 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001033 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001034 ctxt = data->ctxt;
1035 doc = data->doc;
1036 if ((ctxt == NULL) || (doc == NULL))
1037 return;
1038 switch (ent->etype) {
1039 case XML_INTERNAL_PARAMETER_ENTITY:
1040 case XML_EXTERNAL_PARAMETER_ENTITY:
1041 case XML_INTERNAL_PREDEFINED_ENTITY:
1042 return;
1043 case XML_INTERNAL_GENERAL_ENTITY:
1044 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1045 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1046 break;
1047 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001048 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1049 ent->SystemID, ent->content);
1050 if (ret != NULL) {
1051 if (ent->URI != NULL)
1052 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001053 } else {
1054 prev = xmlGetDocEntity(doc, ent->name);
1055 if (prev != NULL) {
1056 if (ent->etype != prev->etype)
1057 goto error;
1058
1059 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1060 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1061 goto error;
1062 } else if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1063 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1064 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001065 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1066 if (!xmlStrEqual(ent->content, prev->content))
1067 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001068 } else {
1069 goto error;
1070 }
1071
1072 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001073 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001074 return;
1075error:
1076 xmlGenericError(xmlGenericErrorContext,
1077 "XInclude: mismatch in redefinition of entity %s\n", ent->name);
1078 ctxt->nbErrors++;
Daniel Veillard4287c572003-02-04 22:48:53 +00001079}
1080
1081/**
1082 * xmlXIncludeMergeEntities:
1083 * @ctxt: an XInclude context
1084 * @doc: the including doc
1085 * @from: the included doc
1086 *
1087 * Inplements the entity merge
1088 *
1089 * Returns 0 if merge succeeded, -1 if some processing failed
1090 */
1091static int
1092xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1093 xmlDocPtr from) {
1094 xmlNodePtr cur;
1095 xmlDtdPtr target, source;
1096
1097 if (ctxt == NULL)
1098 return(-1);
1099
1100 if ((from == NULL) || (from->intSubset == NULL))
1101 return(0);
1102
1103 target = doc->intSubset;
1104 if (target == NULL) {
1105 cur = xmlDocGetRootElement(doc);
1106 if (cur == NULL)
1107 return(-1);
1108 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1109 if (target == NULL)
1110 return(-1);
1111 }
1112
1113 source = from->intSubset;
1114 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001115 xmlXIncludeMergeData data;
1116
1117 data.ctxt = ctxt;
1118 data.doc = doc;
1119
Daniel Veillard4287c572003-02-04 22:48:53 +00001120 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001121 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001122 }
1123 source = from->extSubset;
1124 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001125 xmlXIncludeMergeData data;
1126
1127 data.ctxt = ctxt;
1128 data.doc = doc;
1129
Daniel Veillard4287c572003-02-04 22:48:53 +00001130 /*
1131 * don't duplicate existing stuff when external subsets are the same
1132 */
1133 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1134 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1135 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001136 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001137 }
1138 }
1139 return(0);
1140}
1141
1142/**
Owen Taylor3473f882001-02-23 17:55:21 +00001143 * xmlXIncludeLoadDoc:
1144 * @ctxt: the XInclude context
1145 * @url: the associated URL
1146 * @nr: the xinclude node number
1147 *
1148 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001149 *
1150 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001151 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001152static int
Owen Taylor3473f882001-02-23 17:55:21 +00001153xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1154 xmlDocPtr doc;
1155 xmlURIPtr uri;
1156 xmlChar *URL;
1157 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001158 int i = 0;
1159
1160#ifdef DEBUG_XINCLUDE
1161 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1162#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001163 /*
1164 * Check the URL and remove any fragment identifier
1165 */
1166 uri = xmlParseURI((const char *)url);
1167 if (uri == NULL) {
1168 xmlGenericError(xmlGenericErrorContext,
1169 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001170 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001171 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001172 }
1173 if (uri->fragment != NULL) {
1174 fragment = (xmlChar *) uri->fragment;
1175 uri->fragment = NULL;
1176 }
1177 URL = xmlSaveUri(uri);
1178 xmlFreeURI(uri);
1179 if (URL == NULL) {
1180 xmlGenericError(xmlGenericErrorContext,
1181 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001182 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001183 if (fragment != NULL)
1184 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001185 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001186 }
1187
1188 /*
1189 * Handling of references to the local document are done
1190 * directly through ctxt->doc.
1191 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001192 if ((URL[0] == 0) || (URL[0] == '#') ||
1193 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001194 doc = NULL;
1195 goto loaded;
1196 }
1197
1198 /*
1199 * Prevent reloading twice the document.
1200 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001201 for (i = 0; i < ctxt->incNr; i++) {
1202 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1203 (ctxt->incTab[i]->doc != NULL)) {
1204 doc = ctxt->incTab[i]->doc;
1205#ifdef DEBUG_XINCLUDE
1206 printf("Already loaded %s\n", URL);
1207#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001208 goto loaded;
1209 }
1210 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001211
Owen Taylor3473f882001-02-23 17:55:21 +00001212 /*
1213 * Load it.
1214 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001215#ifdef DEBUG_XINCLUDE
1216 printf("loading %s\n", URL);
1217#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001218 doc = xmlParseFile((const char *)URL);
1219 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001220 xmlFree(URL);
1221 if (fragment != NULL)
1222 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001223 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001224 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001225 ctxt->incTab[nr]->doc = doc;
1226
1227 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001228 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001229 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001230 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001231
1232 /*
1233 * We don't need the DTD anymore, free up space
1234 if (doc->intSubset != NULL) {
1235 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1236 xmlFreeNode((xmlNodePtr) doc->intSubset);
1237 doc->intSubset = NULL;
1238 }
1239 if (doc->extSubset != NULL) {
1240 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1241 xmlFreeNode((xmlNodePtr) doc->extSubset);
1242 doc->extSubset = NULL;
1243 }
1244 */
1245 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001246
1247loaded:
1248 if (fragment == NULL) {
1249 /*
1250 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001251 */
1252 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001253 {
1254 /* Hopefully a DTD declaration won't be copied from
1255 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001256 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001257 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001258 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001259 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001260 }
Owen Taylor3473f882001-02-23 17:55:21 +00001261 } else {
1262 /*
1263 * Computes the XPointer expression and make a copy used
1264 * as the replacement copy.
1265 */
1266 xmlXPathObjectPtr xptr;
1267 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001268 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001269
1270 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001271 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1272 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001273 } else {
1274 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1275 }
1276 if (xptrctxt == NULL) {
1277 xmlGenericError(xmlGenericErrorContext,
1278 "XInclude: could create XPointer context\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001279 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001280 xmlFree(URL);
1281 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001282 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001283 }
1284 xptr = xmlXPtrEval(fragment, xptrctxt);
1285 if (xptr == NULL) {
1286 xmlGenericError(xmlGenericErrorContext,
1287 "XInclude: XPointer evaluation failed: #%s\n",
1288 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001289 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001290 xmlXPathFreeContext(xptrctxt);
1291 xmlFree(URL);
1292 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001293 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001294 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001295 switch (xptr->type) {
1296 case XPATH_UNDEFINED:
1297 case XPATH_BOOLEAN:
1298 case XPATH_NUMBER:
1299 case XPATH_STRING:
1300 case XPATH_POINT:
1301 case XPATH_USERS:
1302 case XPATH_XSLT_TREE:
1303 xmlGenericError(xmlGenericErrorContext,
1304 "XInclude: XPointer is not a range: #%s\n",
1305 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001306 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001307 xmlXPathFreeContext(xptrctxt);
1308 xmlFree(URL);
1309 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001310 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001311 case XPATH_NODESET:
1312 case XPATH_RANGE:
1313 case XPATH_LOCATIONSET:
1314 break;
1315 }
1316 set = xptr->nodesetval;
1317 if (set != NULL) {
1318 for (i = 0;i < set->nodeNr;i++) {
1319 if (set->nodeTab[i] == NULL)
1320 continue;
1321 switch (set->nodeTab[i]->type) {
1322 case XML_TEXT_NODE:
1323 case XML_CDATA_SECTION_NODE:
1324 case XML_ELEMENT_NODE:
1325 case XML_ENTITY_REF_NODE:
1326 case XML_ENTITY_NODE:
1327 case XML_PI_NODE:
1328 case XML_COMMENT_NODE:
1329 case XML_DOCUMENT_NODE:
1330 case XML_HTML_DOCUMENT_NODE:
1331#ifdef LIBXML_DOCB_ENABLED
1332 case XML_DOCB_DOCUMENT_NODE:
1333#endif
1334 continue;
1335 case XML_ATTRIBUTE_NODE:
1336 xmlGenericError(xmlGenericErrorContext,
1337 "XInclude: XPointer selects an attribute: #%s\n",
1338 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001339 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001340 set->nodeTab[i] = NULL;
1341 continue;
1342 case XML_NAMESPACE_DECL:
1343 xmlGenericError(xmlGenericErrorContext,
1344 "XInclude: XPointer selects a namespace: #%s\n",
1345 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001346 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001347 set->nodeTab[i] = NULL;
1348 continue;
1349 case XML_DOCUMENT_TYPE_NODE:
1350 case XML_DOCUMENT_FRAG_NODE:
1351 case XML_NOTATION_NODE:
1352 case XML_DTD_NODE:
1353 case XML_ELEMENT_DECL:
1354 case XML_ATTRIBUTE_DECL:
1355 case XML_ENTITY_DECL:
1356 case XML_XINCLUDE_START:
1357 case XML_XINCLUDE_END:
1358 xmlGenericError(xmlGenericErrorContext,
1359 "XInclude: XPointer selects unexpected nodes: #%s\n",
1360 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001361 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001362 set->nodeTab[i] = NULL;
1363 set->nodeTab[i] = NULL;
1364 continue; /* for */
1365 }
1366 }
1367 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001368 if (doc == NULL) {
1369 ctxt->incTab[nr]->xptr = xptr;
1370 ctxt->incTab[nr]->inc = NULL;
1371 } else {
1372 ctxt->incTab[nr]->inc =
1373 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1374 xmlXPathFreeObject(xptr);
1375 }
Owen Taylor3473f882001-02-23 17:55:21 +00001376 xmlXPathFreeContext(xptrctxt);
1377 xmlFree(fragment);
1378 }
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001379
1380 /*
1381 * Do the xml:base fixup if needed
1382 */
1383 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1384 xmlNodePtr node;
1385
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001386 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001387 while (node != NULL) {
1388 if (node->type == XML_ELEMENT_NODE)
1389 xmlNodeSetBase(node, URL);
1390 node = node->next;
1391 }
1392 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001393 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1394 (ctxt->incTab[nr]->count <= 1)) {
1395#ifdef DEBUG_XINCLUDE
1396 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1397#endif
1398 xmlFreeDoc(ctxt->incTab[nr]->doc);
1399 ctxt->incTab[nr]->doc = NULL;
1400 }
Owen Taylor3473f882001-02-23 17:55:21 +00001401 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001402 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001403}
1404
1405/**
1406 * xmlXIncludeLoadTxt:
1407 * @ctxt: the XInclude context
1408 * @url: the associated URL
1409 * @nr: the xinclude node number
1410 *
1411 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001412 *
1413 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001414 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001415static int
Owen Taylor3473f882001-02-23 17:55:21 +00001416xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1417 xmlParserInputBufferPtr buf;
1418 xmlNodePtr node;
1419 xmlURIPtr uri;
1420 xmlChar *URL;
1421 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001422 xmlChar *encoding = NULL;
1423 xmlCharEncoding enc = 0;
1424
Owen Taylor3473f882001-02-23 17:55:21 +00001425 /*
1426 * Check the URL and remove any fragment identifier
1427 */
1428 uri = xmlParseURI((const char *)url);
1429 if (uri == NULL) {
1430 xmlGenericError(xmlGenericErrorContext,
1431 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001432 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001433 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001434 }
1435 if (uri->fragment != NULL) {
1436 xmlGenericError(xmlGenericErrorContext,
1437 "XInclude: fragment identifier forbidden for text: %s\n",
1438 uri->fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001439 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001440 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001441 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001442 }
1443 URL = xmlSaveUri(uri);
1444 xmlFreeURI(uri);
1445 if (URL == NULL) {
1446 xmlGenericError(xmlGenericErrorContext,
1447 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001448 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001449 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001450 }
1451
1452 /*
1453 * Handling of references to the local document are done
1454 * directly through ctxt->doc.
1455 */
1456 if (URL[0] == 0) {
1457 xmlGenericError(xmlGenericErrorContext,
1458 "XInclude: text serialization of document not available\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001459 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001460 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001461 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001462 }
1463
1464 /*
1465 * Prevent reloading twice the document.
1466 */
1467 for (i = 0; i < ctxt->txtNr; i++) {
1468 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1469 node = xmlCopyNode(ctxt->txtTab[i], 1);
1470 goto loaded;
1471 }
1472 }
1473 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001474 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001475 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001476 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1477 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1478 }
1479 if (encoding != NULL) {
1480 /*
1481 * TODO: we should not have to remap to the xmlCharEncoding
1482 * predefined set, a better interface than
1483 * xmlParserInputBufferCreateFilename should allow any
1484 * encoding supported by iconv
1485 */
1486 enc = xmlParseCharEncoding((const char *) encoding);
1487 if (enc == XML_CHAR_ENCODING_ERROR) {
1488 xmlGenericError(xmlGenericErrorContext,
1489 "XInclude: encoding %s not supported\n", encoding);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001490 ctxt->nbErrors++;
Daniel Veillardd076a202002-11-20 13:28:31 +00001491 xmlFree(encoding);
1492 xmlFree(URL);
1493 return(-1);
1494 }
1495 xmlFree(encoding);
1496 }
1497
1498 /*
1499 * Load it.
1500 */
1501 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001502 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001503 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001504 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001505 }
1506 node = xmlNewText(NULL);
1507
1508 /*
1509 * Scan all chars from the resource and add the to the node
1510 */
1511 while (xmlParserInputBufferRead(buf, 128) > 0) {
1512 int len;
1513 const xmlChar *content;
1514
1515 content = xmlBufferContent(buf->buffer);
1516 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001517 for (i = 0;i < len;) {
1518 int cur;
1519 int l;
1520
1521 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1522 if (!IS_CHAR(cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001523 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd076a202002-11-20 13:28:31 +00001524 "XInclude: %s contains invalid char %d\n", URL, cur);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001525 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001526 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001527 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001528 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001529 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001530 }
1531 xmlBufferShrink(buf->buffer, len);
1532 }
1533 xmlFreeParserInputBuffer(buf);
1534 xmlXIncludeAddTxt(ctxt, node, URL);
1535
1536loaded:
1537 /*
1538 * Add the element as the replacement copy.
1539 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001540 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001541 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001542 return(0);
1543}
1544
1545/**
1546 * xmlXIncludeLoadFallback:
1547 * @ctxt: the XInclude context
1548 * @fallback: the fallback node
1549 * @nr: the xinclude node number
1550 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001551 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001552 * in the XInclude context
1553 *
1554 * Returns 0 in case of success, -1 in case of failure
1555 */
1556static int
1557xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1558 if ((fallback == NULL) || (ctxt == NULL))
1559 return(-1);
1560
Daniel Veillard06503452002-12-13 10:42:08 +00001561 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001562 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001563}
1564
1565/************************************************************************
1566 * *
1567 * XInclude Processing *
1568 * *
1569 ************************************************************************/
1570
1571/**
1572 * xmlXIncludePreProcessNode:
1573 * @ctxt: an XInclude context
1574 * @node: an XInclude node
1575 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001576 * Implement the XInclude preprocessing, currently just adding the element
1577 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001578 *
1579 * Returns the result list or NULL in case of error
1580 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001581static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001582xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1583 xmlXIncludeAddNode(ctxt, node);
1584 return(0);
1585}
1586
Daniel Veillard118aed72002-09-24 14:13:13 +00001587#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00001588/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001589 * xmlXIncludePreloadNode:
1590 * @ctxt: an XInclude context
1591 * @nr: the node number
1592 *
1593 * Do some precomputations and preload shared documents
1594 *
1595 * Returns 0 if substitution succeeded, -1 if some processing failed
1596 */
1597static int
1598xmlXIncludePreloadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1599 xmlNodePtr cur;
1600 xmlChar *href;
1601 xmlChar *parse;
1602 xmlChar *base;
1603 xmlChar *URI;
1604 int xml = 1; /* default Issue 64 */
1605 xmlURIPtr uri;
1606 xmlChar *URL;
1607 xmlChar *fragment = NULL;
1608 int i;
1609
1610
1611 if (ctxt == NULL)
1612 return(-1);
1613 if ((nr < 0) || (nr >= ctxt->incNr))
1614 return(-1);
1615 cur = ctxt->incTab[nr]->ref;
1616 if (cur == NULL)
1617 return(-1);
1618
1619 /*
1620 * read the attributes
1621 */
1622 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1623 if (href == NULL) {
1624 href = xmlGetProp(cur, XINCLUDE_HREF);
1625 if (href == NULL) {
1626 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1627 return(-1);
1628 }
1629 }
1630 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1631 if (parse == NULL) {
1632 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1633 }
1634 if (parse != NULL) {
1635 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1636 xml = 1;
1637 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1638 xml = 0;
1639 else {
1640 xmlGenericError(xmlGenericErrorContext,
1641 "XInclude: invalid value %s for %s\n",
1642 parse, XINCLUDE_PARSE);
1643 if (href != NULL)
1644 xmlFree(href);
1645 if (parse != NULL)
1646 xmlFree(parse);
1647 return(-1);
1648 }
1649 }
1650
1651 /*
1652 * compute the URI
1653 */
1654 base = xmlNodeGetBase(ctxt->doc, cur);
1655 if (base == NULL) {
1656 URI = xmlBuildURI(href, ctxt->doc->URL);
1657 } else {
1658 URI = xmlBuildURI(href, base);
1659 }
1660 if (URI == NULL) {
1661 xmlChar *escbase;
1662 xmlChar *eschref;
1663 /*
1664 * Some escaping may be needed
1665 */
1666 escbase = xmlURIEscape(base);
1667 eschref = xmlURIEscape(href);
1668 URI = xmlBuildURI(eschref, escbase);
1669 if (escbase != NULL)
1670 xmlFree(escbase);
1671 if (eschref != NULL)
1672 xmlFree(eschref);
1673 }
1674 if (parse != NULL)
1675 xmlFree(parse);
1676 if (href != NULL)
1677 xmlFree(href);
1678 if (base != NULL)
1679 xmlFree(base);
1680 if (URI == NULL) {
1681 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001682 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001683 return(-1);
1684 }
1685
1686 /*
1687 * Check the URL and remove any fragment identifier
1688 */
1689 uri = xmlParseURI((const char *)URI);
1690 if (uri == NULL) {
1691 xmlGenericError(xmlGenericErrorContext,
1692 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001693 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001694 xmlFree(URI);
1695 return(-1);
1696 }
1697 if (uri->fragment != NULL) {
1698 fragment = (xmlChar *) uri->fragment;
1699 uri->fragment = NULL;
1700 }
1701 URL = xmlSaveUri(uri);
1702 xmlFreeURI(uri);
1703 if (URL == NULL) {
1704 xmlGenericError(xmlGenericErrorContext,
1705 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001706 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001707 if (fragment != NULL)
1708 xmlFree(fragment);
1709 xmlFree(URI);
1710 return(-1);
1711 }
1712 xmlFree(URI);
1713 if (fragment != NULL)
1714 xmlFree(fragment);
1715
1716 for (i = 0; i < nr; i++) {
1717 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1718#ifdef DEBUG_XINCLUDE
1719 printf("Incrementing count for %d : %s\n", i, ctxt->incTab[i]->URI);
1720#endif
1721 ctxt->incTab[i]->count++;
1722 break;
1723 }
1724 }
1725 xmlFree(URL);
1726 return(0);
1727}
Daniel Veillard118aed72002-09-24 14:13:13 +00001728#endif
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001729
1730/**
Owen Taylor3473f882001-02-23 17:55:21 +00001731 * xmlXIncludeLoadNode:
1732 * @ctxt: an XInclude context
1733 * @nr: the node number
1734 *
1735 * Find and load the infoset replacement for the given node.
1736 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001737 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001738 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001739static int
Owen Taylor3473f882001-02-23 17:55:21 +00001740xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1741 xmlNodePtr cur;
1742 xmlChar *href;
1743 xmlChar *parse;
1744 xmlChar *base;
1745 xmlChar *URI;
1746 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001747 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001748
1749 if (ctxt == NULL)
1750 return(-1);
1751 if ((nr < 0) || (nr >= ctxt->incNr))
1752 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001753 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001754 if (cur == NULL)
1755 return(-1);
1756
Owen Taylor3473f882001-02-23 17:55:21 +00001757 /*
1758 * read the attributes
1759 */
1760 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1761 if (href == NULL) {
1762 href = xmlGetProp(cur, XINCLUDE_HREF);
1763 if (href == NULL) {
1764 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001765 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001766 return(-1);
1767 }
1768 }
1769 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1770 if (parse == NULL) {
1771 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1772 }
1773 if (parse != NULL) {
1774 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1775 xml = 1;
1776 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1777 xml = 0;
1778 else {
1779 xmlGenericError(xmlGenericErrorContext,
1780 "XInclude: invalid value %s for %s\n",
1781 parse, XINCLUDE_PARSE);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001782 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001783 if (href != NULL)
1784 xmlFree(href);
1785 if (parse != NULL)
1786 xmlFree(parse);
1787 return(-1);
1788 }
1789 }
1790
1791 /*
1792 * compute the URI
1793 */
1794 base = xmlNodeGetBase(ctxt->doc, cur);
1795 if (base == NULL) {
1796 URI = xmlBuildURI(href, ctxt->doc->URL);
1797 } else {
1798 URI = xmlBuildURI(href, base);
1799 }
1800 if (URI == NULL) {
1801 xmlChar *escbase;
1802 xmlChar *eschref;
1803 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001804 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001805 */
1806 escbase = xmlURIEscape(base);
1807 eschref = xmlURIEscape(href);
1808 URI = xmlBuildURI(eschref, escbase);
1809 if (escbase != NULL)
1810 xmlFree(escbase);
1811 if (eschref != NULL)
1812 xmlFree(eschref);
1813 }
1814 if (URI == NULL) {
1815 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001816 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001817 if (parse != NULL)
1818 xmlFree(parse);
1819 if (href != NULL)
1820 xmlFree(href);
1821 if (base != NULL)
1822 xmlFree(base);
1823 return(-1);
1824 }
1825#ifdef DEBUG_XINCLUDE
1826 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1827 xml ? "xml": "text");
1828 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1829#endif
1830
1831 /*
1832 * Cleanup
1833 */
1834 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001835 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001836 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1837 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001838 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1839 }
1840 if (ret < 0) {
1841 xmlNodePtr children;
1842
1843 /*
1844 * Time to try a fallback if availble
1845 */
1846#ifdef DEBUG_XINCLUDE
1847 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1848#endif
1849 children = cur->children;
1850 while (children != NULL) {
1851 if ((children->type == XML_ELEMENT_NODE) &&
1852 (children->ns != NULL) &&
1853 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1854 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1855 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1856 if (ret == 0)
1857 break;
1858 }
1859 children = children->next;
1860 }
1861 }
1862 if (ret < 0) {
1863 xmlGenericError(xmlGenericErrorContext,
1864 "XInclude: could not load %s, and no fallback was found\n",
1865 URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001866 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001867 }
1868
1869 /*
1870 * Cleanup
1871 */
1872 if (URI != NULL)
1873 xmlFree(URI);
1874 if (parse != NULL)
1875 xmlFree(parse);
1876 if (href != NULL)
1877 xmlFree(href);
1878 if (base != NULL)
1879 xmlFree(base);
1880 return(0);
1881}
1882
1883/**
1884 * xmlXIncludeIncludeNode:
1885 * @ctxt: an XInclude context
1886 * @nr: the node number
1887 *
1888 * Inplement the infoset replacement for the given node
1889 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001890 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001891 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001892static int
Owen Taylor3473f882001-02-23 17:55:21 +00001893xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001894 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001895
1896 if (ctxt == NULL)
1897 return(-1);
1898 if ((nr < 0) || (nr >= ctxt->incNr))
1899 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001900 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001901 if (cur == NULL)
1902 return(-1);
1903
1904 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001905 * If we stored an XPointer a late computation may be needed
1906 */
1907 if ((ctxt->incTab[nr]->inc == NULL) &&
1908 (ctxt->incTab[nr]->xptr != NULL)) {
1909 ctxt->incTab[nr]->inc =
1910 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1911 ctxt->incTab[nr]->xptr);
1912 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1913 ctxt->incTab[nr]->xptr = NULL;
1914 }
1915 list = ctxt->incTab[nr]->inc;
1916 ctxt->incTab[nr]->inc = NULL;
1917
1918 /*
1919 * Check against the risk of generating a multi-rooted document
1920 */
1921 if ((cur->parent != NULL) &&
1922 (cur->parent->type != XML_ELEMENT_NODE)) {
1923 int nb_elem = 0;
1924
1925 tmp = list;
1926 while (tmp != NULL) {
1927 if (tmp->type == XML_ELEMENT_NODE)
1928 nb_elem++;
1929 tmp = tmp->next;
1930 }
1931 if (nb_elem > 1) {
1932 xmlGenericError(xmlGenericErrorContext,
1933 "XInclude error: would result in multiple root nodes\n");
1934 ctxt->nbErrors++;
1935 return(-1);
1936 }
1937 }
1938
1939 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001940 * Change the current node as an XInclude start one, and add an
1941 * entity end one
1942 */
1943 cur->type = XML_XINCLUDE_START;
1944 end = xmlNewNode(cur->ns, cur->name);
1945 if (end == NULL) {
1946 xmlGenericError(xmlGenericErrorContext,
1947 "XInclude: failed to build node\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001948 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001949 return(-1);
1950 }
1951 end->type = XML_XINCLUDE_END;
1952 xmlAddNextSibling(cur, end);
1953
1954 /*
1955 * Add the list of nodes
1956 */
Owen Taylor3473f882001-02-23 17:55:21 +00001957 while (list != NULL) {
1958 cur = list;
1959 list = list->next;
1960
1961 xmlAddPrevSibling(end, cur);
1962 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001963
1964
Owen Taylor3473f882001-02-23 17:55:21 +00001965 return(0);
1966}
1967
1968/**
1969 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001970 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001971 * @node: an XInclude node
1972 *
1973 * test if the node is an XInclude node
1974 *
1975 * Returns 1 true, 0 otherwise
1976 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001977static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001978xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001979 if (node == NULL)
1980 return(0);
1981 if (node->ns == NULL)
1982 return(0);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001983 if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
1984 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
1985 xmlNodePtr child = node->children;
1986 int nb_fallback = 0;
1987
1988 while (child != NULL) {
1989 if ((child->type == XML_ELEMENT_NODE) &&
1990 (child->ns != NULL) &&
1991 (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
1992 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
1993 xmlGenericError(xmlGenericErrorContext,
1994 "XInclude: %s has an %s child\n",
1995 XINCLUDE_NODE, XINCLUDE_NODE);
1996 ctxt->nbErrors++;
1997 return(0);
1998 }
1999 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2000 nb_fallback++;
2001 }
2002 }
2003 child = child->next;
2004 }
2005 if (nb_fallback > 1) {
2006 xmlGenericError(xmlGenericErrorContext,
2007 "XInclude: %s has %d %s children\n",
2008 XINCLUDE_NODE, nb_fallback, XINCLUDE_FALLBACK);
2009 ctxt->nbErrors++;
2010 return(0);
2011 }
2012 return(1);
2013 }
2014 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2015 if ((node->parent == NULL) ||
2016 (node->parent->type != XML_ELEMENT_NODE) ||
2017 (node->parent->ns == NULL) ||
2018 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
2019 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
2020 xmlGenericError(xmlGenericErrorContext,
2021 "XInclude: %s is not the child of an %s\n",
2022 XINCLUDE_FALLBACK, XINCLUDE_NODE);
2023 ctxt->nbErrors++;
2024 }
2025 }
2026 }
Owen Taylor3473f882001-02-23 17:55:21 +00002027 return(0);
2028}
2029
2030/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002031 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002032 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002033 * @doc: an XML document
2034 *
2035 * Implement the XInclude substitution on the XML document @doc
2036 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002037 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002038 * or the number of substitutions done.
2039 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002040static int
2041xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002042 xmlNodePtr cur;
2043 int ret = 0;
2044 int i;
2045
2046 if (doc == NULL)
2047 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002048 if (ctxt == NULL)
2049 return(-1);
2050
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002051 if (doc->URL != NULL) {
2052 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2053 if (ret < 0)
2054 return(-1);
2055 }
2056
Owen Taylor3473f882001-02-23 17:55:21 +00002057 /*
2058 * First phase: lookup the elements in the document
2059 */
2060 cur = xmlDocGetRootElement(doc);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002061 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002062 xmlXIncludePreProcessNode(ctxt, cur);
2063 while (cur != NULL) {
2064 /* TODO: need to work on entities -> stack */
2065 if ((cur->children != NULL) &&
2066 (cur->children->type != XML_ENTITY_DECL)) {
2067 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002068 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002069 xmlXIncludePreProcessNode(ctxt, cur);
2070 } else if (cur->next != NULL) {
2071 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002072 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002073 xmlXIncludePreProcessNode(ctxt, cur);
2074 } else {
2075 do {
2076 cur = cur->parent;
2077 if (cur == NULL) break; /* do */
2078 if (cur->next != NULL) {
2079 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002080 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002081 xmlXIncludePreProcessNode(ctxt, cur);
2082 break; /* do */
2083 }
2084 } while (cur != NULL);
2085 }
2086 }
2087
2088 /*
2089 * Second Phase : collect the infosets fragments
2090 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002091 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002092 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002093 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002094 }
2095
2096 /*
2097 * Third phase: extend the original document infoset.
2098 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002099 if (ctxt->nbErrors == 0) {
2100 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2101 xmlXIncludeIncludeNode(ctxt, i);
2102 }
Owen Taylor3473f882001-02-23 17:55:21 +00002103 }
2104
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002105 if (doc->URL != NULL)
2106 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002107 return(ret);
2108}
2109
2110/**
2111 * xmlXIncludeProcess:
2112 * @doc: an XML document
2113 *
2114 * Implement the XInclude substitution on the XML document @doc
2115 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002116 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002117 * or the number of substitutions done.
2118 */
2119int
2120xmlXIncludeProcess(xmlDocPtr doc) {
2121 xmlXIncludeCtxtPtr ctxt;
2122 int ret = 0;
2123
2124 if (doc == NULL)
2125 return(-1);
2126 ctxt = xmlXIncludeNewContext(doc);
2127 if (ctxt == NULL)
2128 return(-1);
2129 ret = xmlXIncludeDoProcess(ctxt, doc);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00002130 if ((ret >= 0) && (ctxt->nbErrors > 0))
2131 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002132
Owen Taylor3473f882001-02-23 17:55:21 +00002133 xmlXIncludeFreeContext(ctxt);
2134 return(ret);
2135}
2136
2137#else /* !LIBXML_XINCLUDE_ENABLED */
2138#endif