blob: f4d6aee36752684814552755e7c266ef718996c3 [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
Daniel Veillard34ce8be2002-03-18 19:37:11 +000012#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000013#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000014
Owen Taylor3473f882001-02-23 17:55:21 +000015#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/tree.h>
18#include <libxml/parser.h>
19#include <libxml/uri.h>
20#include <libxml/xpointer.h>
21#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <libxml/xmlerror.h>
Daniel Veillardd076a202002-11-20 13:28:31 +000023#include <libxml/encoding.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000024#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000025
26#ifdef LIBXML_XINCLUDE_ENABLED
27#include <libxml/xinclude.h>
28
Owen Taylor3473f882001-02-23 17:55:21 +000029
Daniel Veillardf4b4f982003-02-13 11:02:08 +000030#define XINCLUDE_MAX_DEPTH 40
31
Daniel Veillard98485322003-08-14 15:44:40 +000032/* #define DEBUG_XINCLUDE */
Daniel Veillard017b1082001-06-21 11:20:21 +000033#ifdef DEBUG_XINCLUDE
34#ifdef LIBXML_DEBUG_ENABLED
35#include <libxml/debugXML.h>
36#endif
37#endif
Owen Taylor3473f882001-02-23 17:55:21 +000038
39/************************************************************************
40 * *
41 * XInclude contexts handling *
42 * *
43 ************************************************************************/
44
45/*
46 * An XInclude context
47 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000048typedef xmlChar *xmlURL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +000049
50typedef struct _xmlXIncludeRef xmlXIncludeRef;
51typedef xmlXIncludeRef *xmlXIncludeRefPtr;
52struct _xmlXIncludeRef {
53 xmlChar *URI; /* the rully resolved resource URL */
54 xmlChar *fragment; /* the fragment in the URI */
55 xmlDocPtr doc; /* the parsed document */
56 xmlNodePtr ref; /* the node making the reference in the source */
57 xmlNodePtr inc; /* the included copy */
58 int xml; /* xml or txt */
59 int count; /* how many refs use that specific doc */
Daniel Veillardf4b4f982003-02-13 11:02:08 +000060 xmlXPathObjectPtr xptr; /* the xpointer if needed */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000061};
62
Owen Taylor3473f882001-02-23 17:55:21 +000063struct _xmlXIncludeCtxt {
64 xmlDocPtr doc; /* the source document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000065 int incBase; /* the first include for this document */
Owen Taylor3473f882001-02-23 17:55:21 +000066 int incNr; /* number of includes */
67 int incMax; /* size of includes tab */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000068 xmlXIncludeRefPtr *incTab; /* array of included references */
69
Owen Taylor3473f882001-02-23 17:55:21 +000070 int txtNr; /* number of unparsed documents */
71 int txtMax; /* size of unparsed documents tab */
72 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000073 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Daniel Veillardd581b7e2003-02-11 18:03:05 +000074
Daniel Veillardf4b4f982003-02-13 11:02:08 +000075 xmlChar * url; /* the current URL processed */
76 int urlNr; /* number of url stacked */
77 int urlMax; /* size of url stack */
78 xmlChar * *urlTab; /* url stack */
79
Daniel Veillardd581b7e2003-02-11 18:03:05 +000080 int nbErrors; /* the number of errors detected */
Owen Taylor3473f882001-02-23 17:55:21 +000081};
82
Daniel Veillardd16df9f2001-05-23 13:44:21 +000083static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +000084xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
Owen Taylor3473f882001-02-23 17:55:21 +000085
Daniel Veillard98485322003-08-14 15:44:40 +000086
Daniel Veillardcd6ff282003-10-08 22:38:13 +000087/************************************************************************
88 * *
Daniel Veillard69d2c172003-10-09 11:46:07 +000089 * XInclude error handler *
Daniel Veillardcd6ff282003-10-08 22:38:13 +000090 * *
91 ************************************************************************/
92
Daniel Veillard98485322003-08-14 15:44:40 +000093/**
Daniel Veillardcd6ff282003-10-08 22:38:13 +000094 * xmlXIncludeErrMemory:
95 * @extra: extra informations
Daniel Veillard98485322003-08-14 15:44:40 +000096 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +000097 * Handle an out of memory condition
Daniel Veillard98485322003-08-14 15:44:40 +000098 */
99static void
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000100xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
101 const char *extra)
Daniel Veillard98485322003-08-14 15:44:40 +0000102{
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000103 if (ctxt != NULL)
104 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000105 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000106 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
107 extra, NULL, NULL, 0, 0,
108 "Memory allocation failed : %s\n", extra);
109}
Daniel Veillard98485322003-08-14 15:44:40 +0000110
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000111/**
112 * xmlXIncludeErr:
113 * @ctxt: the XInclude context
114 * @node: the context node
115 * @msg: the error message
116 * @extra: extra informations
117 *
118 * Handle a resource access error
119 */
120static void
121xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
122 const char *msg, const xmlChar *extra)
123{
124 if (ctxt != NULL)
125 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000126 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000127 error, XML_ERR_ERROR, NULL, 0,
128 (const char *) extra, NULL, NULL, 0, 0,
129 msg, (const char *) extra);
Daniel Veillard98485322003-08-14 15:44:40 +0000130}
131
Owen Taylor3473f882001-02-23 17:55:21 +0000132/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000133 * xmlXIncludeFreeRef:
134 * @ref: the XInclude reference
135 *
136 * Free an XInclude reference
137 */
138static void
139xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
140 if (ref == NULL)
141 return;
142#ifdef DEBUG_XINCLUDE
143 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
144#endif
145 if (ref->doc != NULL) {
146#ifdef DEBUG_XINCLUDE
147 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
148#endif
149 xmlFreeDoc(ref->doc);
150 }
151 if (ref->URI != NULL)
152 xmlFree(ref->URI);
153 if (ref->fragment != NULL)
154 xmlFree(ref->fragment);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000155 if (ref->xptr != NULL)
156 xmlXPathFreeObject(ref->xptr);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000157 xmlFree(ref);
158}
159
160/**
161 * xmlXIncludeNewRef:
162 * @ctxt: the XInclude context
163 * @URI: the resource URI
164 *
165 * Creates a new reference within an XInclude context
166 *
167 * Returns the new set
168 */
169static xmlXIncludeRefPtr
170xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
171 xmlNodePtr ref) {
172 xmlXIncludeRefPtr ret;
173
174#ifdef DEBUG_XINCLUDE
175 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
176#endif
177 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000178 if (ret == NULL) {
179 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000180 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000181 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000182 memset(ret, 0, sizeof(xmlXIncludeRef));
183 if (URI == NULL)
184 ret->URI = NULL;
185 else
186 ret->URI = xmlStrdup(URI);
187 ret->fragment = NULL;
188 ret->ref = ref;
189 ret->doc = 0;
190 ret->count = 0;
191 ret->xml = 0;
192 ret->inc = NULL;
193 if (ctxt->incMax == 0) {
194 ctxt->incMax = 4;
195 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
196 sizeof(ctxt->incTab[0]));
197 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000198 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000199 xmlXIncludeFreeRef(ret);
200 return(NULL);
201 }
202 }
203 if (ctxt->incNr >= ctxt->incMax) {
204 ctxt->incMax *= 2;
205 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
206 ctxt->incMax * sizeof(ctxt->incTab[0]));
207 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000208 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000209 xmlXIncludeFreeRef(ret);
210 return(NULL);
211 }
212 }
213 ctxt->incTab[ctxt->incNr++] = ret;
214 return(ret);
215}
216
217/**
Owen Taylor3473f882001-02-23 17:55:21 +0000218 * xmlXIncludeNewContext:
219 * @doc: an XML Document
220 *
221 * Creates a new XInclude context
222 *
223 * Returns the new set
224 */
Daniel Veillard7899c5c2003-11-03 12:31:38 +0000225xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000226xmlXIncludeNewContext(xmlDocPtr doc) {
227 xmlXIncludeCtxtPtr ret;
228
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000229#ifdef DEBUG_XINCLUDE
230 xmlGenericError(xmlGenericErrorContext, "New context\n");
231#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000232 if (doc == NULL)
233 return(NULL);
234 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000235 if (ret == NULL) {
236 xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
237 "creating XInclude context");
Owen Taylor3473f882001-02-23 17:55:21 +0000238 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000239 }
Owen Taylor3473f882001-02-23 17:55:21 +0000240 memset(ret, 0, sizeof(xmlXIncludeCtxt));
241 ret->doc = doc;
242 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000243 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000244 ret->incMax = 0;
245 ret->incTab = NULL;
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000246 ret->nbErrors = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000247 return(ret);
248}
249
250/**
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000251 * xmlXIncludeURLPush:
252 * @ctxt: the parser context
253 * @value: the url
254 *
255 * Pushes a new url on top of the url stack
256 *
257 * Returns -1 in case of error, the index in the stack otherwise
258 */
259static int
260xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
261 const xmlChar *value)
262{
263 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000264 xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
265 "detected a recursion in %s\n", value);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000266 return(-1);
267 }
268 if (ctxt->urlTab == NULL) {
269 ctxt->urlMax = 4;
270 ctxt->urlNr = 0;
271 ctxt->urlTab = (xmlChar * *) xmlMalloc(
272 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
273 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000274 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000275 return (-1);
276 }
277 }
278 if (ctxt->urlNr >= ctxt->urlMax) {
279 ctxt->urlMax *= 2;
280 ctxt->urlTab =
281 (xmlChar * *) xmlRealloc(ctxt->urlTab,
282 ctxt->urlMax *
283 sizeof(ctxt->urlTab[0]));
284 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000285 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000286 return (-1);
287 }
288 }
289 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
290 return (ctxt->urlNr++);
291}
292
293/**
294 * xmlXIncludeURLPop:
295 * @ctxt: the parser context
296 *
297 * Pops the top url from the url stack
298 */
299static void
300xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
301{
302 xmlChar * ret;
303
304 if (ctxt->urlNr <= 0)
305 return;
306 ctxt->urlNr--;
307 if (ctxt->urlNr > 0)
308 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
309 else
310 ctxt->url = NULL;
311 ret = ctxt->urlTab[ctxt->urlNr];
312 ctxt->urlTab[ctxt->urlNr] = 0;
313 if (ret != NULL)
314 xmlFree(ret);
315}
316
317/**
Owen Taylor3473f882001-02-23 17:55:21 +0000318 * xmlXIncludeFreeContext:
319 * @ctxt: the XInclude context
320 *
321 * Free an XInclude context
322 */
Daniel Veillard7899c5c2003-11-03 12:31:38 +0000323void
Owen Taylor3473f882001-02-23 17:55:21 +0000324xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
325 int i;
326
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000327#ifdef DEBUG_XINCLUDE
328 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
329#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000330 if (ctxt == NULL)
331 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000332 while (ctxt->urlNr > 0)
333 xmlXIncludeURLPop(ctxt);
334 if (ctxt->urlTab != NULL)
335 xmlFree(ctxt->urlTab);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000336 for (i = 0;i < ctxt->incNr;i++) {
337 if (ctxt->incTab[i] != NULL)
338 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000339 }
340 for (i = 0;i < ctxt->txtNr;i++) {
341 if (ctxt->txturlTab[i] != NULL)
342 xmlFree(ctxt->txturlTab[i]);
343 }
344 if (ctxt->incTab != NULL)
345 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000346 if (ctxt->txtTab != NULL)
347 xmlFree(ctxt->txtTab);
348 if (ctxt->txturlTab != NULL)
349 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000350 xmlFree(ctxt);
351}
352
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000353/**
Daniel Veillard98485322003-08-14 15:44:40 +0000354 * xmlXIncludeParseFile:
355 * @ctxt: the XInclude context
356 * @URL: the URL or file path
357 *
358 * parse an document for XInclude
359 */
360static xmlDocPtr
361xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt ATTRIBUTE_UNUSED, const char *URL) {
362 xmlDocPtr ret;
363 xmlParserCtxtPtr pctxt;
364 char *directory = NULL;
365
366 xmlInitParser();
367
368 pctxt = xmlCreateFileParserCtxt(URL);
369 if (pctxt == NULL) {
370 return(NULL);
371 }
372
373 if ((pctxt->directory == NULL) && (directory == NULL))
374 directory = xmlParserGetDirectory(URL);
375 if ((pctxt->directory == NULL) && (directory != NULL))
376 pctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
377
378 pctxt->loadsubset = XML_DETECT_IDS;
379
380 xmlParseDocument(pctxt);
381
382 if (pctxt->wellFormed)
383 ret = pctxt->myDoc;
384 else {
385 ret = NULL;
386 xmlFreeDoc(pctxt->myDoc);
387 pctxt->myDoc = NULL;
388 }
389 xmlFreeParserCtxt(pctxt);
390
391 return(ret);
392}
393
394/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000395 * xmlXIncludeAddNode:
396 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000397 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000398 *
399 * Add a new node to process to an XInclude context
400 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000401static int
402xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
403 xmlXIncludeRefPtr ref;
404 xmlURIPtr uri;
405 xmlChar *URL;
406 xmlChar *fragment = NULL;
407 xmlChar *href;
408 xmlChar *parse;
409 xmlChar *base;
410 xmlChar *URI;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000411 int xml = 1, i; /* default Issue 64 */
412 int local = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000413
414
415 if (ctxt == NULL)
416 return(-1);
417 if (cur == NULL)
418 return(-1);
419
420#ifdef DEBUG_XINCLUDE
421 xmlGenericError(xmlGenericErrorContext, "Add node\n");
422#endif
423 /*
424 * read the attributes
425 */
426 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
427 if (href == NULL) {
428 href = xmlGetProp(cur, XINCLUDE_HREF);
429 if (href == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000430 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_NO_HREF,
431 "no href\n", NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000432 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000433 }
434 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000435 if (href[0] == '#')
436 local = 1;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000437 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
438 if (parse == NULL) {
439 parse = xmlGetProp(cur, XINCLUDE_PARSE);
440 }
441 if (parse != NULL) {
442 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
443 xml = 1;
444 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
445 xml = 0;
446 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000447 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
448 "invalid value %s for 'parse'\n", parse);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000449 if (href != NULL)
450 xmlFree(href);
451 if (parse != NULL)
452 xmlFree(parse);
453 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000454 }
455 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000456
457 /*
458 * compute the URI
459 */
460 base = xmlNodeGetBase(ctxt->doc, cur);
461 if (base == NULL) {
462 URI = xmlBuildURI(href, ctxt->doc->URL);
463 } else {
464 URI = xmlBuildURI(href, base);
465 }
466 if (URI == NULL) {
467 xmlChar *escbase;
468 xmlChar *eschref;
469 /*
470 * Some escaping may be needed
471 */
472 escbase = xmlURIEscape(base);
473 eschref = xmlURIEscape(href);
474 URI = xmlBuildURI(eschref, escbase);
475 if (escbase != NULL)
476 xmlFree(escbase);
477 if (eschref != NULL)
478 xmlFree(eschref);
479 }
480 if (parse != NULL)
481 xmlFree(parse);
482 if (href != NULL)
483 xmlFree(href);
484 if (base != NULL)
485 xmlFree(base);
486 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000487 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
488 "failed build URL\n", NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000489 return(-1);
490 }
491
492 /*
493 * Check the URL and remove any fragment identifier
494 */
495 uri = xmlParseURI((const char *)URI);
496 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000497 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
498 "invalid value URI %s\n", URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000499 return(-1);
500 }
501 if (uri->fragment != NULL) {
502 fragment = (xmlChar *) uri->fragment;
503 uri->fragment = NULL;
504 }
505 URL = xmlSaveUri(uri);
506 xmlFreeURI(uri);
507 xmlFree(URI);
508 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000509 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
510 "invalid value URI %s\n", URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000511 if (fragment != NULL)
512 xmlFree(fragment);
513 return(-1);
514 }
515
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000516 /*
517 * Check the URL against the stack for recursions
518 */
519 if (!local) {
520 for (i = 0;i < ctxt->urlNr;i++) {
521 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000522 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
523 "detected a recursion in %s\n", URL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000524 return(-1);
525 }
526 }
527 }
528
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000529 ref = xmlXIncludeNewRef(ctxt, URL, cur);
530 if (ref == NULL) {
531 return(-1);
532 }
533 ref->fragment = fragment;
534 ref->doc = NULL;
535 ref->xml = xml;
536 ref->count = 1;
537 xmlFree(URL);
538 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000539}
540
541/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000542 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000543 * @ctxt: the XInclude context
544 * @doc: the new document
545 * @url: the associated URL
546 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000547 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000548 */
549static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000550xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000551 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000552 xmlXIncludeCtxtPtr newctxt;
553 int i;
554
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000555 /*
556 * Avoid recursion in already substitued resources
557 for (i = 0;i < ctxt->urlNr;i++) {
558 if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
559 return;
560 }
561 */
562
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000563#ifdef DEBUG_XINCLUDE
564 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
565#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000566 /*
567 * Handle recursion here.
568 */
569
570 newctxt = xmlXIncludeNewContext(doc);
571 if (newctxt != NULL) {
572 /*
573 * Copy the existing document set
574 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000575 newctxt->incMax = ctxt->incMax;
576 newctxt->incNr = ctxt->incNr;
577 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
578 sizeof(newctxt->incTab[0]));
579 if (newctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000580 xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000581 xmlFree(newctxt);
582 return;
583 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000584 /*
585 * copy the urlTab
586 */
587 newctxt->urlMax = ctxt->urlMax;
588 newctxt->urlNr = ctxt->urlNr;
589 newctxt->urlTab = ctxt->urlTab;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000590
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000591 /*
592 * Inherit the documents already in use by others includes
593 */
594 newctxt->incBase = ctxt->incNr;
595 for (i = 0;i < ctxt->incNr;i++) {
596 newctxt->incTab[i] = ctxt->incTab[i];
597 newctxt->incTab[i]->count++; /* prevent the recursion from
598 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000599 }
Daniel Veillard8edf1c52003-07-22 20:52:14 +0000600 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000601 for (i = 0;i < ctxt->incNr;i++) {
602 newctxt->incTab[i]->count--;
603 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000604 }
Daniel Veillardd9b72832003-03-27 14:24:00 +0000605
606 /* urlTab may have been reallocated */
607 ctxt->urlTab = newctxt->urlTab;
608 ctxt->urlMax = newctxt->urlMax;
609
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000610 newctxt->urlMax = 0;
611 newctxt->urlNr = 0;
612 newctxt->urlTab = NULL;
613
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000614 xmlXIncludeFreeContext(newctxt);
615 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000616#ifdef DEBUG_XINCLUDE
617 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
618#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000619}
620
621/**
622 * xmlXIncludeAddTxt:
623 * @ctxt: the XInclude context
624 * @txt: the new text node
625 * @url: the associated URL
626 *
627 * Add a new txtument to the list
628 */
629static void
630xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000631#ifdef DEBUG_XINCLUDE
632 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
633#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000634 if (ctxt->txtMax == 0) {
635 ctxt->txtMax = 4;
636 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
637 sizeof(ctxt->txtTab[0]));
638 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000639 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000640 return;
641 }
642 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
643 sizeof(ctxt->txturlTab[0]));
644 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000645 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000646 return;
647 }
648 }
649 if (ctxt->txtNr >= ctxt->txtMax) {
650 ctxt->txtMax *= 2;
651 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
652 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
653 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000654 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000655 return;
656 }
657 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000658 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000659 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000660 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000661 return;
662 }
663 }
664 ctxt->txtTab[ctxt->txtNr] = txt;
665 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
666 ctxt->txtNr++;
667}
668
Owen Taylor3473f882001-02-23 17:55:21 +0000669/************************************************************************
670 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000671 * Node copy with specific semantic *
672 * *
673 ************************************************************************/
674
675/**
676 * xmlXIncludeCopyNode:
677 * @ctxt: the XInclude context
678 * @target: the document target
679 * @source: the document source
680 * @elem: the element
681 *
682 * Make a copy of the node while preserving the XInclude semantic
683 * of the Infoset copy
684 */
685static xmlNodePtr
686xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
687 xmlDocPtr source, xmlNodePtr elem) {
688 xmlNodePtr result = NULL;
689
690 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
691 (elem == NULL))
692 return(NULL);
693 if (elem->type == XML_DTD_NODE)
694 return(NULL);
695 result = xmlDocCopyNode(elem, target, 1);
696 return(result);
697}
698
699/**
700 * xmlXIncludeCopyNodeList:
701 * @ctxt: the XInclude context
702 * @target: the document target
703 * @source: the document source
704 * @elem: the element list
705 *
706 * Make a copy of the node list while preserving the XInclude semantic
707 * of the Infoset copy
708 */
709static xmlNodePtr
710xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
711 xmlDocPtr source, xmlNodePtr elem) {
712 xmlNodePtr cur, res, result = NULL, last = NULL;
713
714 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
715 (elem == NULL))
716 return(NULL);
717 cur = elem;
718 while (cur != NULL) {
719 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
720 if (res != NULL) {
721 if (result == NULL) {
722 result = last = res;
723 } else {
724 last->next = res;
725 res->prev = last;
726 last = res;
727 }
728 }
729 cur = cur->next;
730 }
731 return(result);
732}
733
734/**
735 * xmlXInclueGetNthChild:
736 * @cur: the node
737 * @no: the child number
738 *
739 * Returns the @no'th element child of @cur or NULL
740 */
741static xmlNodePtr
742xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
743 int i;
744 if (cur == NULL)
745 return(cur);
746 cur = cur->children;
747 for (i = 0;i <= no;cur = cur->next) {
748 if (cur == NULL)
749 return(cur);
750 if ((cur->type == XML_ELEMENT_NODE) ||
751 (cur->type == XML_DOCUMENT_NODE) ||
752 (cur->type == XML_HTML_DOCUMENT_NODE)) {
753 i++;
754 if (i == no)
755 break;
756 }
757 }
758 return(cur);
759}
760
761xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
762
763/**
764 * xmlXIncludeCopyRange:
765 * @ctxt: the XInclude context
766 * @target: the document target
767 * @source: the document source
768 * @obj: the XPointer result from the evaluation.
769 *
770 * Build a node list tree copy of the XPointer result.
771 *
772 * Returns an xmlNodePtr list or NULL.
773 * the caller has to free the node tree.
774 */
775static xmlNodePtr
776xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
777 xmlDocPtr source, xmlXPathObjectPtr range) {
778 /* pointers to generated nodes */
779 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
780 /* pointers to traversal nodes */
781 xmlNodePtr start, cur, end;
782 int index1, index2;
783
784 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
785 (range == NULL))
786 return(NULL);
787 if (range->type != XPATH_RANGE)
788 return(NULL);
789 start = (xmlNodePtr) range->user;
790
791 if (start == NULL)
792 return(NULL);
793 end = range->user2;
794 if (end == NULL)
795 return(xmlDocCopyNode(start, target, 1));
796
797 cur = start;
798 index1 = range->index;
799 index2 = range->index2;
800 while (cur != NULL) {
801 if (cur == end) {
802 if (cur->type == XML_TEXT_NODE) {
803 const xmlChar *content = cur->content;
804 int len;
805
806 if (content == NULL) {
807 tmp = xmlNewTextLen(NULL, 0);
808 } else {
809 len = index2;
810 if ((cur == start) && (index1 > 1)) {
811 content += (index1 - 1);
812 len -= (index1 - 1);
813 index1 = 0;
814 } else {
815 len = index2;
816 }
817 tmp = xmlNewTextLen(content, len);
818 }
819 /* single sub text node selection */
820 if (list == NULL)
821 return(tmp);
822 /* prune and return full set */
823 if (last != NULL)
824 xmlAddNextSibling(last, tmp);
825 else
826 xmlAddChild(parent, tmp);
827 return(list);
828 } else {
829 tmp = xmlDocCopyNode(cur, target, 0);
830 if (list == NULL)
831 list = tmp;
832 else {
833 if (last != NULL)
834 xmlAddNextSibling(last, tmp);
835 else
836 xmlAddChild(parent, tmp);
837 }
838 last = NULL;
839 parent = tmp;
840
841 if (index2 > 1) {
842 end = xmlXIncludeGetNthChild(cur, index2 - 1);
843 index2 = 0;
844 }
845 if ((cur == start) && (index1 > 1)) {
846 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
847 index1 = 0;
848 } else {
849 cur = cur->children;
850 }
851 /*
852 * Now gather the remaining nodes from cur to end
853 */
854 continue; /* while */
855 }
856 } else if ((cur == start) &&
857 (list == NULL) /* looks superfluous but ... */ ) {
858 if ((cur->type == XML_TEXT_NODE) ||
859 (cur->type == XML_CDATA_SECTION_NODE)) {
860 const xmlChar *content = cur->content;
861
862 if (content == NULL) {
863 tmp = xmlNewTextLen(NULL, 0);
864 } else {
865 if (index1 > 1) {
866 content += (index1 - 1);
867 }
868 tmp = xmlNewText(content);
869 }
870 last = list = tmp;
871 } else {
872 if ((cur == start) && (index1 > 1)) {
873 tmp = xmlDocCopyNode(cur, target, 0);
874 list = tmp;
875 parent = tmp;
876 last = NULL;
877 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
878 index1 = 0;
879 /*
880 * Now gather the remaining nodes from cur to end
881 */
882 continue; /* while */
883 }
884 tmp = xmlDocCopyNode(cur, target, 1);
885 list = tmp;
886 parent = NULL;
887 last = tmp;
888 }
889 } else {
890 tmp = NULL;
891 switch (cur->type) {
892 case XML_DTD_NODE:
893 case XML_ELEMENT_DECL:
894 case XML_ATTRIBUTE_DECL:
895 case XML_ENTITY_NODE:
896 /* Do not copy DTD informations */
897 break;
898 case XML_ENTITY_DECL:
899 /* handle crossing entities -> stack needed */
900 break;
901 case XML_XINCLUDE_START:
902 case XML_XINCLUDE_END:
903 /* don't consider it part of the tree content */
904 break;
905 case XML_ATTRIBUTE_NODE:
906 /* Humm, should not happen ! */
907 break;
908 default:
909 tmp = xmlDocCopyNode(cur, target, 1);
910 break;
911 }
912 if (tmp != NULL) {
913 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
914 return(NULL);
915 }
916 if (last != NULL)
917 xmlAddNextSibling(last, tmp);
918 else {
919 xmlAddChild(parent, tmp);
920 last = tmp;
921 }
922 }
923 }
924 /*
925 * Skip to next node in document order
926 */
927 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
928 return(NULL);
929 }
930 cur = xmlXPtrAdvanceNode(cur);
931 }
932 return(list);
933}
934
935/**
936 * xmlXIncludeBuildNodeList:
937 * @ctxt: the XInclude context
938 * @target: the document target
939 * @source: the document source
940 * @obj: the XPointer result from the evaluation.
941 *
942 * Build a node list tree copy of the XPointer result.
943 * This will drop Attributes and Namespace declarations.
944 *
945 * Returns an xmlNodePtr list or NULL.
946 * the caller has to free the node tree.
947 */
948static xmlNodePtr
949xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
950 xmlDocPtr source, xmlXPathObjectPtr obj) {
951 xmlNodePtr list = NULL, last = NULL;
952 int i;
953
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000954 if (source == NULL)
955 source = ctxt->doc;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000956 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
957 (obj == NULL))
958 return(NULL);
959 switch (obj->type) {
960 case XPATH_NODESET: {
961 xmlNodeSetPtr set = obj->nodesetval;
962 if (set == NULL)
963 return(NULL);
964 for (i = 0;i < set->nodeNr;i++) {
965 if (set->nodeTab[i] == NULL)
966 continue;
967 switch (set->nodeTab[i]->type) {
968 case XML_TEXT_NODE:
969 case XML_CDATA_SECTION_NODE:
970 case XML_ELEMENT_NODE:
971 case XML_ENTITY_REF_NODE:
972 case XML_ENTITY_NODE:
973 case XML_PI_NODE:
974 case XML_COMMENT_NODE:
975 case XML_DOCUMENT_NODE:
976 case XML_HTML_DOCUMENT_NODE:
977#ifdef LIBXML_DOCB_ENABLED
978 case XML_DOCB_DOCUMENT_NODE:
979#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000980 case XML_XINCLUDE_END:
981 break;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000982 case XML_XINCLUDE_START: {
983 xmlNodePtr tmp, cur = set->nodeTab[i];
984
985 cur = cur->next;
986 while (cur != NULL) {
987 switch(cur->type) {
988 case XML_TEXT_NODE:
989 case XML_CDATA_SECTION_NODE:
990 case XML_ELEMENT_NODE:
991 case XML_ENTITY_REF_NODE:
992 case XML_ENTITY_NODE:
993 case XML_PI_NODE:
994 case XML_COMMENT_NODE:
995 tmp = xmlXIncludeCopyNode(ctxt, target,
996 source, cur);
997 if (last == NULL) {
998 list = last = tmp;
999 } else {
1000 xmlAddNextSibling(last, tmp);
1001 last = tmp;
1002 }
1003 cur = cur->next;
1004 continue;
1005 default:
1006 break;
1007 }
1008 break;
1009 }
1010 continue;
1011 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001012 case XML_ATTRIBUTE_NODE:
1013 case XML_NAMESPACE_DECL:
1014 case XML_DOCUMENT_TYPE_NODE:
1015 case XML_DOCUMENT_FRAG_NODE:
1016 case XML_NOTATION_NODE:
1017 case XML_DTD_NODE:
1018 case XML_ELEMENT_DECL:
1019 case XML_ATTRIBUTE_DECL:
1020 case XML_ENTITY_DECL:
1021 continue; /* for */
1022 }
1023 if (last == NULL)
1024 list = last = xmlXIncludeCopyNode(ctxt, target, source,
1025 set->nodeTab[i]);
1026 else {
1027 xmlAddNextSibling(last,
1028 xmlXIncludeCopyNode(ctxt, target, source,
1029 set->nodeTab[i]));
1030 if (last->next != NULL)
1031 last = last->next;
1032 }
1033 }
1034 break;
1035 }
1036 case XPATH_LOCATIONSET: {
1037 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1038 if (set == NULL)
1039 return(NULL);
1040 for (i = 0;i < set->locNr;i++) {
1041 if (last == NULL)
1042 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
1043 set->locTab[i]);
1044 else
1045 xmlAddNextSibling(last,
1046 xmlXIncludeCopyXPointer(ctxt, target, source,
1047 set->locTab[i]));
1048 if (last != NULL) {
1049 while (last->next != NULL)
1050 last = last->next;
1051 }
1052 }
1053 break;
1054 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001055#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001056 case XPATH_RANGE:
1057 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001058#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001059 case XPATH_POINT:
1060 /* points are ignored in XInclude */
1061 break;
1062 default:
1063 break;
1064 }
1065 return(list);
1066}
1067/************************************************************************
1068 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001069 * XInclude I/O handling *
1070 * *
1071 ************************************************************************/
1072
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001073typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1074typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1075struct _xmlXIncludeMergeData {
1076 xmlDocPtr doc;
1077 xmlXIncludeCtxtPtr ctxt;
1078};
1079
Owen Taylor3473f882001-02-23 17:55:21 +00001080/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001081 * xmlXIncludeMergeOneEntity:
1082 * @ent: the entity
1083 * @doc: the including doc
1084 * @nr: the entity name
1085 *
1086 * Inplements the merge of one entity
1087 */
1088static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001089xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001090 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001091 xmlEntityPtr ret, prev;
1092 xmlDocPtr doc;
1093 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001094
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001095 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001096 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001097 ctxt = data->ctxt;
1098 doc = data->doc;
1099 if ((ctxt == NULL) || (doc == NULL))
1100 return;
1101 switch (ent->etype) {
1102 case XML_INTERNAL_PARAMETER_ENTITY:
1103 case XML_EXTERNAL_PARAMETER_ENTITY:
1104 case XML_INTERNAL_PREDEFINED_ENTITY:
1105 return;
1106 case XML_INTERNAL_GENERAL_ENTITY:
1107 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1108 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1109 break;
1110 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001111 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1112 ent->SystemID, ent->content);
1113 if (ret != NULL) {
1114 if (ent->URI != NULL)
1115 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001116 } else {
1117 prev = xmlGetDocEntity(doc, ent->name);
1118 if (prev != NULL) {
1119 if (ent->etype != prev->etype)
1120 goto error;
1121
1122 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1123 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1124 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001125 } else if ((ent->ExternalID != NULL) &&
1126 (prev->ExternalID != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001127 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1128 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001129 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1130 if (!xmlStrEqual(ent->content, prev->content))
1131 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001132 } else {
1133 goto error;
1134 }
1135
1136 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001137 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001138 return;
1139error:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001140 switch (ent->etype) {
1141 case XML_INTERNAL_PARAMETER_ENTITY:
1142 case XML_EXTERNAL_PARAMETER_ENTITY:
1143 case XML_INTERNAL_PREDEFINED_ENTITY:
1144 case XML_INTERNAL_GENERAL_ENTITY:
1145 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1146 return;
1147 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1148 break;
1149 }
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001150 xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
1151 "mismatch in redefinition of entity %s\n",
1152 ent->name);
Daniel Veillard4287c572003-02-04 22:48:53 +00001153}
1154
1155/**
1156 * xmlXIncludeMergeEntities:
1157 * @ctxt: an XInclude context
1158 * @doc: the including doc
1159 * @from: the included doc
1160 *
1161 * Inplements the entity merge
1162 *
1163 * Returns 0 if merge succeeded, -1 if some processing failed
1164 */
1165static int
1166xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1167 xmlDocPtr from) {
1168 xmlNodePtr cur;
1169 xmlDtdPtr target, source;
1170
1171 if (ctxt == NULL)
1172 return(-1);
1173
1174 if ((from == NULL) || (from->intSubset == NULL))
1175 return(0);
1176
1177 target = doc->intSubset;
1178 if (target == NULL) {
1179 cur = xmlDocGetRootElement(doc);
1180 if (cur == NULL)
1181 return(-1);
1182 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1183 if (target == NULL)
1184 return(-1);
1185 }
1186
1187 source = from->intSubset;
1188 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001189 xmlXIncludeMergeData data;
1190
1191 data.ctxt = ctxt;
1192 data.doc = doc;
1193
Daniel Veillard4287c572003-02-04 22:48:53 +00001194 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001195 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001196 }
1197 source = from->extSubset;
1198 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001199 xmlXIncludeMergeData data;
1200
1201 data.ctxt = ctxt;
1202 data.doc = doc;
1203
Daniel Veillard4287c572003-02-04 22:48:53 +00001204 /*
1205 * don't duplicate existing stuff when external subsets are the same
1206 */
1207 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1208 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1209 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001210 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001211 }
1212 }
1213 return(0);
1214}
1215
1216/**
Owen Taylor3473f882001-02-23 17:55:21 +00001217 * xmlXIncludeLoadDoc:
1218 * @ctxt: the XInclude context
1219 * @url: the associated URL
1220 * @nr: the xinclude node number
1221 *
1222 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001223 *
1224 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001225 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001226static int
Owen Taylor3473f882001-02-23 17:55:21 +00001227xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1228 xmlDocPtr doc;
1229 xmlURIPtr uri;
1230 xmlChar *URL;
1231 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001232 int i = 0;
1233
1234#ifdef DEBUG_XINCLUDE
1235 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1236#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001237 /*
1238 * Check the URL and remove any fragment identifier
1239 */
1240 uri = xmlParseURI((const char *)url);
1241 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001242 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1243 XML_XINCLUDE_HREF_URI,
1244 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001245 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001246 }
1247 if (uri->fragment != NULL) {
1248 fragment = (xmlChar *) uri->fragment;
1249 uri->fragment = NULL;
1250 }
1251 URL = xmlSaveUri(uri);
1252 xmlFreeURI(uri);
1253 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001254 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1255 XML_XINCLUDE_HREF_URI,
1256 "invalid value URI %s\n", url);
Owen Taylor3473f882001-02-23 17:55:21 +00001257 if (fragment != NULL)
1258 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001259 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001260 }
1261
1262 /*
1263 * Handling of references to the local document are done
1264 * directly through ctxt->doc.
1265 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001266 if ((URL[0] == 0) || (URL[0] == '#') ||
1267 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001268 doc = NULL;
1269 goto loaded;
1270 }
1271
1272 /*
1273 * Prevent reloading twice the document.
1274 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001275 for (i = 0; i < ctxt->incNr; i++) {
1276 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1277 (ctxt->incTab[i]->doc != NULL)) {
1278 doc = ctxt->incTab[i]->doc;
1279#ifdef DEBUG_XINCLUDE
1280 printf("Already loaded %s\n", URL);
1281#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001282 goto loaded;
1283 }
1284 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001285
Owen Taylor3473f882001-02-23 17:55:21 +00001286 /*
1287 * Load it.
1288 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001289#ifdef DEBUG_XINCLUDE
1290 printf("loading %s\n", URL);
1291#endif
Daniel Veillard98485322003-08-14 15:44:40 +00001292 doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001293 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001294 xmlFree(URL);
1295 if (fragment != NULL)
1296 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001297 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001298 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001299 ctxt->incTab[nr]->doc = doc;
Daniel Veillard98485322003-08-14 15:44:40 +00001300 for (i = nr + 1; i < ctxt->incNr; i++) {
1301 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1302 ctxt->incTab[nr]->count++;
1303#ifdef DEBUG_XINCLUDE
1304 printf("Increasing %s count since reused\n", URL);
1305#endif
1306 break;
1307 }
1308 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001309
1310 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001311 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001312 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001313 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001314
1315 /*
1316 * We don't need the DTD anymore, free up space
1317 if (doc->intSubset != NULL) {
1318 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1319 xmlFreeNode((xmlNodePtr) doc->intSubset);
1320 doc->intSubset = NULL;
1321 }
1322 if (doc->extSubset != NULL) {
1323 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1324 xmlFreeNode((xmlNodePtr) doc->extSubset);
1325 doc->extSubset = NULL;
1326 }
1327 */
1328 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001329
1330loaded:
1331 if (fragment == NULL) {
1332 /*
1333 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001334 */
1335 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001336 {
1337 /* Hopefully a DTD declaration won't be copied from
1338 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001339 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001340 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001341 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001342 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001343 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001344 }
1345#ifdef LIBXML_XPTR_ENABLED
1346 else {
Owen Taylor3473f882001-02-23 17:55:21 +00001347 /*
1348 * Computes the XPointer expression and make a copy used
1349 * as the replacement copy.
1350 */
1351 xmlXPathObjectPtr xptr;
1352 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001353 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001354
1355 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001356 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1357 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001358 } else {
1359 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1360 }
1361 if (xptrctxt == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001362 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1363 XML_XINCLUDE_XPTR_FAILED,
1364 "could create XPointer context\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001365 xmlFree(URL);
1366 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001367 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001368 }
1369 xptr = xmlXPtrEval(fragment, xptrctxt);
1370 if (xptr == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001371 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1372 XML_XINCLUDE_XPTR_FAILED,
1373 "XPointer evaluation failed: #%s\n",
1374 fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001375 xmlXPathFreeContext(xptrctxt);
1376 xmlFree(URL);
1377 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001378 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001379 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001380 switch (xptr->type) {
1381 case XPATH_UNDEFINED:
1382 case XPATH_BOOLEAN:
1383 case XPATH_NUMBER:
1384 case XPATH_STRING:
1385 case XPATH_POINT:
1386 case XPATH_USERS:
1387 case XPATH_XSLT_TREE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001388 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1389 XML_XINCLUDE_XPTR_RESULT,
1390 "XPointer is not a range: #%s\n",
1391 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001392 xmlXPathFreeContext(xptrctxt);
1393 xmlFree(URL);
1394 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001395 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001396 case XPATH_NODESET:
Daniel Veillard798ae542003-11-03 17:13:52 +00001397 if ((xptr->nodesetval == NULL) ||
1398 (xptr->nodesetval->nodeNr <= 0)) {
1399 xmlXPathFreeContext(xptrctxt);
1400 xmlFree(URL);
1401 xmlFree(fragment);
1402 return(-1);
1403 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001404 case XPATH_RANGE:
1405 case XPATH_LOCATIONSET:
1406 break;
1407 }
1408 set = xptr->nodesetval;
1409 if (set != NULL) {
1410 for (i = 0;i < set->nodeNr;i++) {
1411 if (set->nodeTab[i] == NULL)
1412 continue;
1413 switch (set->nodeTab[i]->type) {
1414 case XML_TEXT_NODE:
1415 case XML_CDATA_SECTION_NODE:
1416 case XML_ELEMENT_NODE:
1417 case XML_ENTITY_REF_NODE:
1418 case XML_ENTITY_NODE:
1419 case XML_PI_NODE:
1420 case XML_COMMENT_NODE:
1421 case XML_DOCUMENT_NODE:
1422 case XML_HTML_DOCUMENT_NODE:
1423#ifdef LIBXML_DOCB_ENABLED
1424 case XML_DOCB_DOCUMENT_NODE:
1425#endif
1426 continue;
1427 case XML_ATTRIBUTE_NODE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001428 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1429 XML_XINCLUDE_XPTR_RESULT,
1430 "XPointer selects an attribute: #%s\n",
1431 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001432 set->nodeTab[i] = NULL;
1433 continue;
1434 case XML_NAMESPACE_DECL:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001435 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1436 XML_XINCLUDE_XPTR_RESULT,
1437 "XPointer selects a namespace: #%s\n",
1438 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001439 set->nodeTab[i] = NULL;
1440 continue;
1441 case XML_DOCUMENT_TYPE_NODE:
1442 case XML_DOCUMENT_FRAG_NODE:
1443 case XML_NOTATION_NODE:
1444 case XML_DTD_NODE:
1445 case XML_ELEMENT_DECL:
1446 case XML_ATTRIBUTE_DECL:
1447 case XML_ENTITY_DECL:
1448 case XML_XINCLUDE_START:
1449 case XML_XINCLUDE_END:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001450 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1451 XML_XINCLUDE_XPTR_RESULT,
1452 "XPointer selects unexpected nodes: #%s\n",
1453 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001454 set->nodeTab[i] = NULL;
1455 set->nodeTab[i] = NULL;
1456 continue; /* for */
1457 }
1458 }
1459 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001460 if (doc == NULL) {
1461 ctxt->incTab[nr]->xptr = xptr;
1462 ctxt->incTab[nr]->inc = NULL;
1463 } else {
1464 ctxt->incTab[nr]->inc =
1465 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1466 xmlXPathFreeObject(xptr);
1467 }
Owen Taylor3473f882001-02-23 17:55:21 +00001468 xmlXPathFreeContext(xptrctxt);
1469 xmlFree(fragment);
1470 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001471#endif
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001472
1473 /*
1474 * Do the xml:base fixup if needed
1475 */
1476 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1477 xmlNodePtr node;
1478
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001479 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001480 while (node != NULL) {
1481 if (node->type == XML_ELEMENT_NODE)
1482 xmlNodeSetBase(node, URL);
1483 node = node->next;
1484 }
1485 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001486 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1487 (ctxt->incTab[nr]->count <= 1)) {
1488#ifdef DEBUG_XINCLUDE
1489 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1490#endif
1491 xmlFreeDoc(ctxt->incTab[nr]->doc);
1492 ctxt->incTab[nr]->doc = NULL;
1493 }
Owen Taylor3473f882001-02-23 17:55:21 +00001494 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001495 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001496}
1497
1498/**
1499 * xmlXIncludeLoadTxt:
1500 * @ctxt: the XInclude context
1501 * @url: the associated URL
1502 * @nr: the xinclude node number
1503 *
1504 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001505 *
1506 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001507 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001508static int
Owen Taylor3473f882001-02-23 17:55:21 +00001509xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1510 xmlParserInputBufferPtr buf;
1511 xmlNodePtr node;
1512 xmlURIPtr uri;
1513 xmlChar *URL;
1514 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001515 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001516 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001517
Owen Taylor3473f882001-02-23 17:55:21 +00001518 /*
1519 * Check the URL and remove any fragment identifier
1520 */
1521 uri = xmlParseURI((const char *)url);
1522 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001523 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1524 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001525 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001526 }
1527 if (uri->fragment != NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001528 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1529 "fragment identifier forbidden for text: %s\n",
1530 (const xmlChar *) uri->fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001531 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001532 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001533 }
1534 URL = xmlSaveUri(uri);
1535 xmlFreeURI(uri);
1536 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001537 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1538 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001539 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001540 }
1541
1542 /*
1543 * Handling of references to the local document are done
1544 * directly through ctxt->doc.
1545 */
1546 if (URL[0] == 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001547 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1548 XML_XINCLUDE_TEXT_DOCUMENT,
1549 "text serialization of document not available\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001550 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001551 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001552 }
1553
1554 /*
1555 * Prevent reloading twice the document.
1556 */
1557 for (i = 0; i < ctxt->txtNr; i++) {
1558 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1559 node = xmlCopyNode(ctxt->txtTab[i], 1);
1560 goto loaded;
1561 }
1562 }
1563 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001564 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001565 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001566 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1567 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1568 }
1569 if (encoding != NULL) {
1570 /*
1571 * TODO: we should not have to remap to the xmlCharEncoding
1572 * predefined set, a better interface than
1573 * xmlParserInputBufferCreateFilename should allow any
1574 * encoding supported by iconv
1575 */
1576 enc = xmlParseCharEncoding((const char *) encoding);
1577 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001578 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1579 XML_XINCLUDE_UNKNOWN_ENCODING,
1580 "encoding %s not supported\n", encoding);
Daniel Veillardd076a202002-11-20 13:28:31 +00001581 xmlFree(encoding);
1582 xmlFree(URL);
1583 return(-1);
1584 }
1585 xmlFree(encoding);
1586 }
1587
1588 /*
1589 * Load it.
1590 */
1591 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001592 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001593 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001594 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001595 }
1596 node = xmlNewText(NULL);
1597
1598 /*
1599 * Scan all chars from the resource and add the to the node
1600 */
1601 while (xmlParserInputBufferRead(buf, 128) > 0) {
1602 int len;
1603 const xmlChar *content;
1604
1605 content = xmlBufferContent(buf->buffer);
1606 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001607 for (i = 0;i < len;) {
1608 int cur;
1609 int l;
1610
1611 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1612 if (!IS_CHAR(cur)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001613 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1614 XML_XINCLUDE_INVALID_CHAR,
1615 "%s contains invalid char\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001616 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001617 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001618 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001619 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001620 }
1621 xmlBufferShrink(buf->buffer, len);
1622 }
1623 xmlFreeParserInputBuffer(buf);
1624 xmlXIncludeAddTxt(ctxt, node, URL);
1625
1626loaded:
1627 /*
1628 * Add the element as the replacement copy.
1629 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001630 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001631 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001632 return(0);
1633}
1634
1635/**
1636 * xmlXIncludeLoadFallback:
1637 * @ctxt: the XInclude context
1638 * @fallback: the fallback node
1639 * @nr: the xinclude node number
1640 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001641 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001642 * in the XInclude context
1643 *
1644 * Returns 0 in case of success, -1 in case of failure
1645 */
1646static int
1647xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1648 if ((fallback == NULL) || (ctxt == NULL))
1649 return(-1);
1650
Daniel Veillard06503452002-12-13 10:42:08 +00001651 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001652 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001653}
1654
1655/************************************************************************
1656 * *
1657 * XInclude Processing *
1658 * *
1659 ************************************************************************/
1660
1661/**
1662 * xmlXIncludePreProcessNode:
1663 * @ctxt: an XInclude context
1664 * @node: an XInclude node
1665 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001666 * Implement the XInclude preprocessing, currently just adding the element
1667 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001668 *
1669 * Returns the result list or NULL in case of error
1670 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001671static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001672xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1673 xmlXIncludeAddNode(ctxt, node);
1674 return(0);
1675}
1676
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001677/**
Owen Taylor3473f882001-02-23 17:55:21 +00001678 * xmlXIncludeLoadNode:
1679 * @ctxt: an XInclude context
1680 * @nr: the node number
1681 *
1682 * Find and load the infoset replacement for the given node.
1683 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001684 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001685 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001686static int
Owen Taylor3473f882001-02-23 17:55:21 +00001687xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1688 xmlNodePtr cur;
1689 xmlChar *href;
1690 xmlChar *parse;
1691 xmlChar *base;
1692 xmlChar *URI;
1693 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001694 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001695
1696 if (ctxt == NULL)
1697 return(-1);
1698 if ((nr < 0) || (nr >= ctxt->incNr))
1699 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001700 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001701 if (cur == NULL)
1702 return(-1);
1703
Owen Taylor3473f882001-02-23 17:55:21 +00001704 /*
1705 * read the attributes
1706 */
1707 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1708 if (href == NULL) {
1709 href = xmlGetProp(cur, XINCLUDE_HREF);
1710 if (href == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001711 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1712 XML_XINCLUDE_NO_HREF, "no href\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001713 return(-1);
1714 }
1715 }
1716 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1717 if (parse == NULL) {
1718 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1719 }
1720 if (parse != NULL) {
1721 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1722 xml = 1;
1723 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1724 xml = 0;
1725 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001726 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1727 XML_XINCLUDE_PARSE_VALUE,
1728 "invalid value %s for 'parse'\n", parse);
Owen Taylor3473f882001-02-23 17:55:21 +00001729 if (href != NULL)
1730 xmlFree(href);
1731 if (parse != NULL)
1732 xmlFree(parse);
1733 return(-1);
1734 }
1735 }
1736
1737 /*
1738 * compute the URI
1739 */
1740 base = xmlNodeGetBase(ctxt->doc, cur);
1741 if (base == NULL) {
1742 URI = xmlBuildURI(href, ctxt->doc->URL);
1743 } else {
1744 URI = xmlBuildURI(href, base);
1745 }
1746 if (URI == NULL) {
1747 xmlChar *escbase;
1748 xmlChar *eschref;
1749 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001750 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001751 */
1752 escbase = xmlURIEscape(base);
1753 eschref = xmlURIEscape(href);
1754 URI = xmlBuildURI(eschref, escbase);
1755 if (escbase != NULL)
1756 xmlFree(escbase);
1757 if (eschref != NULL)
1758 xmlFree(eschref);
1759 }
1760 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001761 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1762 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001763 if (parse != NULL)
1764 xmlFree(parse);
1765 if (href != NULL)
1766 xmlFree(href);
1767 if (base != NULL)
1768 xmlFree(base);
1769 return(-1);
1770 }
1771#ifdef DEBUG_XINCLUDE
1772 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1773 xml ? "xml": "text");
1774 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1775#endif
1776
1777 /*
1778 * Cleanup
1779 */
1780 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001781 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001782 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1783 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001784 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1785 }
1786 if (ret < 0) {
1787 xmlNodePtr children;
1788
1789 /*
1790 * Time to try a fallback if availble
1791 */
1792#ifdef DEBUG_XINCLUDE
1793 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1794#endif
1795 children = cur->children;
1796 while (children != NULL) {
1797 if ((children->type == XML_ELEMENT_NODE) &&
1798 (children->ns != NULL) &&
1799 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1800 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1801 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1802 if (ret == 0)
1803 break;
1804 }
1805 children = children->next;
1806 }
1807 }
1808 if (ret < 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001809 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1810 XML_XINCLUDE_NO_FALLBACK,
1811 "could not load %s, and no fallback was found\n",
1812 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001813 }
1814
1815 /*
1816 * Cleanup
1817 */
1818 if (URI != NULL)
1819 xmlFree(URI);
1820 if (parse != NULL)
1821 xmlFree(parse);
1822 if (href != NULL)
1823 xmlFree(href);
1824 if (base != NULL)
1825 xmlFree(base);
1826 return(0);
1827}
1828
1829/**
1830 * xmlXIncludeIncludeNode:
1831 * @ctxt: an XInclude context
1832 * @nr: the node number
1833 *
1834 * Inplement the infoset replacement for the given node
1835 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001836 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001837 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001838static int
Owen Taylor3473f882001-02-23 17:55:21 +00001839xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001840 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001841
1842 if (ctxt == NULL)
1843 return(-1);
1844 if ((nr < 0) || (nr >= ctxt->incNr))
1845 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001846 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001847 if (cur == NULL)
1848 return(-1);
1849
1850 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001851 * If we stored an XPointer a late computation may be needed
1852 */
1853 if ((ctxt->incTab[nr]->inc == NULL) &&
1854 (ctxt->incTab[nr]->xptr != NULL)) {
1855 ctxt->incTab[nr]->inc =
1856 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1857 ctxt->incTab[nr]->xptr);
1858 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1859 ctxt->incTab[nr]->xptr = NULL;
1860 }
1861 list = ctxt->incTab[nr]->inc;
1862 ctxt->incTab[nr]->inc = NULL;
1863
1864 /*
1865 * Check against the risk of generating a multi-rooted document
1866 */
1867 if ((cur->parent != NULL) &&
1868 (cur->parent->type != XML_ELEMENT_NODE)) {
1869 int nb_elem = 0;
1870
1871 tmp = list;
1872 while (tmp != NULL) {
1873 if (tmp->type == XML_ELEMENT_NODE)
1874 nb_elem++;
1875 tmp = tmp->next;
1876 }
1877 if (nb_elem > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001878 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1879 XML_XINCLUDE_MULTIPLE_ROOT,
1880 "XInclude error: would result in multiple root nodes\n",
1881 NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001882 return(-1);
1883 }
1884 }
1885
1886 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001887 * Change the current node as an XInclude start one, and add an
1888 * entity end one
1889 */
1890 cur->type = XML_XINCLUDE_START;
1891 end = xmlNewNode(cur->ns, cur->name);
1892 if (end == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001893 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED,
1894 "failed to build node\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001895 return(-1);
1896 }
1897 end->type = XML_XINCLUDE_END;
1898 xmlAddNextSibling(cur, end);
1899
1900 /*
1901 * Add the list of nodes
1902 */
Owen Taylor3473f882001-02-23 17:55:21 +00001903 while (list != NULL) {
1904 cur = list;
1905 list = list->next;
1906
1907 xmlAddPrevSibling(end, cur);
1908 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001909
1910
Owen Taylor3473f882001-02-23 17:55:21 +00001911 return(0);
1912}
1913
1914/**
1915 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001916 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001917 * @node: an XInclude node
1918 *
1919 * test if the node is an XInclude node
1920 *
1921 * Returns 1 true, 0 otherwise
1922 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001923static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001924xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001925 if (node == NULL)
1926 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00001927 if (node->type != XML_ELEMENT_NODE)
1928 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001929 if (node->ns == NULL)
1930 return(0);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001931 if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
1932 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
1933 xmlNodePtr child = node->children;
1934 int nb_fallback = 0;
1935
1936 while (child != NULL) {
1937 if ((child->type == XML_ELEMENT_NODE) &&
1938 (child->ns != NULL) &&
1939 (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
1940 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001941 xmlXIncludeErr(ctxt, node,
1942 XML_XINCLUDE_INCLUDE_IN_INCLUDE,
1943 "%s has an 'include' child\n",
1944 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001945 return(0);
1946 }
1947 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
1948 nb_fallback++;
1949 }
1950 }
1951 child = child->next;
1952 }
1953 if (nb_fallback > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001954 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
1955 "%s has multiple fallback children\n",
1956 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001957 return(0);
1958 }
1959 return(1);
1960 }
1961 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
1962 if ((node->parent == NULL) ||
1963 (node->parent->type != XML_ELEMENT_NODE) ||
1964 (node->parent->ns == NULL) ||
1965 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
1966 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001967 xmlXIncludeErr(ctxt, node,
1968 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
1969 "%s is not the child of an 'include'\n",
1970 XINCLUDE_FALLBACK);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001971 }
1972 }
1973 }
Owen Taylor3473f882001-02-23 17:55:21 +00001974 return(0);
1975}
1976
1977/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001978 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001979 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001980 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001981 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00001982 *
1983 * Implement the XInclude substitution on the XML document @doc
1984 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001985 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001986 * or the number of substitutions done.
1987 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001988static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001989xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00001990 xmlNodePtr cur;
1991 int ret = 0;
1992 int i;
1993
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001994 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001995 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001996 if (ctxt == NULL)
1997 return(-1);
1998
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001999 if (doc->URL != NULL) {
2000 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2001 if (ret < 0)
2002 return(-1);
2003 }
2004
Owen Taylor3473f882001-02-23 17:55:21 +00002005 /*
2006 * First phase: lookup the elements in the document
2007 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002008 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002009 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002010 xmlXIncludePreProcessNode(ctxt, cur);
2011 while (cur != NULL) {
2012 /* TODO: need to work on entities -> stack */
2013 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002014 (cur->children->type != XML_ENTITY_DECL) &&
2015 (cur->children->type != XML_XINCLUDE_START) &&
2016 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002017 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002018 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002019 xmlXIncludePreProcessNode(ctxt, cur);
2020 } else if (cur->next != NULL) {
2021 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002022 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002023 xmlXIncludePreProcessNode(ctxt, cur);
2024 } else {
2025 do {
2026 cur = cur->parent;
2027 if (cur == NULL) break; /* do */
2028 if (cur->next != NULL) {
2029 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002030 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002031 xmlXIncludePreProcessNode(ctxt, cur);
2032 break; /* do */
2033 }
2034 } while (cur != NULL);
2035 }
2036 }
2037
2038 /*
2039 * Second Phase : collect the infosets fragments
2040 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002041 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002042 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002043 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002044 }
2045
2046 /*
2047 * Third phase: extend the original document infoset.
2048 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002049 if (ctxt->nbErrors == 0) {
2050 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2051 xmlXIncludeIncludeNode(ctxt, i);
2052 }
Owen Taylor3473f882001-02-23 17:55:21 +00002053 }
2054
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002055 if (doc->URL != NULL)
2056 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002057 return(ret);
2058}
2059
2060/**
2061 * xmlXIncludeProcess:
2062 * @doc: an XML document
2063 *
2064 * Implement the XInclude substitution on the XML document @doc
2065 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002066 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002067 * or the number of substitutions done.
2068 */
2069int
2070xmlXIncludeProcess(xmlDocPtr doc) {
2071 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002072 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002073 int ret = 0;
2074
2075 if (doc == NULL)
2076 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002077 tree = xmlDocGetRootElement(doc);
2078 if (tree == NULL)
2079 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002080 ctxt = xmlXIncludeNewContext(doc);
2081 if (ctxt == NULL)
2082 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002083 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2084 if ((ret >= 0) && (ctxt->nbErrors > 0))
2085 ret = -1;
2086
2087 xmlXIncludeFreeContext(ctxt);
2088 return(ret);
2089}
2090
2091/**
2092 * xmlXIncludeProcessTree:
2093 * @tree: a node in an XML document
2094 *
2095 * Implement the XInclude substitution for the given subtree
2096 *
2097 * Returns 0 if no substitution were done, -1 if some processing failed
2098 * or the number of substitutions done.
2099 */
2100int
2101xmlXIncludeProcessTree(xmlNodePtr tree) {
2102 xmlXIncludeCtxtPtr ctxt;
2103 int ret = 0;
2104
2105 if ((tree == NULL) || (tree->doc == NULL))
2106 return(-1);
2107 ctxt = xmlXIncludeNewContext(tree->doc);
2108 if (ctxt == NULL)
2109 return(-1);
2110 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00002111 if ((ret >= 0) && (ctxt->nbErrors > 0))
2112 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002113
Owen Taylor3473f882001-02-23 17:55:21 +00002114 xmlXIncludeFreeContext(ctxt);
2115 return(ret);
2116}
2117
Daniel Veillard7899c5c2003-11-03 12:31:38 +00002118/**
2119 * xmlXIncludeProcessNode:
2120 * @ctxt: an existing XInclude context
2121 * @node: a node in an XML document
2122 *
2123 * Implement the XInclude substitution for the given subtree reusing
2124 * the informations and data coming from the given context.
2125 *
2126 * Returns 0 if no substitution were done, -1 if some processing failed
2127 * or the number of substitutions done.
2128 */
2129int
2130xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2131 int ret = 0;
2132
2133 if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
2134 return(-1);
2135 ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
2136 if ((ret >= 0) && (ctxt->nbErrors > 0))
2137 ret = -1;
2138 return(ret);
2139}
2140
Owen Taylor3473f882001-02-23 17:55:21 +00002141#else /* !LIBXML_XINCLUDE_ENABLED */
2142#endif