blob: ad497ae072d98dbaa0c824221d2ab09918bc2a0c [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 Veillardd9b72832003-03-27 14:24:00 +0000541
542 /* urlTab may have been reallocated */
543 ctxt->urlTab = newctxt->urlTab;
544 ctxt->urlMax = newctxt->urlMax;
545
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000546 newctxt->urlMax = 0;
547 newctxt->urlNr = 0;
548 newctxt->urlTab = NULL;
549
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000550 xmlXIncludeFreeContext(newctxt);
551 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000552#ifdef DEBUG_XINCLUDE
553 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
554#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000555}
556
557/**
558 * xmlXIncludeAddTxt:
559 * @ctxt: the XInclude context
560 * @txt: the new text node
561 * @url: the associated URL
562 *
563 * Add a new txtument to the list
564 */
565static void
566xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000567#ifdef DEBUG_XINCLUDE
568 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
569#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000570 if (ctxt->txtMax == 0) {
571 ctxt->txtMax = 4;
572 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
573 sizeof(ctxt->txtTab[0]));
574 if (ctxt->txtTab == NULL) {
575 xmlGenericError(xmlGenericErrorContext,
576 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000577 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000578 return;
579 }
580 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
581 sizeof(ctxt->txturlTab[0]));
582 if (ctxt->txturlTab == NULL) {
583 xmlGenericError(xmlGenericErrorContext,
584 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000585 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000586 return;
587 }
588 }
589 if (ctxt->txtNr >= ctxt->txtMax) {
590 ctxt->txtMax *= 2;
591 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
592 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
593 if (ctxt->txtTab == NULL) {
594 xmlGenericError(xmlGenericErrorContext,
595 "realloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000596 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000597 return;
598 }
599 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000600 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000601 if (ctxt->txturlTab == NULL) {
602 xmlGenericError(xmlGenericErrorContext,
603 "realloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000604 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000605 return;
606 }
607 }
608 ctxt->txtTab[ctxt->txtNr] = txt;
609 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
610 ctxt->txtNr++;
611}
612
Owen Taylor3473f882001-02-23 17:55:21 +0000613/************************************************************************
614 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000615 * Node copy with specific semantic *
616 * *
617 ************************************************************************/
618
619/**
620 * xmlXIncludeCopyNode:
621 * @ctxt: the XInclude context
622 * @target: the document target
623 * @source: the document source
624 * @elem: the element
625 *
626 * Make a copy of the node while preserving the XInclude semantic
627 * of the Infoset copy
628 */
629static xmlNodePtr
630xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
631 xmlDocPtr source, xmlNodePtr elem) {
632 xmlNodePtr result = NULL;
633
634 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
635 (elem == NULL))
636 return(NULL);
637 if (elem->type == XML_DTD_NODE)
638 return(NULL);
639 result = xmlDocCopyNode(elem, target, 1);
640 return(result);
641}
642
643/**
644 * xmlXIncludeCopyNodeList:
645 * @ctxt: the XInclude context
646 * @target: the document target
647 * @source: the document source
648 * @elem: the element list
649 *
650 * Make a copy of the node list while preserving the XInclude semantic
651 * of the Infoset copy
652 */
653static xmlNodePtr
654xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
655 xmlDocPtr source, xmlNodePtr elem) {
656 xmlNodePtr cur, res, result = NULL, last = NULL;
657
658 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
659 (elem == NULL))
660 return(NULL);
661 cur = elem;
662 while (cur != NULL) {
663 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
664 if (res != NULL) {
665 if (result == NULL) {
666 result = last = res;
667 } else {
668 last->next = res;
669 res->prev = last;
670 last = res;
671 }
672 }
673 cur = cur->next;
674 }
675 return(result);
676}
677
678/**
679 * xmlXInclueGetNthChild:
680 * @cur: the node
681 * @no: the child number
682 *
683 * Returns the @no'th element child of @cur or NULL
684 */
685static xmlNodePtr
686xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
687 int i;
688 if (cur == NULL)
689 return(cur);
690 cur = cur->children;
691 for (i = 0;i <= no;cur = cur->next) {
692 if (cur == NULL)
693 return(cur);
694 if ((cur->type == XML_ELEMENT_NODE) ||
695 (cur->type == XML_DOCUMENT_NODE) ||
696 (cur->type == XML_HTML_DOCUMENT_NODE)) {
697 i++;
698 if (i == no)
699 break;
700 }
701 }
702 return(cur);
703}
704
705xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
706
707/**
708 * xmlXIncludeCopyRange:
709 * @ctxt: the XInclude context
710 * @target: the document target
711 * @source: the document source
712 * @obj: the XPointer result from the evaluation.
713 *
714 * Build a node list tree copy of the XPointer result.
715 *
716 * Returns an xmlNodePtr list or NULL.
717 * the caller has to free the node tree.
718 */
719static xmlNodePtr
720xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
721 xmlDocPtr source, xmlXPathObjectPtr range) {
722 /* pointers to generated nodes */
723 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
724 /* pointers to traversal nodes */
725 xmlNodePtr start, cur, end;
726 int index1, index2;
727
728 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
729 (range == NULL))
730 return(NULL);
731 if (range->type != XPATH_RANGE)
732 return(NULL);
733 start = (xmlNodePtr) range->user;
734
735 if (start == NULL)
736 return(NULL);
737 end = range->user2;
738 if (end == NULL)
739 return(xmlDocCopyNode(start, target, 1));
740
741 cur = start;
742 index1 = range->index;
743 index2 = range->index2;
744 while (cur != NULL) {
745 if (cur == end) {
746 if (cur->type == XML_TEXT_NODE) {
747 const xmlChar *content = cur->content;
748 int len;
749
750 if (content == NULL) {
751 tmp = xmlNewTextLen(NULL, 0);
752 } else {
753 len = index2;
754 if ((cur == start) && (index1 > 1)) {
755 content += (index1 - 1);
756 len -= (index1 - 1);
757 index1 = 0;
758 } else {
759 len = index2;
760 }
761 tmp = xmlNewTextLen(content, len);
762 }
763 /* single sub text node selection */
764 if (list == NULL)
765 return(tmp);
766 /* prune and return full set */
767 if (last != NULL)
768 xmlAddNextSibling(last, tmp);
769 else
770 xmlAddChild(parent, tmp);
771 return(list);
772 } else {
773 tmp = xmlDocCopyNode(cur, target, 0);
774 if (list == NULL)
775 list = tmp;
776 else {
777 if (last != NULL)
778 xmlAddNextSibling(last, tmp);
779 else
780 xmlAddChild(parent, tmp);
781 }
782 last = NULL;
783 parent = tmp;
784
785 if (index2 > 1) {
786 end = xmlXIncludeGetNthChild(cur, index2 - 1);
787 index2 = 0;
788 }
789 if ((cur == start) && (index1 > 1)) {
790 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
791 index1 = 0;
792 } else {
793 cur = cur->children;
794 }
795 /*
796 * Now gather the remaining nodes from cur to end
797 */
798 continue; /* while */
799 }
800 } else if ((cur == start) &&
801 (list == NULL) /* looks superfluous but ... */ ) {
802 if ((cur->type == XML_TEXT_NODE) ||
803 (cur->type == XML_CDATA_SECTION_NODE)) {
804 const xmlChar *content = cur->content;
805
806 if (content == NULL) {
807 tmp = xmlNewTextLen(NULL, 0);
808 } else {
809 if (index1 > 1) {
810 content += (index1 - 1);
811 }
812 tmp = xmlNewText(content);
813 }
814 last = list = tmp;
815 } else {
816 if ((cur == start) && (index1 > 1)) {
817 tmp = xmlDocCopyNode(cur, target, 0);
818 list = tmp;
819 parent = tmp;
820 last = NULL;
821 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
822 index1 = 0;
823 /*
824 * Now gather the remaining nodes from cur to end
825 */
826 continue; /* while */
827 }
828 tmp = xmlDocCopyNode(cur, target, 1);
829 list = tmp;
830 parent = NULL;
831 last = tmp;
832 }
833 } else {
834 tmp = NULL;
835 switch (cur->type) {
836 case XML_DTD_NODE:
837 case XML_ELEMENT_DECL:
838 case XML_ATTRIBUTE_DECL:
839 case XML_ENTITY_NODE:
840 /* Do not copy DTD informations */
841 break;
842 case XML_ENTITY_DECL:
843 /* handle crossing entities -> stack needed */
844 break;
845 case XML_XINCLUDE_START:
846 case XML_XINCLUDE_END:
847 /* don't consider it part of the tree content */
848 break;
849 case XML_ATTRIBUTE_NODE:
850 /* Humm, should not happen ! */
851 break;
852 default:
853 tmp = xmlDocCopyNode(cur, target, 1);
854 break;
855 }
856 if (tmp != NULL) {
857 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
858 return(NULL);
859 }
860 if (last != NULL)
861 xmlAddNextSibling(last, tmp);
862 else {
863 xmlAddChild(parent, tmp);
864 last = tmp;
865 }
866 }
867 }
868 /*
869 * Skip to next node in document order
870 */
871 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
872 return(NULL);
873 }
874 cur = xmlXPtrAdvanceNode(cur);
875 }
876 return(list);
877}
878
879/**
880 * xmlXIncludeBuildNodeList:
881 * @ctxt: the XInclude context
882 * @target: the document target
883 * @source: the document source
884 * @obj: the XPointer result from the evaluation.
885 *
886 * Build a node list tree copy of the XPointer result.
887 * This will drop Attributes and Namespace declarations.
888 *
889 * Returns an xmlNodePtr list or NULL.
890 * the caller has to free the node tree.
891 */
892static xmlNodePtr
893xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
894 xmlDocPtr source, xmlXPathObjectPtr obj) {
895 xmlNodePtr list = NULL, last = NULL;
896 int i;
897
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000898 if (source == NULL)
899 source = ctxt->doc;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000900 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
901 (obj == NULL))
902 return(NULL);
903 switch (obj->type) {
904 case XPATH_NODESET: {
905 xmlNodeSetPtr set = obj->nodesetval;
906 if (set == NULL)
907 return(NULL);
908 for (i = 0;i < set->nodeNr;i++) {
909 if (set->nodeTab[i] == NULL)
910 continue;
911 switch (set->nodeTab[i]->type) {
912 case XML_TEXT_NODE:
913 case XML_CDATA_SECTION_NODE:
914 case XML_ELEMENT_NODE:
915 case XML_ENTITY_REF_NODE:
916 case XML_ENTITY_NODE:
917 case XML_PI_NODE:
918 case XML_COMMENT_NODE:
919 case XML_DOCUMENT_NODE:
920 case XML_HTML_DOCUMENT_NODE:
921#ifdef LIBXML_DOCB_ENABLED
922 case XML_DOCB_DOCUMENT_NODE:
923#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000924 case XML_XINCLUDE_END:
925 break;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000926 case XML_XINCLUDE_START: {
927 xmlNodePtr tmp, cur = set->nodeTab[i];
928
929 cur = cur->next;
930 while (cur != NULL) {
931 switch(cur->type) {
932 case XML_TEXT_NODE:
933 case XML_CDATA_SECTION_NODE:
934 case XML_ELEMENT_NODE:
935 case XML_ENTITY_REF_NODE:
936 case XML_ENTITY_NODE:
937 case XML_PI_NODE:
938 case XML_COMMENT_NODE:
939 tmp = xmlXIncludeCopyNode(ctxt, target,
940 source, cur);
941 if (last == NULL) {
942 list = last = tmp;
943 } else {
944 xmlAddNextSibling(last, tmp);
945 last = tmp;
946 }
947 cur = cur->next;
948 continue;
949 default:
950 break;
951 }
952 break;
953 }
954 continue;
955 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000956 case XML_ATTRIBUTE_NODE:
957 case XML_NAMESPACE_DECL:
958 case XML_DOCUMENT_TYPE_NODE:
959 case XML_DOCUMENT_FRAG_NODE:
960 case XML_NOTATION_NODE:
961 case XML_DTD_NODE:
962 case XML_ELEMENT_DECL:
963 case XML_ATTRIBUTE_DECL:
964 case XML_ENTITY_DECL:
965 continue; /* for */
966 }
967 if (last == NULL)
968 list = last = xmlXIncludeCopyNode(ctxt, target, source,
969 set->nodeTab[i]);
970 else {
971 xmlAddNextSibling(last,
972 xmlXIncludeCopyNode(ctxt, target, source,
973 set->nodeTab[i]));
974 if (last->next != NULL)
975 last = last->next;
976 }
977 }
978 break;
979 }
980 case XPATH_LOCATIONSET: {
981 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
982 if (set == NULL)
983 return(NULL);
984 for (i = 0;i < set->locNr;i++) {
985 if (last == NULL)
986 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
987 set->locTab[i]);
988 else
989 xmlAddNextSibling(last,
990 xmlXIncludeCopyXPointer(ctxt, target, source,
991 set->locTab[i]));
992 if (last != NULL) {
993 while (last->next != NULL)
994 last = last->next;
995 }
996 }
997 break;
998 }
999 case XPATH_RANGE:
1000 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
1001 case XPATH_POINT:
1002 /* points are ignored in XInclude */
1003 break;
1004 default:
1005 break;
1006 }
1007 return(list);
1008}
1009/************************************************************************
1010 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001011 * XInclude I/O handling *
1012 * *
1013 ************************************************************************/
1014
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001015typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1016typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1017struct _xmlXIncludeMergeData {
1018 xmlDocPtr doc;
1019 xmlXIncludeCtxtPtr ctxt;
1020};
1021
Owen Taylor3473f882001-02-23 17:55:21 +00001022/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001023 * xmlXIncludeMergeOneEntity:
1024 * @ent: the entity
1025 * @doc: the including doc
1026 * @nr: the entity name
1027 *
1028 * Inplements the merge of one entity
1029 */
1030static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001031xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001032 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001033 xmlEntityPtr ret, prev;
1034 xmlDocPtr doc;
1035 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001036
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001037 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001038 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001039 ctxt = data->ctxt;
1040 doc = data->doc;
1041 if ((ctxt == NULL) || (doc == NULL))
1042 return;
1043 switch (ent->etype) {
1044 case XML_INTERNAL_PARAMETER_ENTITY:
1045 case XML_EXTERNAL_PARAMETER_ENTITY:
1046 case XML_INTERNAL_PREDEFINED_ENTITY:
1047 return;
1048 case XML_INTERNAL_GENERAL_ENTITY:
1049 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1050 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1051 break;
1052 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001053 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1054 ent->SystemID, ent->content);
1055 if (ret != NULL) {
1056 if (ent->URI != NULL)
1057 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001058 } else {
1059 prev = xmlGetDocEntity(doc, ent->name);
1060 if (prev != NULL) {
1061 if (ent->etype != prev->etype)
1062 goto error;
1063
1064 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1065 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1066 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001067 } else if ((ent->ExternalID != NULL) &&
1068 (prev->ExternalID != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001069 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1070 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001071 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1072 if (!xmlStrEqual(ent->content, prev->content))
1073 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001074 } else {
1075 goto error;
1076 }
1077
1078 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001079 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001080 return;
1081error:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001082 switch (ent->etype) {
1083 case XML_INTERNAL_PARAMETER_ENTITY:
1084 case XML_EXTERNAL_PARAMETER_ENTITY:
1085 case XML_INTERNAL_PREDEFINED_ENTITY:
1086 case XML_INTERNAL_GENERAL_ENTITY:
1087 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1088 return;
1089 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1090 break;
1091 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001092 xmlGenericError(xmlGenericErrorContext,
1093 "XInclude: mismatch in redefinition of entity %s\n", ent->name);
1094 ctxt->nbErrors++;
Daniel Veillard4287c572003-02-04 22:48:53 +00001095}
1096
1097/**
1098 * xmlXIncludeMergeEntities:
1099 * @ctxt: an XInclude context
1100 * @doc: the including doc
1101 * @from: the included doc
1102 *
1103 * Inplements the entity merge
1104 *
1105 * Returns 0 if merge succeeded, -1 if some processing failed
1106 */
1107static int
1108xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1109 xmlDocPtr from) {
1110 xmlNodePtr cur;
1111 xmlDtdPtr target, source;
1112
1113 if (ctxt == NULL)
1114 return(-1);
1115
1116 if ((from == NULL) || (from->intSubset == NULL))
1117 return(0);
1118
1119 target = doc->intSubset;
1120 if (target == NULL) {
1121 cur = xmlDocGetRootElement(doc);
1122 if (cur == NULL)
1123 return(-1);
1124 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1125 if (target == NULL)
1126 return(-1);
1127 }
1128
1129 source = from->intSubset;
1130 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001131 xmlXIncludeMergeData data;
1132
1133 data.ctxt = ctxt;
1134 data.doc = doc;
1135
Daniel Veillard4287c572003-02-04 22:48:53 +00001136 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001137 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001138 }
1139 source = from->extSubset;
1140 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001141 xmlXIncludeMergeData data;
1142
1143 data.ctxt = ctxt;
1144 data.doc = doc;
1145
Daniel Veillard4287c572003-02-04 22:48:53 +00001146 /*
1147 * don't duplicate existing stuff when external subsets are the same
1148 */
1149 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1150 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1151 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001152 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001153 }
1154 }
1155 return(0);
1156}
1157
1158/**
Owen Taylor3473f882001-02-23 17:55:21 +00001159 * xmlXIncludeLoadDoc:
1160 * @ctxt: the XInclude context
1161 * @url: the associated URL
1162 * @nr: the xinclude node number
1163 *
1164 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001165 *
1166 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001167 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001168static int
Owen Taylor3473f882001-02-23 17:55:21 +00001169xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1170 xmlDocPtr doc;
1171 xmlURIPtr uri;
1172 xmlChar *URL;
1173 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001174 int i = 0;
1175
1176#ifdef DEBUG_XINCLUDE
1177 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1178#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001179 /*
1180 * Check the URL and remove any fragment identifier
1181 */
1182 uri = xmlParseURI((const char *)url);
1183 if (uri == NULL) {
1184 xmlGenericError(xmlGenericErrorContext,
1185 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001186 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001187 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001188 }
1189 if (uri->fragment != NULL) {
1190 fragment = (xmlChar *) uri->fragment;
1191 uri->fragment = NULL;
1192 }
1193 URL = xmlSaveUri(uri);
1194 xmlFreeURI(uri);
1195 if (URL == NULL) {
1196 xmlGenericError(xmlGenericErrorContext,
1197 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001198 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001199 if (fragment != NULL)
1200 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001201 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001202 }
1203
1204 /*
1205 * Handling of references to the local document are done
1206 * directly through ctxt->doc.
1207 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001208 if ((URL[0] == 0) || (URL[0] == '#') ||
1209 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001210 doc = NULL;
1211 goto loaded;
1212 }
1213
1214 /*
1215 * Prevent reloading twice the document.
1216 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001217 for (i = 0; i < ctxt->incNr; i++) {
1218 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1219 (ctxt->incTab[i]->doc != NULL)) {
1220 doc = ctxt->incTab[i]->doc;
1221#ifdef DEBUG_XINCLUDE
1222 printf("Already loaded %s\n", URL);
1223#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001224 goto loaded;
1225 }
1226 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001227
Owen Taylor3473f882001-02-23 17:55:21 +00001228 /*
1229 * Load it.
1230 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001231#ifdef DEBUG_XINCLUDE
1232 printf("loading %s\n", URL);
1233#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001234 doc = xmlParseFile((const char *)URL);
1235 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001236 xmlFree(URL);
1237 if (fragment != NULL)
1238 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001239 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001240 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001241 ctxt->incTab[nr]->doc = doc;
1242
1243 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001244 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001245 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001246 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001247
1248 /*
1249 * We don't need the DTD anymore, free up space
1250 if (doc->intSubset != NULL) {
1251 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1252 xmlFreeNode((xmlNodePtr) doc->intSubset);
1253 doc->intSubset = NULL;
1254 }
1255 if (doc->extSubset != NULL) {
1256 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1257 xmlFreeNode((xmlNodePtr) doc->extSubset);
1258 doc->extSubset = NULL;
1259 }
1260 */
1261 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001262
1263loaded:
1264 if (fragment == NULL) {
1265 /*
1266 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001267 */
1268 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001269 {
1270 /* Hopefully a DTD declaration won't be copied from
1271 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001272 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001273 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001274 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001275 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001276 }
Owen Taylor3473f882001-02-23 17:55:21 +00001277 } else {
1278 /*
1279 * Computes the XPointer expression and make a copy used
1280 * as the replacement copy.
1281 */
1282 xmlXPathObjectPtr xptr;
1283 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001284 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001285
1286 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001287 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1288 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001289 } else {
1290 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1291 }
1292 if (xptrctxt == NULL) {
1293 xmlGenericError(xmlGenericErrorContext,
1294 "XInclude: could create XPointer context\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001295 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001296 xmlFree(URL);
1297 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001298 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001299 }
1300 xptr = xmlXPtrEval(fragment, xptrctxt);
1301 if (xptr == NULL) {
1302 xmlGenericError(xmlGenericErrorContext,
1303 "XInclude: XPointer evaluation failed: #%s\n",
1304 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001305 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001306 xmlXPathFreeContext(xptrctxt);
1307 xmlFree(URL);
1308 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001309 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001310 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001311 switch (xptr->type) {
1312 case XPATH_UNDEFINED:
1313 case XPATH_BOOLEAN:
1314 case XPATH_NUMBER:
1315 case XPATH_STRING:
1316 case XPATH_POINT:
1317 case XPATH_USERS:
1318 case XPATH_XSLT_TREE:
1319 xmlGenericError(xmlGenericErrorContext,
1320 "XInclude: XPointer is not a range: #%s\n",
1321 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001322 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001323 xmlXPathFreeContext(xptrctxt);
1324 xmlFree(URL);
1325 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001326 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001327 case XPATH_NODESET:
1328 case XPATH_RANGE:
1329 case XPATH_LOCATIONSET:
1330 break;
1331 }
1332 set = xptr->nodesetval;
1333 if (set != NULL) {
1334 for (i = 0;i < set->nodeNr;i++) {
1335 if (set->nodeTab[i] == NULL)
1336 continue;
1337 switch (set->nodeTab[i]->type) {
1338 case XML_TEXT_NODE:
1339 case XML_CDATA_SECTION_NODE:
1340 case XML_ELEMENT_NODE:
1341 case XML_ENTITY_REF_NODE:
1342 case XML_ENTITY_NODE:
1343 case XML_PI_NODE:
1344 case XML_COMMENT_NODE:
1345 case XML_DOCUMENT_NODE:
1346 case XML_HTML_DOCUMENT_NODE:
1347#ifdef LIBXML_DOCB_ENABLED
1348 case XML_DOCB_DOCUMENT_NODE:
1349#endif
1350 continue;
1351 case XML_ATTRIBUTE_NODE:
1352 xmlGenericError(xmlGenericErrorContext,
1353 "XInclude: XPointer selects an attribute: #%s\n",
1354 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001355 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001356 set->nodeTab[i] = NULL;
1357 continue;
1358 case XML_NAMESPACE_DECL:
1359 xmlGenericError(xmlGenericErrorContext,
1360 "XInclude: XPointer selects a namespace: #%s\n",
1361 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001362 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001363 set->nodeTab[i] = NULL;
1364 continue;
1365 case XML_DOCUMENT_TYPE_NODE:
1366 case XML_DOCUMENT_FRAG_NODE:
1367 case XML_NOTATION_NODE:
1368 case XML_DTD_NODE:
1369 case XML_ELEMENT_DECL:
1370 case XML_ATTRIBUTE_DECL:
1371 case XML_ENTITY_DECL:
1372 case XML_XINCLUDE_START:
1373 case XML_XINCLUDE_END:
1374 xmlGenericError(xmlGenericErrorContext,
1375 "XInclude: XPointer selects unexpected nodes: #%s\n",
1376 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001377 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001378 set->nodeTab[i] = NULL;
1379 set->nodeTab[i] = NULL;
1380 continue; /* for */
1381 }
1382 }
1383 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001384 if (doc == NULL) {
1385 ctxt->incTab[nr]->xptr = xptr;
1386 ctxt->incTab[nr]->inc = NULL;
1387 } else {
1388 ctxt->incTab[nr]->inc =
1389 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1390 xmlXPathFreeObject(xptr);
1391 }
Owen Taylor3473f882001-02-23 17:55:21 +00001392 xmlXPathFreeContext(xptrctxt);
1393 xmlFree(fragment);
1394 }
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001395
1396 /*
1397 * Do the xml:base fixup if needed
1398 */
1399 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1400 xmlNodePtr node;
1401
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001402 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001403 while (node != NULL) {
1404 if (node->type == XML_ELEMENT_NODE)
1405 xmlNodeSetBase(node, URL);
1406 node = node->next;
1407 }
1408 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001409 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1410 (ctxt->incTab[nr]->count <= 1)) {
1411#ifdef DEBUG_XINCLUDE
1412 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1413#endif
1414 xmlFreeDoc(ctxt->incTab[nr]->doc);
1415 ctxt->incTab[nr]->doc = NULL;
1416 }
Owen Taylor3473f882001-02-23 17:55:21 +00001417 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001418 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001419}
1420
1421/**
1422 * xmlXIncludeLoadTxt:
1423 * @ctxt: the XInclude context
1424 * @url: the associated URL
1425 * @nr: the xinclude node number
1426 *
1427 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001428 *
1429 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001430 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001431static int
Owen Taylor3473f882001-02-23 17:55:21 +00001432xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1433 xmlParserInputBufferPtr buf;
1434 xmlNodePtr node;
1435 xmlURIPtr uri;
1436 xmlChar *URL;
1437 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001438 xmlChar *encoding = NULL;
1439 xmlCharEncoding enc = 0;
1440
Owen Taylor3473f882001-02-23 17:55:21 +00001441 /*
1442 * Check the URL and remove any fragment identifier
1443 */
1444 uri = xmlParseURI((const char *)url);
1445 if (uri == 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 if (uri->fragment != NULL) {
1452 xmlGenericError(xmlGenericErrorContext,
1453 "XInclude: fragment identifier forbidden for text: %s\n",
1454 uri->fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001455 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001456 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001457 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001458 }
1459 URL = xmlSaveUri(uri);
1460 xmlFreeURI(uri);
1461 if (URL == NULL) {
1462 xmlGenericError(xmlGenericErrorContext,
1463 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001464 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001465 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001466 }
1467
1468 /*
1469 * Handling of references to the local document are done
1470 * directly through ctxt->doc.
1471 */
1472 if (URL[0] == 0) {
1473 xmlGenericError(xmlGenericErrorContext,
1474 "XInclude: text serialization of document not available\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001475 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001476 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001477 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001478 }
1479
1480 /*
1481 * Prevent reloading twice the document.
1482 */
1483 for (i = 0; i < ctxt->txtNr; i++) {
1484 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1485 node = xmlCopyNode(ctxt->txtTab[i], 1);
1486 goto loaded;
1487 }
1488 }
1489 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001490 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001491 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001492 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1493 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1494 }
1495 if (encoding != NULL) {
1496 /*
1497 * TODO: we should not have to remap to the xmlCharEncoding
1498 * predefined set, a better interface than
1499 * xmlParserInputBufferCreateFilename should allow any
1500 * encoding supported by iconv
1501 */
1502 enc = xmlParseCharEncoding((const char *) encoding);
1503 if (enc == XML_CHAR_ENCODING_ERROR) {
1504 xmlGenericError(xmlGenericErrorContext,
1505 "XInclude: encoding %s not supported\n", encoding);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001506 ctxt->nbErrors++;
Daniel Veillardd076a202002-11-20 13:28:31 +00001507 xmlFree(encoding);
1508 xmlFree(URL);
1509 return(-1);
1510 }
1511 xmlFree(encoding);
1512 }
1513
1514 /*
1515 * Load it.
1516 */
1517 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001518 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001519 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001520 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001521 }
1522 node = xmlNewText(NULL);
1523
1524 /*
1525 * Scan all chars from the resource and add the to the node
1526 */
1527 while (xmlParserInputBufferRead(buf, 128) > 0) {
1528 int len;
1529 const xmlChar *content;
1530
1531 content = xmlBufferContent(buf->buffer);
1532 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001533 for (i = 0;i < len;) {
1534 int cur;
1535 int l;
1536
1537 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1538 if (!IS_CHAR(cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001539 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd076a202002-11-20 13:28:31 +00001540 "XInclude: %s contains invalid char %d\n", URL, cur);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001541 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001542 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001543 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001544 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001545 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001546 }
1547 xmlBufferShrink(buf->buffer, len);
1548 }
1549 xmlFreeParserInputBuffer(buf);
1550 xmlXIncludeAddTxt(ctxt, node, URL);
1551
1552loaded:
1553 /*
1554 * Add the element as the replacement copy.
1555 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001556 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001557 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001558 return(0);
1559}
1560
1561/**
1562 * xmlXIncludeLoadFallback:
1563 * @ctxt: the XInclude context
1564 * @fallback: the fallback node
1565 * @nr: the xinclude node number
1566 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001567 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001568 * in the XInclude context
1569 *
1570 * Returns 0 in case of success, -1 in case of failure
1571 */
1572static int
1573xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1574 if ((fallback == NULL) || (ctxt == NULL))
1575 return(-1);
1576
Daniel Veillard06503452002-12-13 10:42:08 +00001577 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001578 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001579}
1580
1581/************************************************************************
1582 * *
1583 * XInclude Processing *
1584 * *
1585 ************************************************************************/
1586
1587/**
1588 * xmlXIncludePreProcessNode:
1589 * @ctxt: an XInclude context
1590 * @node: an XInclude node
1591 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001592 * Implement the XInclude preprocessing, currently just adding the element
1593 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001594 *
1595 * Returns the result list or NULL in case of error
1596 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001597static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001598xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1599 xmlXIncludeAddNode(ctxt, node);
1600 return(0);
1601}
1602
Daniel Veillard118aed72002-09-24 14:13:13 +00001603#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00001604/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001605 * xmlXIncludePreloadNode:
1606 * @ctxt: an XInclude context
1607 * @nr: the node number
1608 *
1609 * Do some precomputations and preload shared documents
1610 *
1611 * Returns 0 if substitution succeeded, -1 if some processing failed
1612 */
1613static int
1614xmlXIncludePreloadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1615 xmlNodePtr cur;
1616 xmlChar *href;
1617 xmlChar *parse;
1618 xmlChar *base;
1619 xmlChar *URI;
1620 int xml = 1; /* default Issue 64 */
1621 xmlURIPtr uri;
1622 xmlChar *URL;
1623 xmlChar *fragment = NULL;
1624 int i;
1625
1626
1627 if (ctxt == NULL)
1628 return(-1);
1629 if ((nr < 0) || (nr >= ctxt->incNr))
1630 return(-1);
1631 cur = ctxt->incTab[nr]->ref;
1632 if (cur == NULL)
1633 return(-1);
1634
1635 /*
1636 * read the attributes
1637 */
1638 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1639 if (href == NULL) {
1640 href = xmlGetProp(cur, XINCLUDE_HREF);
1641 if (href == NULL) {
1642 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1643 return(-1);
1644 }
1645 }
1646 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1647 if (parse == NULL) {
1648 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1649 }
1650 if (parse != NULL) {
1651 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1652 xml = 1;
1653 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1654 xml = 0;
1655 else {
1656 xmlGenericError(xmlGenericErrorContext,
1657 "XInclude: invalid value %s for %s\n",
1658 parse, XINCLUDE_PARSE);
1659 if (href != NULL)
1660 xmlFree(href);
1661 if (parse != NULL)
1662 xmlFree(parse);
1663 return(-1);
1664 }
1665 }
1666
1667 /*
1668 * compute the URI
1669 */
1670 base = xmlNodeGetBase(ctxt->doc, cur);
1671 if (base == NULL) {
1672 URI = xmlBuildURI(href, ctxt->doc->URL);
1673 } else {
1674 URI = xmlBuildURI(href, base);
1675 }
1676 if (URI == NULL) {
1677 xmlChar *escbase;
1678 xmlChar *eschref;
1679 /*
1680 * Some escaping may be needed
1681 */
1682 escbase = xmlURIEscape(base);
1683 eschref = xmlURIEscape(href);
1684 URI = xmlBuildURI(eschref, escbase);
1685 if (escbase != NULL)
1686 xmlFree(escbase);
1687 if (eschref != NULL)
1688 xmlFree(eschref);
1689 }
1690 if (parse != NULL)
1691 xmlFree(parse);
1692 if (href != NULL)
1693 xmlFree(href);
1694 if (base != NULL)
1695 xmlFree(base);
1696 if (URI == NULL) {
1697 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001698 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001699 return(-1);
1700 }
1701
1702 /*
1703 * Check the URL and remove any fragment identifier
1704 */
1705 uri = xmlParseURI((const char *)URI);
1706 if (uri == NULL) {
1707 xmlGenericError(xmlGenericErrorContext,
1708 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001709 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001710 xmlFree(URI);
1711 return(-1);
1712 }
1713 if (uri->fragment != NULL) {
1714 fragment = (xmlChar *) uri->fragment;
1715 uri->fragment = NULL;
1716 }
1717 URL = xmlSaveUri(uri);
1718 xmlFreeURI(uri);
1719 if (URL == NULL) {
1720 xmlGenericError(xmlGenericErrorContext,
1721 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001722 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001723 if (fragment != NULL)
1724 xmlFree(fragment);
1725 xmlFree(URI);
1726 return(-1);
1727 }
1728 xmlFree(URI);
1729 if (fragment != NULL)
1730 xmlFree(fragment);
1731
1732 for (i = 0; i < nr; i++) {
1733 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1734#ifdef DEBUG_XINCLUDE
1735 printf("Incrementing count for %d : %s\n", i, ctxt->incTab[i]->URI);
1736#endif
1737 ctxt->incTab[i]->count++;
1738 break;
1739 }
1740 }
1741 xmlFree(URL);
1742 return(0);
1743}
Daniel Veillard118aed72002-09-24 14:13:13 +00001744#endif
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001745
1746/**
Owen Taylor3473f882001-02-23 17:55:21 +00001747 * xmlXIncludeLoadNode:
1748 * @ctxt: an XInclude context
1749 * @nr: the node number
1750 *
1751 * Find and load the infoset replacement for the given node.
1752 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001753 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001754 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001755static int
Owen Taylor3473f882001-02-23 17:55:21 +00001756xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1757 xmlNodePtr cur;
1758 xmlChar *href;
1759 xmlChar *parse;
1760 xmlChar *base;
1761 xmlChar *URI;
1762 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001763 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001764
1765 if (ctxt == NULL)
1766 return(-1);
1767 if ((nr < 0) || (nr >= ctxt->incNr))
1768 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001769 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001770 if (cur == NULL)
1771 return(-1);
1772
Owen Taylor3473f882001-02-23 17:55:21 +00001773 /*
1774 * read the attributes
1775 */
1776 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1777 if (href == NULL) {
1778 href = xmlGetProp(cur, XINCLUDE_HREF);
1779 if (href == NULL) {
1780 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001781 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001782 return(-1);
1783 }
1784 }
1785 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1786 if (parse == NULL) {
1787 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1788 }
1789 if (parse != NULL) {
1790 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1791 xml = 1;
1792 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1793 xml = 0;
1794 else {
1795 xmlGenericError(xmlGenericErrorContext,
1796 "XInclude: invalid value %s for %s\n",
1797 parse, XINCLUDE_PARSE);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001798 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001799 if (href != NULL)
1800 xmlFree(href);
1801 if (parse != NULL)
1802 xmlFree(parse);
1803 return(-1);
1804 }
1805 }
1806
1807 /*
1808 * compute the URI
1809 */
1810 base = xmlNodeGetBase(ctxt->doc, cur);
1811 if (base == NULL) {
1812 URI = xmlBuildURI(href, ctxt->doc->URL);
1813 } else {
1814 URI = xmlBuildURI(href, base);
1815 }
1816 if (URI == NULL) {
1817 xmlChar *escbase;
1818 xmlChar *eschref;
1819 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001820 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001821 */
1822 escbase = xmlURIEscape(base);
1823 eschref = xmlURIEscape(href);
1824 URI = xmlBuildURI(eschref, escbase);
1825 if (escbase != NULL)
1826 xmlFree(escbase);
1827 if (eschref != NULL)
1828 xmlFree(eschref);
1829 }
1830 if (URI == NULL) {
1831 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001832 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001833 if (parse != NULL)
1834 xmlFree(parse);
1835 if (href != NULL)
1836 xmlFree(href);
1837 if (base != NULL)
1838 xmlFree(base);
1839 return(-1);
1840 }
1841#ifdef DEBUG_XINCLUDE
1842 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1843 xml ? "xml": "text");
1844 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1845#endif
1846
1847 /*
1848 * Cleanup
1849 */
1850 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001851 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001852 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1853 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001854 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1855 }
1856 if (ret < 0) {
1857 xmlNodePtr children;
1858
1859 /*
1860 * Time to try a fallback if availble
1861 */
1862#ifdef DEBUG_XINCLUDE
1863 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1864#endif
1865 children = cur->children;
1866 while (children != NULL) {
1867 if ((children->type == XML_ELEMENT_NODE) &&
1868 (children->ns != NULL) &&
1869 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1870 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1871 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1872 if (ret == 0)
1873 break;
1874 }
1875 children = children->next;
1876 }
1877 }
1878 if (ret < 0) {
1879 xmlGenericError(xmlGenericErrorContext,
1880 "XInclude: could not load %s, and no fallback was found\n",
1881 URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001882 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001883 }
1884
1885 /*
1886 * Cleanup
1887 */
1888 if (URI != NULL)
1889 xmlFree(URI);
1890 if (parse != NULL)
1891 xmlFree(parse);
1892 if (href != NULL)
1893 xmlFree(href);
1894 if (base != NULL)
1895 xmlFree(base);
1896 return(0);
1897}
1898
1899/**
1900 * xmlXIncludeIncludeNode:
1901 * @ctxt: an XInclude context
1902 * @nr: the node number
1903 *
1904 * Inplement the infoset replacement for the given node
1905 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001906 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001907 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001908static int
Owen Taylor3473f882001-02-23 17:55:21 +00001909xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001910 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001911
1912 if (ctxt == NULL)
1913 return(-1);
1914 if ((nr < 0) || (nr >= ctxt->incNr))
1915 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001916 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001917 if (cur == NULL)
1918 return(-1);
1919
1920 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001921 * If we stored an XPointer a late computation may be needed
1922 */
1923 if ((ctxt->incTab[nr]->inc == NULL) &&
1924 (ctxt->incTab[nr]->xptr != NULL)) {
1925 ctxt->incTab[nr]->inc =
1926 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1927 ctxt->incTab[nr]->xptr);
1928 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1929 ctxt->incTab[nr]->xptr = NULL;
1930 }
1931 list = ctxt->incTab[nr]->inc;
1932 ctxt->incTab[nr]->inc = NULL;
1933
1934 /*
1935 * Check against the risk of generating a multi-rooted document
1936 */
1937 if ((cur->parent != NULL) &&
1938 (cur->parent->type != XML_ELEMENT_NODE)) {
1939 int nb_elem = 0;
1940
1941 tmp = list;
1942 while (tmp != NULL) {
1943 if (tmp->type == XML_ELEMENT_NODE)
1944 nb_elem++;
1945 tmp = tmp->next;
1946 }
1947 if (nb_elem > 1) {
1948 xmlGenericError(xmlGenericErrorContext,
1949 "XInclude error: would result in multiple root nodes\n");
1950 ctxt->nbErrors++;
1951 return(-1);
1952 }
1953 }
1954
1955 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001956 * Change the current node as an XInclude start one, and add an
1957 * entity end one
1958 */
1959 cur->type = XML_XINCLUDE_START;
1960 end = xmlNewNode(cur->ns, cur->name);
1961 if (end == NULL) {
1962 xmlGenericError(xmlGenericErrorContext,
1963 "XInclude: failed to build node\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001964 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001965 return(-1);
1966 }
1967 end->type = XML_XINCLUDE_END;
1968 xmlAddNextSibling(cur, end);
1969
1970 /*
1971 * Add the list of nodes
1972 */
Owen Taylor3473f882001-02-23 17:55:21 +00001973 while (list != NULL) {
1974 cur = list;
1975 list = list->next;
1976
1977 xmlAddPrevSibling(end, cur);
1978 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001979
1980
Owen Taylor3473f882001-02-23 17:55:21 +00001981 return(0);
1982}
1983
1984/**
1985 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001986 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001987 * @node: an XInclude node
1988 *
1989 * test if the node is an XInclude node
1990 *
1991 * Returns 1 true, 0 otherwise
1992 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001993static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001994xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001995 if (node == NULL)
1996 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00001997 if (node->type != XML_ELEMENT_NODE)
1998 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001999 if (node->ns == NULL)
2000 return(0);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002001 if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
2002 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2003 xmlNodePtr child = node->children;
2004 int nb_fallback = 0;
2005
2006 while (child != NULL) {
2007 if ((child->type == XML_ELEMENT_NODE) &&
2008 (child->ns != NULL) &&
2009 (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
2010 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
2011 xmlGenericError(xmlGenericErrorContext,
2012 "XInclude: %s has an %s child\n",
2013 XINCLUDE_NODE, XINCLUDE_NODE);
2014 ctxt->nbErrors++;
2015 return(0);
2016 }
2017 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2018 nb_fallback++;
2019 }
2020 }
2021 child = child->next;
2022 }
2023 if (nb_fallback > 1) {
2024 xmlGenericError(xmlGenericErrorContext,
2025 "XInclude: %s has %d %s children\n",
2026 XINCLUDE_NODE, nb_fallback, XINCLUDE_FALLBACK);
2027 ctxt->nbErrors++;
2028 return(0);
2029 }
2030 return(1);
2031 }
2032 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2033 if ((node->parent == NULL) ||
2034 (node->parent->type != XML_ELEMENT_NODE) ||
2035 (node->parent->ns == NULL) ||
2036 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
2037 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
2038 xmlGenericError(xmlGenericErrorContext,
2039 "XInclude: %s is not the child of an %s\n",
2040 XINCLUDE_FALLBACK, XINCLUDE_NODE);
2041 ctxt->nbErrors++;
2042 }
2043 }
2044 }
Owen Taylor3473f882001-02-23 17:55:21 +00002045 return(0);
2046}
2047
2048/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002049 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002050 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002051 * @doc: an XML document
2052 *
2053 * Implement the XInclude substitution on the XML document @doc
2054 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002055 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002056 * or the number of substitutions done.
2057 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002058static int
2059xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002060 xmlNodePtr cur;
2061 int ret = 0;
2062 int i;
2063
2064 if (doc == NULL)
2065 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002066 if (ctxt == NULL)
2067 return(-1);
2068
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002069 if (doc->URL != NULL) {
2070 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2071 if (ret < 0)
2072 return(-1);
2073 }
2074
Owen Taylor3473f882001-02-23 17:55:21 +00002075 /*
2076 * First phase: lookup the elements in the document
2077 */
2078 cur = xmlDocGetRootElement(doc);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002079 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002080 xmlXIncludePreProcessNode(ctxt, cur);
2081 while (cur != NULL) {
2082 /* TODO: need to work on entities -> stack */
2083 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002084 (cur->children->type != XML_ENTITY_DECL) &&
2085 (cur->children->type != XML_XINCLUDE_START) &&
2086 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002087 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002088 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002089 xmlXIncludePreProcessNode(ctxt, cur);
2090 } else if (cur->next != NULL) {
2091 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002092 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002093 xmlXIncludePreProcessNode(ctxt, cur);
2094 } else {
2095 do {
2096 cur = cur->parent;
2097 if (cur == NULL) break; /* do */
2098 if (cur->next != NULL) {
2099 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002100 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002101 xmlXIncludePreProcessNode(ctxt, cur);
2102 break; /* do */
2103 }
2104 } while (cur != NULL);
2105 }
2106 }
2107
2108 /*
2109 * Second Phase : collect the infosets fragments
2110 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002111 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002112 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002113 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002114 }
2115
2116 /*
2117 * Third phase: extend the original document infoset.
2118 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002119 if (ctxt->nbErrors == 0) {
2120 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2121 xmlXIncludeIncludeNode(ctxt, i);
2122 }
Owen Taylor3473f882001-02-23 17:55:21 +00002123 }
2124
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002125 if (doc->URL != NULL)
2126 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002127 return(ret);
2128}
2129
2130/**
2131 * xmlXIncludeProcess:
2132 * @doc: an XML document
2133 *
2134 * Implement the XInclude substitution on the XML document @doc
2135 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002136 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002137 * or the number of substitutions done.
2138 */
2139int
2140xmlXIncludeProcess(xmlDocPtr doc) {
2141 xmlXIncludeCtxtPtr ctxt;
2142 int ret = 0;
2143
2144 if (doc == NULL)
2145 return(-1);
2146 ctxt = xmlXIncludeNewContext(doc);
2147 if (ctxt == NULL)
2148 return(-1);
2149 ret = xmlXIncludeDoProcess(ctxt, doc);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00002150 if ((ret >= 0) && (ctxt->nbErrors > 0))
2151 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002152
Owen Taylor3473f882001-02-23 17:55:21 +00002153 xmlXIncludeFreeContext(ctxt);
2154 return(ret);
2155}
2156
2157#else /* !LIBXML_XINCLUDE_ENABLED */
2158#endif