blob: c992b58860c687dfb18009245a82bb2303c90c55 [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
Daniel Veillardbbd22452001-05-23 12:02:27 +000029#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
Owen Taylor3473f882001-02-23 17:55:21 +000030#define XINCLUDE_NODE (const xmlChar *) "include"
Daniel Veillard58e44c92002-08-02 22:19:49 +000031#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
Owen Taylor3473f882001-02-23 17:55:21 +000032#define XINCLUDE_HREF (const xmlChar *) "href"
33#define XINCLUDE_PARSE (const xmlChar *) "parse"
34#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
35#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
Daniel Veillardd076a202002-11-20 13:28:31 +000036#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
Owen Taylor3473f882001-02-23 17:55:21 +000037
Daniel Veillardf4b4f982003-02-13 11:02:08 +000038#define XINCLUDE_MAX_DEPTH 40
39
Daniel Veillard98485322003-08-14 15:44:40 +000040/* #define DEBUG_XINCLUDE */
Daniel Veillard017b1082001-06-21 11:20:21 +000041#ifdef DEBUG_XINCLUDE
42#ifdef LIBXML_DEBUG_ENABLED
43#include <libxml/debugXML.h>
44#endif
45#endif
Owen Taylor3473f882001-02-23 17:55:21 +000046
47/************************************************************************
48 * *
49 * XInclude contexts handling *
50 * *
51 ************************************************************************/
52
53/*
54 * An XInclude context
55 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000056typedef xmlChar *xmlURL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +000057
58typedef struct _xmlXIncludeRef xmlXIncludeRef;
59typedef xmlXIncludeRef *xmlXIncludeRefPtr;
60struct _xmlXIncludeRef {
61 xmlChar *URI; /* the rully resolved resource URL */
62 xmlChar *fragment; /* the fragment in the URI */
63 xmlDocPtr doc; /* the parsed document */
64 xmlNodePtr ref; /* the node making the reference in the source */
65 xmlNodePtr inc; /* the included copy */
66 int xml; /* xml or txt */
67 int count; /* how many refs use that specific doc */
Daniel Veillardf4b4f982003-02-13 11:02:08 +000068 xmlXPathObjectPtr xptr; /* the xpointer if needed */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000069};
70
Owen Taylor3473f882001-02-23 17:55:21 +000071typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
72typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
73struct _xmlXIncludeCtxt {
74 xmlDocPtr doc; /* the source document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000075 int incBase; /* the first include for this document */
Owen Taylor3473f882001-02-23 17:55:21 +000076 int incNr; /* number of includes */
77 int incMax; /* size of includes tab */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000078 xmlXIncludeRefPtr *incTab; /* array of included references */
79
Owen Taylor3473f882001-02-23 17:55:21 +000080 int txtNr; /* number of unparsed documents */
81 int txtMax; /* size of unparsed documents tab */
82 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000083 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Daniel Veillardd581b7e2003-02-11 18:03:05 +000084
Daniel Veillardf4b4f982003-02-13 11:02:08 +000085 xmlChar * url; /* the current URL processed */
86 int urlNr; /* number of url stacked */
87 int urlMax; /* size of url stack */
88 xmlChar * *urlTab; /* url stack */
89
Daniel Veillardd581b7e2003-02-11 18:03:05 +000090 int nbErrors; /* the number of errors detected */
Owen Taylor3473f882001-02-23 17:55:21 +000091};
92
Daniel Veillardd16df9f2001-05-23 13:44:21 +000093static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +000094xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
Owen Taylor3473f882001-02-23 17:55:21 +000095
Daniel Veillard98485322003-08-14 15:44:40 +000096
Daniel Veillardcd6ff282003-10-08 22:38:13 +000097/************************************************************************
98 * *
Daniel Veillard69d2c172003-10-09 11:46:07 +000099 * XInclude error handler *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000100 * *
101 ************************************************************************/
102
Daniel Veillard98485322003-08-14 15:44:40 +0000103/**
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000104 * xmlXIncludeErrMemory:
105 * @extra: extra informations
Daniel Veillard98485322003-08-14 15:44:40 +0000106 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000107 * Handle an out of memory condition
Daniel Veillard98485322003-08-14 15:44:40 +0000108 */
109static void
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000110xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
111 const char *extra)
Daniel Veillard98485322003-08-14 15:44:40 +0000112{
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000113 if (ctxt != NULL)
114 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000115 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000116 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
117 extra, NULL, NULL, 0, 0,
118 "Memory allocation failed : %s\n", extra);
119}
Daniel Veillard98485322003-08-14 15:44:40 +0000120
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000121/**
122 * xmlXIncludeErr:
123 * @ctxt: the XInclude context
124 * @node: the context node
125 * @msg: the error message
126 * @extra: extra informations
127 *
128 * Handle a resource access error
129 */
130static void
131xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
132 const char *msg, const xmlChar *extra)
133{
134 if (ctxt != NULL)
135 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000136 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000137 error, XML_ERR_ERROR, NULL, 0,
138 (const char *) extra, NULL, NULL, 0, 0,
139 msg, (const char *) extra);
Daniel Veillard98485322003-08-14 15:44:40 +0000140}
141
Owen Taylor3473f882001-02-23 17:55:21 +0000142/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000143 * xmlXIncludeFreeRef:
144 * @ref: the XInclude reference
145 *
146 * Free an XInclude reference
147 */
148static void
149xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
150 if (ref == NULL)
151 return;
152#ifdef DEBUG_XINCLUDE
153 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
154#endif
155 if (ref->doc != NULL) {
156#ifdef DEBUG_XINCLUDE
157 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
158#endif
159 xmlFreeDoc(ref->doc);
160 }
161 if (ref->URI != NULL)
162 xmlFree(ref->URI);
163 if (ref->fragment != NULL)
164 xmlFree(ref->fragment);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000165 if (ref->xptr != NULL)
166 xmlXPathFreeObject(ref->xptr);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000167 xmlFree(ref);
168}
169
170/**
171 * xmlXIncludeNewRef:
172 * @ctxt: the XInclude context
173 * @URI: the resource URI
174 *
175 * Creates a new reference within an XInclude context
176 *
177 * Returns the new set
178 */
179static xmlXIncludeRefPtr
180xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
181 xmlNodePtr ref) {
182 xmlXIncludeRefPtr ret;
183
184#ifdef DEBUG_XINCLUDE
185 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
186#endif
187 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000188 if (ret == NULL) {
189 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000190 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000191 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000192 memset(ret, 0, sizeof(xmlXIncludeRef));
193 if (URI == NULL)
194 ret->URI = NULL;
195 else
196 ret->URI = xmlStrdup(URI);
197 ret->fragment = NULL;
198 ret->ref = ref;
199 ret->doc = 0;
200 ret->count = 0;
201 ret->xml = 0;
202 ret->inc = NULL;
203 if (ctxt->incMax == 0) {
204 ctxt->incMax = 4;
205 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
206 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 if (ctxt->incNr >= ctxt->incMax) {
214 ctxt->incMax *= 2;
215 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
216 ctxt->incMax * sizeof(ctxt->incTab[0]));
217 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000218 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000219 xmlXIncludeFreeRef(ret);
220 return(NULL);
221 }
222 }
223 ctxt->incTab[ctxt->incNr++] = ret;
224 return(ret);
225}
226
227/**
Owen Taylor3473f882001-02-23 17:55:21 +0000228 * xmlXIncludeNewContext:
229 * @doc: an XML Document
230 *
231 * Creates a new XInclude context
232 *
233 * Returns the new set
234 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000235static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000236xmlXIncludeNewContext(xmlDocPtr doc) {
237 xmlXIncludeCtxtPtr ret;
238
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000239#ifdef DEBUG_XINCLUDE
240 xmlGenericError(xmlGenericErrorContext, "New context\n");
241#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000242 if (doc == NULL)
243 return(NULL);
244 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000245 if (ret == NULL) {
246 xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
247 "creating XInclude context");
Owen Taylor3473f882001-02-23 17:55:21 +0000248 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000249 }
Owen Taylor3473f882001-02-23 17:55:21 +0000250 memset(ret, 0, sizeof(xmlXIncludeCtxt));
251 ret->doc = doc;
252 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000253 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000254 ret->incMax = 0;
255 ret->incTab = NULL;
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000256 ret->nbErrors = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000257 return(ret);
258}
259
260/**
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000261 * xmlXIncludeURLPush:
262 * @ctxt: the parser context
263 * @value: the url
264 *
265 * Pushes a new url on top of the url stack
266 *
267 * Returns -1 in case of error, the index in the stack otherwise
268 */
269static int
270xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
271 const xmlChar *value)
272{
273 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000274 xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
275 "detected a recursion in %s\n", value);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000276 return(-1);
277 }
278 if (ctxt->urlTab == NULL) {
279 ctxt->urlMax = 4;
280 ctxt->urlNr = 0;
281 ctxt->urlTab = (xmlChar * *) xmlMalloc(
282 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
283 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000284 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000285 return (-1);
286 }
287 }
288 if (ctxt->urlNr >= ctxt->urlMax) {
289 ctxt->urlMax *= 2;
290 ctxt->urlTab =
291 (xmlChar * *) xmlRealloc(ctxt->urlTab,
292 ctxt->urlMax *
293 sizeof(ctxt->urlTab[0]));
294 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000295 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000296 return (-1);
297 }
298 }
299 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
300 return (ctxt->urlNr++);
301}
302
303/**
304 * xmlXIncludeURLPop:
305 * @ctxt: the parser context
306 *
307 * Pops the top url from the url stack
308 */
309static void
310xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
311{
312 xmlChar * ret;
313
314 if (ctxt->urlNr <= 0)
315 return;
316 ctxt->urlNr--;
317 if (ctxt->urlNr > 0)
318 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
319 else
320 ctxt->url = NULL;
321 ret = ctxt->urlTab[ctxt->urlNr];
322 ctxt->urlTab[ctxt->urlNr] = 0;
323 if (ret != NULL)
324 xmlFree(ret);
325}
326
327/**
Owen Taylor3473f882001-02-23 17:55:21 +0000328 * xmlXIncludeFreeContext:
329 * @ctxt: the XInclude context
330 *
331 * Free an XInclude context
332 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000333static void
Owen Taylor3473f882001-02-23 17:55:21 +0000334xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
335 int i;
336
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000337#ifdef DEBUG_XINCLUDE
338 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
339#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000340 if (ctxt == NULL)
341 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000342 while (ctxt->urlNr > 0)
343 xmlXIncludeURLPop(ctxt);
344 if (ctxt->urlTab != NULL)
345 xmlFree(ctxt->urlTab);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000346 for (i = 0;i < ctxt->incNr;i++) {
347 if (ctxt->incTab[i] != NULL)
348 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000349 }
350 for (i = 0;i < ctxt->txtNr;i++) {
351 if (ctxt->txturlTab[i] != NULL)
352 xmlFree(ctxt->txturlTab[i]);
353 }
354 if (ctxt->incTab != NULL)
355 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000356 if (ctxt->txtTab != NULL)
357 xmlFree(ctxt->txtTab);
358 if (ctxt->txturlTab != NULL)
359 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000360 xmlFree(ctxt);
361}
362
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000363/**
Daniel Veillard98485322003-08-14 15:44:40 +0000364 * xmlXIncludeParseFile:
365 * @ctxt: the XInclude context
366 * @URL: the URL or file path
367 *
368 * parse an document for XInclude
369 */
370static xmlDocPtr
371xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt ATTRIBUTE_UNUSED, const char *URL) {
372 xmlDocPtr ret;
373 xmlParserCtxtPtr pctxt;
374 char *directory = NULL;
375
376 xmlInitParser();
377
378 pctxt = xmlCreateFileParserCtxt(URL);
379 if (pctxt == NULL) {
380 return(NULL);
381 }
382
383 if ((pctxt->directory == NULL) && (directory == NULL))
384 directory = xmlParserGetDirectory(URL);
385 if ((pctxt->directory == NULL) && (directory != NULL))
386 pctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
387
388 pctxt->loadsubset = XML_DETECT_IDS;
389
390 xmlParseDocument(pctxt);
391
392 if (pctxt->wellFormed)
393 ret = pctxt->myDoc;
394 else {
395 ret = NULL;
396 xmlFreeDoc(pctxt->myDoc);
397 pctxt->myDoc = NULL;
398 }
399 xmlFreeParserCtxt(pctxt);
400
401 return(ret);
402}
403
404/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000405 * xmlXIncludeAddNode:
406 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000407 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000408 *
409 * Add a new node to process to an XInclude context
410 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000411static int
412xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
413 xmlXIncludeRefPtr ref;
414 xmlURIPtr uri;
415 xmlChar *URL;
416 xmlChar *fragment = NULL;
417 xmlChar *href;
418 xmlChar *parse;
419 xmlChar *base;
420 xmlChar *URI;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000421 int xml = 1, i; /* default Issue 64 */
422 int local = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000423
424
425 if (ctxt == NULL)
426 return(-1);
427 if (cur == NULL)
428 return(-1);
429
430#ifdef DEBUG_XINCLUDE
431 xmlGenericError(xmlGenericErrorContext, "Add node\n");
432#endif
433 /*
434 * read the attributes
435 */
436 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
437 if (href == NULL) {
438 href = xmlGetProp(cur, XINCLUDE_HREF);
439 if (href == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000440 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_NO_HREF,
441 "no href\n", NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000442 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000443 }
444 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000445 if (href[0] == '#')
446 local = 1;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000447 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
448 if (parse == NULL) {
449 parse = xmlGetProp(cur, XINCLUDE_PARSE);
450 }
451 if (parse != NULL) {
452 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
453 xml = 1;
454 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
455 xml = 0;
456 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000457 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
458 "invalid value %s for 'parse'\n", parse);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000459 if (href != NULL)
460 xmlFree(href);
461 if (parse != NULL)
462 xmlFree(parse);
463 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000464 }
465 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000466
467 /*
468 * compute the URI
469 */
470 base = xmlNodeGetBase(ctxt->doc, cur);
471 if (base == NULL) {
472 URI = xmlBuildURI(href, ctxt->doc->URL);
473 } else {
474 URI = xmlBuildURI(href, base);
475 }
476 if (URI == NULL) {
477 xmlChar *escbase;
478 xmlChar *eschref;
479 /*
480 * Some escaping may be needed
481 */
482 escbase = xmlURIEscape(base);
483 eschref = xmlURIEscape(href);
484 URI = xmlBuildURI(eschref, escbase);
485 if (escbase != NULL)
486 xmlFree(escbase);
487 if (eschref != NULL)
488 xmlFree(eschref);
489 }
490 if (parse != NULL)
491 xmlFree(parse);
492 if (href != NULL)
493 xmlFree(href);
494 if (base != NULL)
495 xmlFree(base);
496 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000497 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
498 "failed build URL\n", NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000499 return(-1);
500 }
501
502 /*
503 * Check the URL and remove any fragment identifier
504 */
505 uri = xmlParseURI((const char *)URI);
506 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000507 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
508 "invalid value URI %s\n", URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000509 return(-1);
510 }
511 if (uri->fragment != NULL) {
512 fragment = (xmlChar *) uri->fragment;
513 uri->fragment = NULL;
514 }
515 URL = xmlSaveUri(uri);
516 xmlFreeURI(uri);
517 xmlFree(URI);
518 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000519 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
520 "invalid value URI %s\n", URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000521 if (fragment != NULL)
522 xmlFree(fragment);
523 return(-1);
524 }
525
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000526 /*
527 * Check the URL against the stack for recursions
528 */
529 if (!local) {
530 for (i = 0;i < ctxt->urlNr;i++) {
531 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000532 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
533 "detected a recursion in %s\n", URL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000534 return(-1);
535 }
536 }
537 }
538
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000539 ref = xmlXIncludeNewRef(ctxt, URL, cur);
540 if (ref == NULL) {
541 return(-1);
542 }
543 ref->fragment = fragment;
544 ref->doc = NULL;
545 ref->xml = xml;
546 ref->count = 1;
547 xmlFree(URL);
548 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000549}
550
551/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000552 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000553 * @ctxt: the XInclude context
554 * @doc: the new document
555 * @url: the associated URL
556 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000557 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000558 */
559static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000560xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000561 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000562 xmlXIncludeCtxtPtr newctxt;
563 int i;
564
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000565 /*
566 * Avoid recursion in already substitued resources
567 for (i = 0;i < ctxt->urlNr;i++) {
568 if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
569 return;
570 }
571 */
572
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000573#ifdef DEBUG_XINCLUDE
574 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
575#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000576 /*
577 * Handle recursion here.
578 */
579
580 newctxt = xmlXIncludeNewContext(doc);
581 if (newctxt != NULL) {
582 /*
583 * Copy the existing document set
584 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000585 newctxt->incMax = ctxt->incMax;
586 newctxt->incNr = ctxt->incNr;
587 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
588 sizeof(newctxt->incTab[0]));
589 if (newctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000590 xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000591 xmlFree(newctxt);
592 return;
593 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000594 /*
595 * copy the urlTab
596 */
597 newctxt->urlMax = ctxt->urlMax;
598 newctxt->urlNr = ctxt->urlNr;
599 newctxt->urlTab = ctxt->urlTab;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000600
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000601 /*
602 * Inherit the documents already in use by others includes
603 */
604 newctxt->incBase = ctxt->incNr;
605 for (i = 0;i < ctxt->incNr;i++) {
606 newctxt->incTab[i] = ctxt->incTab[i];
607 newctxt->incTab[i]->count++; /* prevent the recursion from
608 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000609 }
Daniel Veillard8edf1c52003-07-22 20:52:14 +0000610 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000611 for (i = 0;i < ctxt->incNr;i++) {
612 newctxt->incTab[i]->count--;
613 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000614 }
Daniel Veillardd9b72832003-03-27 14:24:00 +0000615
616 /* urlTab may have been reallocated */
617 ctxt->urlTab = newctxt->urlTab;
618 ctxt->urlMax = newctxt->urlMax;
619
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000620 newctxt->urlMax = 0;
621 newctxt->urlNr = 0;
622 newctxt->urlTab = NULL;
623
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000624 xmlXIncludeFreeContext(newctxt);
625 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000626#ifdef DEBUG_XINCLUDE
627 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
628#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000629}
630
631/**
632 * xmlXIncludeAddTxt:
633 * @ctxt: the XInclude context
634 * @txt: the new text node
635 * @url: the associated URL
636 *
637 * Add a new txtument to the list
638 */
639static void
640xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000641#ifdef DEBUG_XINCLUDE
642 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
643#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000644 if (ctxt->txtMax == 0) {
645 ctxt->txtMax = 4;
646 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
647 sizeof(ctxt->txtTab[0]));
648 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000649 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000650 return;
651 }
652 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
653 sizeof(ctxt->txturlTab[0]));
654 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000655 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000656 return;
657 }
658 }
659 if (ctxt->txtNr >= ctxt->txtMax) {
660 ctxt->txtMax *= 2;
661 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
662 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
663 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000664 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000665 return;
666 }
667 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000668 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000669 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000670 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000671 return;
672 }
673 }
674 ctxt->txtTab[ctxt->txtNr] = txt;
675 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
676 ctxt->txtNr++;
677}
678
Owen Taylor3473f882001-02-23 17:55:21 +0000679/************************************************************************
680 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000681 * Node copy with specific semantic *
682 * *
683 ************************************************************************/
684
685/**
686 * xmlXIncludeCopyNode:
687 * @ctxt: the XInclude context
688 * @target: the document target
689 * @source: the document source
690 * @elem: the element
691 *
692 * Make a copy of the node while preserving the XInclude semantic
693 * of the Infoset copy
694 */
695static xmlNodePtr
696xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
697 xmlDocPtr source, xmlNodePtr elem) {
698 xmlNodePtr result = NULL;
699
700 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
701 (elem == NULL))
702 return(NULL);
703 if (elem->type == XML_DTD_NODE)
704 return(NULL);
705 result = xmlDocCopyNode(elem, target, 1);
706 return(result);
707}
708
709/**
710 * xmlXIncludeCopyNodeList:
711 * @ctxt: the XInclude context
712 * @target: the document target
713 * @source: the document source
714 * @elem: the element list
715 *
716 * Make a copy of the node list while preserving the XInclude semantic
717 * of the Infoset copy
718 */
719static xmlNodePtr
720xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
721 xmlDocPtr source, xmlNodePtr elem) {
722 xmlNodePtr cur, res, result = NULL, last = NULL;
723
724 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
725 (elem == NULL))
726 return(NULL);
727 cur = elem;
728 while (cur != NULL) {
729 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
730 if (res != NULL) {
731 if (result == NULL) {
732 result = last = res;
733 } else {
734 last->next = res;
735 res->prev = last;
736 last = res;
737 }
738 }
739 cur = cur->next;
740 }
741 return(result);
742}
743
744/**
745 * xmlXInclueGetNthChild:
746 * @cur: the node
747 * @no: the child number
748 *
749 * Returns the @no'th element child of @cur or NULL
750 */
751static xmlNodePtr
752xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
753 int i;
754 if (cur == NULL)
755 return(cur);
756 cur = cur->children;
757 for (i = 0;i <= no;cur = cur->next) {
758 if (cur == NULL)
759 return(cur);
760 if ((cur->type == XML_ELEMENT_NODE) ||
761 (cur->type == XML_DOCUMENT_NODE) ||
762 (cur->type == XML_HTML_DOCUMENT_NODE)) {
763 i++;
764 if (i == no)
765 break;
766 }
767 }
768 return(cur);
769}
770
771xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
772
773/**
774 * xmlXIncludeCopyRange:
775 * @ctxt: the XInclude context
776 * @target: the document target
777 * @source: the document source
778 * @obj: the XPointer result from the evaluation.
779 *
780 * Build a node list tree copy of the XPointer result.
781 *
782 * Returns an xmlNodePtr list or NULL.
783 * the caller has to free the node tree.
784 */
785static xmlNodePtr
786xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
787 xmlDocPtr source, xmlXPathObjectPtr range) {
788 /* pointers to generated nodes */
789 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
790 /* pointers to traversal nodes */
791 xmlNodePtr start, cur, end;
792 int index1, index2;
793
794 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
795 (range == NULL))
796 return(NULL);
797 if (range->type != XPATH_RANGE)
798 return(NULL);
799 start = (xmlNodePtr) range->user;
800
801 if (start == NULL)
802 return(NULL);
803 end = range->user2;
804 if (end == NULL)
805 return(xmlDocCopyNode(start, target, 1));
806
807 cur = start;
808 index1 = range->index;
809 index2 = range->index2;
810 while (cur != NULL) {
811 if (cur == end) {
812 if (cur->type == XML_TEXT_NODE) {
813 const xmlChar *content = cur->content;
814 int len;
815
816 if (content == NULL) {
817 tmp = xmlNewTextLen(NULL, 0);
818 } else {
819 len = index2;
820 if ((cur == start) && (index1 > 1)) {
821 content += (index1 - 1);
822 len -= (index1 - 1);
823 index1 = 0;
824 } else {
825 len = index2;
826 }
827 tmp = xmlNewTextLen(content, len);
828 }
829 /* single sub text node selection */
830 if (list == NULL)
831 return(tmp);
832 /* prune and return full set */
833 if (last != NULL)
834 xmlAddNextSibling(last, tmp);
835 else
836 xmlAddChild(parent, tmp);
837 return(list);
838 } else {
839 tmp = xmlDocCopyNode(cur, target, 0);
840 if (list == NULL)
841 list = tmp;
842 else {
843 if (last != NULL)
844 xmlAddNextSibling(last, tmp);
845 else
846 xmlAddChild(parent, tmp);
847 }
848 last = NULL;
849 parent = tmp;
850
851 if (index2 > 1) {
852 end = xmlXIncludeGetNthChild(cur, index2 - 1);
853 index2 = 0;
854 }
855 if ((cur == start) && (index1 > 1)) {
856 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
857 index1 = 0;
858 } else {
859 cur = cur->children;
860 }
861 /*
862 * Now gather the remaining nodes from cur to end
863 */
864 continue; /* while */
865 }
866 } else if ((cur == start) &&
867 (list == NULL) /* looks superfluous but ... */ ) {
868 if ((cur->type == XML_TEXT_NODE) ||
869 (cur->type == XML_CDATA_SECTION_NODE)) {
870 const xmlChar *content = cur->content;
871
872 if (content == NULL) {
873 tmp = xmlNewTextLen(NULL, 0);
874 } else {
875 if (index1 > 1) {
876 content += (index1 - 1);
877 }
878 tmp = xmlNewText(content);
879 }
880 last = list = tmp;
881 } else {
882 if ((cur == start) && (index1 > 1)) {
883 tmp = xmlDocCopyNode(cur, target, 0);
884 list = tmp;
885 parent = tmp;
886 last = NULL;
887 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
888 index1 = 0;
889 /*
890 * Now gather the remaining nodes from cur to end
891 */
892 continue; /* while */
893 }
894 tmp = xmlDocCopyNode(cur, target, 1);
895 list = tmp;
896 parent = NULL;
897 last = tmp;
898 }
899 } else {
900 tmp = NULL;
901 switch (cur->type) {
902 case XML_DTD_NODE:
903 case XML_ELEMENT_DECL:
904 case XML_ATTRIBUTE_DECL:
905 case XML_ENTITY_NODE:
906 /* Do not copy DTD informations */
907 break;
908 case XML_ENTITY_DECL:
909 /* handle crossing entities -> stack needed */
910 break;
911 case XML_XINCLUDE_START:
912 case XML_XINCLUDE_END:
913 /* don't consider it part of the tree content */
914 break;
915 case XML_ATTRIBUTE_NODE:
916 /* Humm, should not happen ! */
917 break;
918 default:
919 tmp = xmlDocCopyNode(cur, target, 1);
920 break;
921 }
922 if (tmp != NULL) {
923 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
924 return(NULL);
925 }
926 if (last != NULL)
927 xmlAddNextSibling(last, tmp);
928 else {
929 xmlAddChild(parent, tmp);
930 last = tmp;
931 }
932 }
933 }
934 /*
935 * Skip to next node in document order
936 */
937 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
938 return(NULL);
939 }
940 cur = xmlXPtrAdvanceNode(cur);
941 }
942 return(list);
943}
944
945/**
946 * xmlXIncludeBuildNodeList:
947 * @ctxt: the XInclude context
948 * @target: the document target
949 * @source: the document source
950 * @obj: the XPointer result from the evaluation.
951 *
952 * Build a node list tree copy of the XPointer result.
953 * This will drop Attributes and Namespace declarations.
954 *
955 * Returns an xmlNodePtr list or NULL.
956 * the caller has to free the node tree.
957 */
958static xmlNodePtr
959xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
960 xmlDocPtr source, xmlXPathObjectPtr obj) {
961 xmlNodePtr list = NULL, last = NULL;
962 int i;
963
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000964 if (source == NULL)
965 source = ctxt->doc;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000966 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
967 (obj == NULL))
968 return(NULL);
969 switch (obj->type) {
970 case XPATH_NODESET: {
971 xmlNodeSetPtr set = obj->nodesetval;
972 if (set == NULL)
973 return(NULL);
974 for (i = 0;i < set->nodeNr;i++) {
975 if (set->nodeTab[i] == NULL)
976 continue;
977 switch (set->nodeTab[i]->type) {
978 case XML_TEXT_NODE:
979 case XML_CDATA_SECTION_NODE:
980 case XML_ELEMENT_NODE:
981 case XML_ENTITY_REF_NODE:
982 case XML_ENTITY_NODE:
983 case XML_PI_NODE:
984 case XML_COMMENT_NODE:
985 case XML_DOCUMENT_NODE:
986 case XML_HTML_DOCUMENT_NODE:
987#ifdef LIBXML_DOCB_ENABLED
988 case XML_DOCB_DOCUMENT_NODE:
989#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000990 case XML_XINCLUDE_END:
991 break;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000992 case XML_XINCLUDE_START: {
993 xmlNodePtr tmp, cur = set->nodeTab[i];
994
995 cur = cur->next;
996 while (cur != NULL) {
997 switch(cur->type) {
998 case XML_TEXT_NODE:
999 case XML_CDATA_SECTION_NODE:
1000 case XML_ELEMENT_NODE:
1001 case XML_ENTITY_REF_NODE:
1002 case XML_ENTITY_NODE:
1003 case XML_PI_NODE:
1004 case XML_COMMENT_NODE:
1005 tmp = xmlXIncludeCopyNode(ctxt, target,
1006 source, cur);
1007 if (last == NULL) {
1008 list = last = tmp;
1009 } else {
1010 xmlAddNextSibling(last, tmp);
1011 last = tmp;
1012 }
1013 cur = cur->next;
1014 continue;
1015 default:
1016 break;
1017 }
1018 break;
1019 }
1020 continue;
1021 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001022 case XML_ATTRIBUTE_NODE:
1023 case XML_NAMESPACE_DECL:
1024 case XML_DOCUMENT_TYPE_NODE:
1025 case XML_DOCUMENT_FRAG_NODE:
1026 case XML_NOTATION_NODE:
1027 case XML_DTD_NODE:
1028 case XML_ELEMENT_DECL:
1029 case XML_ATTRIBUTE_DECL:
1030 case XML_ENTITY_DECL:
1031 continue; /* for */
1032 }
1033 if (last == NULL)
1034 list = last = xmlXIncludeCopyNode(ctxt, target, source,
1035 set->nodeTab[i]);
1036 else {
1037 xmlAddNextSibling(last,
1038 xmlXIncludeCopyNode(ctxt, target, source,
1039 set->nodeTab[i]));
1040 if (last->next != NULL)
1041 last = last->next;
1042 }
1043 }
1044 break;
1045 }
1046 case XPATH_LOCATIONSET: {
1047 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1048 if (set == NULL)
1049 return(NULL);
1050 for (i = 0;i < set->locNr;i++) {
1051 if (last == NULL)
1052 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
1053 set->locTab[i]);
1054 else
1055 xmlAddNextSibling(last,
1056 xmlXIncludeCopyXPointer(ctxt, target, source,
1057 set->locTab[i]));
1058 if (last != NULL) {
1059 while (last->next != NULL)
1060 last = last->next;
1061 }
1062 }
1063 break;
1064 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001065#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001066 case XPATH_RANGE:
1067 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001068#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001069 case XPATH_POINT:
1070 /* points are ignored in XInclude */
1071 break;
1072 default:
1073 break;
1074 }
1075 return(list);
1076}
1077/************************************************************************
1078 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001079 * XInclude I/O handling *
1080 * *
1081 ************************************************************************/
1082
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001083typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1084typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1085struct _xmlXIncludeMergeData {
1086 xmlDocPtr doc;
1087 xmlXIncludeCtxtPtr ctxt;
1088};
1089
Owen Taylor3473f882001-02-23 17:55:21 +00001090/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001091 * xmlXIncludeMergeOneEntity:
1092 * @ent: the entity
1093 * @doc: the including doc
1094 * @nr: the entity name
1095 *
1096 * Inplements the merge of one entity
1097 */
1098static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001099xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001100 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001101 xmlEntityPtr ret, prev;
1102 xmlDocPtr doc;
1103 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001104
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001105 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001106 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001107 ctxt = data->ctxt;
1108 doc = data->doc;
1109 if ((ctxt == NULL) || (doc == NULL))
1110 return;
1111 switch (ent->etype) {
1112 case XML_INTERNAL_PARAMETER_ENTITY:
1113 case XML_EXTERNAL_PARAMETER_ENTITY:
1114 case XML_INTERNAL_PREDEFINED_ENTITY:
1115 return;
1116 case XML_INTERNAL_GENERAL_ENTITY:
1117 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1118 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1119 break;
1120 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001121 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1122 ent->SystemID, ent->content);
1123 if (ret != NULL) {
1124 if (ent->URI != NULL)
1125 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001126 } else {
1127 prev = xmlGetDocEntity(doc, ent->name);
1128 if (prev != NULL) {
1129 if (ent->etype != prev->etype)
1130 goto error;
1131
1132 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1133 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1134 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001135 } else if ((ent->ExternalID != NULL) &&
1136 (prev->ExternalID != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001137 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1138 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001139 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1140 if (!xmlStrEqual(ent->content, prev->content))
1141 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001142 } else {
1143 goto error;
1144 }
1145
1146 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001147 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001148 return;
1149error:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001150 switch (ent->etype) {
1151 case XML_INTERNAL_PARAMETER_ENTITY:
1152 case XML_EXTERNAL_PARAMETER_ENTITY:
1153 case XML_INTERNAL_PREDEFINED_ENTITY:
1154 case XML_INTERNAL_GENERAL_ENTITY:
1155 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1156 return;
1157 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1158 break;
1159 }
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001160 xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
1161 "mismatch in redefinition of entity %s\n",
1162 ent->name);
Daniel Veillard4287c572003-02-04 22:48:53 +00001163}
1164
1165/**
1166 * xmlXIncludeMergeEntities:
1167 * @ctxt: an XInclude context
1168 * @doc: the including doc
1169 * @from: the included doc
1170 *
1171 * Inplements the entity merge
1172 *
1173 * Returns 0 if merge succeeded, -1 if some processing failed
1174 */
1175static int
1176xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1177 xmlDocPtr from) {
1178 xmlNodePtr cur;
1179 xmlDtdPtr target, source;
1180
1181 if (ctxt == NULL)
1182 return(-1);
1183
1184 if ((from == NULL) || (from->intSubset == NULL))
1185 return(0);
1186
1187 target = doc->intSubset;
1188 if (target == NULL) {
1189 cur = xmlDocGetRootElement(doc);
1190 if (cur == NULL)
1191 return(-1);
1192 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1193 if (target == NULL)
1194 return(-1);
1195 }
1196
1197 source = from->intSubset;
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 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001205 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001206 }
1207 source = from->extSubset;
1208 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001209 xmlXIncludeMergeData data;
1210
1211 data.ctxt = ctxt;
1212 data.doc = doc;
1213
Daniel Veillard4287c572003-02-04 22:48:53 +00001214 /*
1215 * don't duplicate existing stuff when external subsets are the same
1216 */
1217 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1218 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1219 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001220 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001221 }
1222 }
1223 return(0);
1224}
1225
1226/**
Owen Taylor3473f882001-02-23 17:55:21 +00001227 * xmlXIncludeLoadDoc:
1228 * @ctxt: the XInclude context
1229 * @url: the associated URL
1230 * @nr: the xinclude node number
1231 *
1232 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001233 *
1234 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001235 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001236static int
Owen Taylor3473f882001-02-23 17:55:21 +00001237xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1238 xmlDocPtr doc;
1239 xmlURIPtr uri;
1240 xmlChar *URL;
1241 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001242 int i = 0;
1243
1244#ifdef DEBUG_XINCLUDE
1245 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1246#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001247 /*
1248 * Check the URL and remove any fragment identifier
1249 */
1250 uri = xmlParseURI((const char *)url);
1251 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001252 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1253 XML_XINCLUDE_HREF_URI,
1254 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001255 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001256 }
1257 if (uri->fragment != NULL) {
1258 fragment = (xmlChar *) uri->fragment;
1259 uri->fragment = NULL;
1260 }
1261 URL = xmlSaveUri(uri);
1262 xmlFreeURI(uri);
1263 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001264 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1265 XML_XINCLUDE_HREF_URI,
1266 "invalid value URI %s\n", url);
Owen Taylor3473f882001-02-23 17:55:21 +00001267 if (fragment != NULL)
1268 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001269 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001270 }
1271
1272 /*
1273 * Handling of references to the local document are done
1274 * directly through ctxt->doc.
1275 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001276 if ((URL[0] == 0) || (URL[0] == '#') ||
1277 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001278 doc = NULL;
1279 goto loaded;
1280 }
1281
1282 /*
1283 * Prevent reloading twice the document.
1284 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001285 for (i = 0; i < ctxt->incNr; i++) {
1286 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1287 (ctxt->incTab[i]->doc != NULL)) {
1288 doc = ctxt->incTab[i]->doc;
1289#ifdef DEBUG_XINCLUDE
1290 printf("Already loaded %s\n", URL);
1291#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001292 goto loaded;
1293 }
1294 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001295
Owen Taylor3473f882001-02-23 17:55:21 +00001296 /*
1297 * Load it.
1298 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001299#ifdef DEBUG_XINCLUDE
1300 printf("loading %s\n", URL);
1301#endif
Daniel Veillard98485322003-08-14 15:44:40 +00001302 doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001303 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001304 xmlFree(URL);
1305 if (fragment != NULL)
1306 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001307 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001308 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001309 ctxt->incTab[nr]->doc = doc;
Daniel Veillard98485322003-08-14 15:44:40 +00001310 for (i = nr + 1; i < ctxt->incNr; i++) {
1311 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1312 ctxt->incTab[nr]->count++;
1313#ifdef DEBUG_XINCLUDE
1314 printf("Increasing %s count since reused\n", URL);
1315#endif
1316 break;
1317 }
1318 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001319
1320 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001321 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001322 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001323 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001324
1325 /*
1326 * We don't need the DTD anymore, free up space
1327 if (doc->intSubset != NULL) {
1328 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1329 xmlFreeNode((xmlNodePtr) doc->intSubset);
1330 doc->intSubset = NULL;
1331 }
1332 if (doc->extSubset != NULL) {
1333 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1334 xmlFreeNode((xmlNodePtr) doc->extSubset);
1335 doc->extSubset = NULL;
1336 }
1337 */
1338 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001339
1340loaded:
1341 if (fragment == NULL) {
1342 /*
1343 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001344 */
1345 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001346 {
1347 /* Hopefully a DTD declaration won't be copied from
1348 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001349 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001350 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001351 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001352 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001353 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001354 }
1355#ifdef LIBXML_XPTR_ENABLED
1356 else {
Owen Taylor3473f882001-02-23 17:55:21 +00001357 /*
1358 * Computes the XPointer expression and make a copy used
1359 * as the replacement copy.
1360 */
1361 xmlXPathObjectPtr xptr;
1362 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001363 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001364
1365 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001366 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1367 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001368 } else {
1369 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1370 }
1371 if (xptrctxt == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001372 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1373 XML_XINCLUDE_XPTR_FAILED,
1374 "could create XPointer context\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001375 xmlFree(URL);
1376 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001377 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001378 }
1379 xptr = xmlXPtrEval(fragment, xptrctxt);
1380 if (xptr == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001381 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1382 XML_XINCLUDE_XPTR_FAILED,
1383 "XPointer evaluation failed: #%s\n",
1384 fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001385 xmlXPathFreeContext(xptrctxt);
1386 xmlFree(URL);
1387 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001388 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001389 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001390 switch (xptr->type) {
1391 case XPATH_UNDEFINED:
1392 case XPATH_BOOLEAN:
1393 case XPATH_NUMBER:
1394 case XPATH_STRING:
1395 case XPATH_POINT:
1396 case XPATH_USERS:
1397 case XPATH_XSLT_TREE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001398 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1399 XML_XINCLUDE_XPTR_RESULT,
1400 "XPointer is not a range: #%s\n",
1401 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001402 xmlXPathFreeContext(xptrctxt);
1403 xmlFree(URL);
1404 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001405 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001406 case XPATH_NODESET:
1407 case XPATH_RANGE:
1408 case XPATH_LOCATIONSET:
1409 break;
1410 }
1411 set = xptr->nodesetval;
1412 if (set != NULL) {
1413 for (i = 0;i < set->nodeNr;i++) {
1414 if (set->nodeTab[i] == NULL)
1415 continue;
1416 switch (set->nodeTab[i]->type) {
1417 case XML_TEXT_NODE:
1418 case XML_CDATA_SECTION_NODE:
1419 case XML_ELEMENT_NODE:
1420 case XML_ENTITY_REF_NODE:
1421 case XML_ENTITY_NODE:
1422 case XML_PI_NODE:
1423 case XML_COMMENT_NODE:
1424 case XML_DOCUMENT_NODE:
1425 case XML_HTML_DOCUMENT_NODE:
1426#ifdef LIBXML_DOCB_ENABLED
1427 case XML_DOCB_DOCUMENT_NODE:
1428#endif
1429 continue;
1430 case XML_ATTRIBUTE_NODE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001431 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1432 XML_XINCLUDE_XPTR_RESULT,
1433 "XPointer selects an attribute: #%s\n",
1434 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001435 set->nodeTab[i] = NULL;
1436 continue;
1437 case XML_NAMESPACE_DECL:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001438 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1439 XML_XINCLUDE_XPTR_RESULT,
1440 "XPointer selects a namespace: #%s\n",
1441 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001442 set->nodeTab[i] = NULL;
1443 continue;
1444 case XML_DOCUMENT_TYPE_NODE:
1445 case XML_DOCUMENT_FRAG_NODE:
1446 case XML_NOTATION_NODE:
1447 case XML_DTD_NODE:
1448 case XML_ELEMENT_DECL:
1449 case XML_ATTRIBUTE_DECL:
1450 case XML_ENTITY_DECL:
1451 case XML_XINCLUDE_START:
1452 case XML_XINCLUDE_END:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001453 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1454 XML_XINCLUDE_XPTR_RESULT,
1455 "XPointer selects unexpected nodes: #%s\n",
1456 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001457 set->nodeTab[i] = NULL;
1458 set->nodeTab[i] = NULL;
1459 continue; /* for */
1460 }
1461 }
1462 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001463 if (doc == NULL) {
1464 ctxt->incTab[nr]->xptr = xptr;
1465 ctxt->incTab[nr]->inc = NULL;
1466 } else {
1467 ctxt->incTab[nr]->inc =
1468 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1469 xmlXPathFreeObject(xptr);
1470 }
Owen Taylor3473f882001-02-23 17:55:21 +00001471 xmlXPathFreeContext(xptrctxt);
1472 xmlFree(fragment);
1473 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001474#endif
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001475
1476 /*
1477 * Do the xml:base fixup if needed
1478 */
1479 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1480 xmlNodePtr node;
1481
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001482 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001483 while (node != NULL) {
1484 if (node->type == XML_ELEMENT_NODE)
1485 xmlNodeSetBase(node, URL);
1486 node = node->next;
1487 }
1488 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001489 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1490 (ctxt->incTab[nr]->count <= 1)) {
1491#ifdef DEBUG_XINCLUDE
1492 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1493#endif
1494 xmlFreeDoc(ctxt->incTab[nr]->doc);
1495 ctxt->incTab[nr]->doc = NULL;
1496 }
Owen Taylor3473f882001-02-23 17:55:21 +00001497 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001498 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001499}
1500
1501/**
1502 * xmlXIncludeLoadTxt:
1503 * @ctxt: the XInclude context
1504 * @url: the associated URL
1505 * @nr: the xinclude node number
1506 *
1507 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001508 *
1509 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001510 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001511static int
Owen Taylor3473f882001-02-23 17:55:21 +00001512xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1513 xmlParserInputBufferPtr buf;
1514 xmlNodePtr node;
1515 xmlURIPtr uri;
1516 xmlChar *URL;
1517 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001518 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001519 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001520
Owen Taylor3473f882001-02-23 17:55:21 +00001521 /*
1522 * Check the URL and remove any fragment identifier
1523 */
1524 uri = xmlParseURI((const char *)url);
1525 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001526 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1527 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001528 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001529 }
1530 if (uri->fragment != NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001531 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1532 "fragment identifier forbidden for text: %s\n",
1533 (const xmlChar *) uri->fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001534 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001535 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 }
1537 URL = xmlSaveUri(uri);
1538 xmlFreeURI(uri);
1539 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001540 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1541 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001542 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001543 }
1544
1545 /*
1546 * Handling of references to the local document are done
1547 * directly through ctxt->doc.
1548 */
1549 if (URL[0] == 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001550 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1551 XML_XINCLUDE_TEXT_DOCUMENT,
1552 "text serialization of document not available\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001553 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001554 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001555 }
1556
1557 /*
1558 * Prevent reloading twice the document.
1559 */
1560 for (i = 0; i < ctxt->txtNr; i++) {
1561 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1562 node = xmlCopyNode(ctxt->txtTab[i], 1);
1563 goto loaded;
1564 }
1565 }
1566 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001567 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001568 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001569 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1570 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1571 }
1572 if (encoding != NULL) {
1573 /*
1574 * TODO: we should not have to remap to the xmlCharEncoding
1575 * predefined set, a better interface than
1576 * xmlParserInputBufferCreateFilename should allow any
1577 * encoding supported by iconv
1578 */
1579 enc = xmlParseCharEncoding((const char *) encoding);
1580 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001581 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1582 XML_XINCLUDE_UNKNOWN_ENCODING,
1583 "encoding %s not supported\n", encoding);
Daniel Veillardd076a202002-11-20 13:28:31 +00001584 xmlFree(encoding);
1585 xmlFree(URL);
1586 return(-1);
1587 }
1588 xmlFree(encoding);
1589 }
1590
1591 /*
1592 * Load it.
1593 */
1594 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001595 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001596 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001597 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001598 }
1599 node = xmlNewText(NULL);
1600
1601 /*
1602 * Scan all chars from the resource and add the to the node
1603 */
1604 while (xmlParserInputBufferRead(buf, 128) > 0) {
1605 int len;
1606 const xmlChar *content;
1607
1608 content = xmlBufferContent(buf->buffer);
1609 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001610 for (i = 0;i < len;) {
1611 int cur;
1612 int l;
1613
1614 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1615 if (!IS_CHAR(cur)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001616 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1617 XML_XINCLUDE_INVALID_CHAR,
1618 "%s contains invalid char\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001619 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001620 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001621 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001622 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001623 }
1624 xmlBufferShrink(buf->buffer, len);
1625 }
1626 xmlFreeParserInputBuffer(buf);
1627 xmlXIncludeAddTxt(ctxt, node, URL);
1628
1629loaded:
1630 /*
1631 * Add the element as the replacement copy.
1632 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001633 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001634 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001635 return(0);
1636}
1637
1638/**
1639 * xmlXIncludeLoadFallback:
1640 * @ctxt: the XInclude context
1641 * @fallback: the fallback node
1642 * @nr: the xinclude node number
1643 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001644 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001645 * in the XInclude context
1646 *
1647 * Returns 0 in case of success, -1 in case of failure
1648 */
1649static int
1650xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1651 if ((fallback == NULL) || (ctxt == NULL))
1652 return(-1);
1653
Daniel Veillard06503452002-12-13 10:42:08 +00001654 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001655 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001656}
1657
1658/************************************************************************
1659 * *
1660 * XInclude Processing *
1661 * *
1662 ************************************************************************/
1663
1664/**
1665 * xmlXIncludePreProcessNode:
1666 * @ctxt: an XInclude context
1667 * @node: an XInclude node
1668 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001669 * Implement the XInclude preprocessing, currently just adding the element
1670 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001671 *
1672 * Returns the result list or NULL in case of error
1673 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001674static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001675xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1676 xmlXIncludeAddNode(ctxt, node);
1677 return(0);
1678}
1679
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001680/**
Owen Taylor3473f882001-02-23 17:55:21 +00001681 * xmlXIncludeLoadNode:
1682 * @ctxt: an XInclude context
1683 * @nr: the node number
1684 *
1685 * Find and load the infoset replacement for the given node.
1686 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001687 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001688 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001689static int
Owen Taylor3473f882001-02-23 17:55:21 +00001690xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1691 xmlNodePtr cur;
1692 xmlChar *href;
1693 xmlChar *parse;
1694 xmlChar *base;
1695 xmlChar *URI;
1696 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001697 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001698
1699 if (ctxt == NULL)
1700 return(-1);
1701 if ((nr < 0) || (nr >= ctxt->incNr))
1702 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001703 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001704 if (cur == NULL)
1705 return(-1);
1706
Owen Taylor3473f882001-02-23 17:55:21 +00001707 /*
1708 * read the attributes
1709 */
1710 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1711 if (href == NULL) {
1712 href = xmlGetProp(cur, XINCLUDE_HREF);
1713 if (href == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001714 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1715 XML_XINCLUDE_NO_HREF, "no href\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001716 return(-1);
1717 }
1718 }
1719 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1720 if (parse == NULL) {
1721 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1722 }
1723 if (parse != NULL) {
1724 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1725 xml = 1;
1726 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1727 xml = 0;
1728 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001729 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1730 XML_XINCLUDE_PARSE_VALUE,
1731 "invalid value %s for 'parse'\n", parse);
Owen Taylor3473f882001-02-23 17:55:21 +00001732 if (href != NULL)
1733 xmlFree(href);
1734 if (parse != NULL)
1735 xmlFree(parse);
1736 return(-1);
1737 }
1738 }
1739
1740 /*
1741 * compute the URI
1742 */
1743 base = xmlNodeGetBase(ctxt->doc, cur);
1744 if (base == NULL) {
1745 URI = xmlBuildURI(href, ctxt->doc->URL);
1746 } else {
1747 URI = xmlBuildURI(href, base);
1748 }
1749 if (URI == NULL) {
1750 xmlChar *escbase;
1751 xmlChar *eschref;
1752 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001753 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001754 */
1755 escbase = xmlURIEscape(base);
1756 eschref = xmlURIEscape(href);
1757 URI = xmlBuildURI(eschref, escbase);
1758 if (escbase != NULL)
1759 xmlFree(escbase);
1760 if (eschref != NULL)
1761 xmlFree(eschref);
1762 }
1763 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001764 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1765 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001766 if (parse != NULL)
1767 xmlFree(parse);
1768 if (href != NULL)
1769 xmlFree(href);
1770 if (base != NULL)
1771 xmlFree(base);
1772 return(-1);
1773 }
1774#ifdef DEBUG_XINCLUDE
1775 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1776 xml ? "xml": "text");
1777 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1778#endif
1779
1780 /*
1781 * Cleanup
1782 */
1783 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001784 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001785 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1786 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001787 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1788 }
1789 if (ret < 0) {
1790 xmlNodePtr children;
1791
1792 /*
1793 * Time to try a fallback if availble
1794 */
1795#ifdef DEBUG_XINCLUDE
1796 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1797#endif
1798 children = cur->children;
1799 while (children != NULL) {
1800 if ((children->type == XML_ELEMENT_NODE) &&
1801 (children->ns != NULL) &&
1802 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1803 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1804 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1805 if (ret == 0)
1806 break;
1807 }
1808 children = children->next;
1809 }
1810 }
1811 if (ret < 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001812 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1813 XML_XINCLUDE_NO_FALLBACK,
1814 "could not load %s, and no fallback was found\n",
1815 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001816 }
1817
1818 /*
1819 * Cleanup
1820 */
1821 if (URI != NULL)
1822 xmlFree(URI);
1823 if (parse != NULL)
1824 xmlFree(parse);
1825 if (href != NULL)
1826 xmlFree(href);
1827 if (base != NULL)
1828 xmlFree(base);
1829 return(0);
1830}
1831
1832/**
1833 * xmlXIncludeIncludeNode:
1834 * @ctxt: an XInclude context
1835 * @nr: the node number
1836 *
1837 * Inplement the infoset replacement for the given node
1838 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001839 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001840 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001841static int
Owen Taylor3473f882001-02-23 17:55:21 +00001842xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001843 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001844
1845 if (ctxt == NULL)
1846 return(-1);
1847 if ((nr < 0) || (nr >= ctxt->incNr))
1848 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001849 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001850 if (cur == NULL)
1851 return(-1);
1852
1853 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001854 * If we stored an XPointer a late computation may be needed
1855 */
1856 if ((ctxt->incTab[nr]->inc == NULL) &&
1857 (ctxt->incTab[nr]->xptr != NULL)) {
1858 ctxt->incTab[nr]->inc =
1859 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1860 ctxt->incTab[nr]->xptr);
1861 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1862 ctxt->incTab[nr]->xptr = NULL;
1863 }
1864 list = ctxt->incTab[nr]->inc;
1865 ctxt->incTab[nr]->inc = NULL;
1866
1867 /*
1868 * Check against the risk of generating a multi-rooted document
1869 */
1870 if ((cur->parent != NULL) &&
1871 (cur->parent->type != XML_ELEMENT_NODE)) {
1872 int nb_elem = 0;
1873
1874 tmp = list;
1875 while (tmp != NULL) {
1876 if (tmp->type == XML_ELEMENT_NODE)
1877 nb_elem++;
1878 tmp = tmp->next;
1879 }
1880 if (nb_elem > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001881 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1882 XML_XINCLUDE_MULTIPLE_ROOT,
1883 "XInclude error: would result in multiple root nodes\n",
1884 NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001885 return(-1);
1886 }
1887 }
1888
1889 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001890 * Change the current node as an XInclude start one, and add an
1891 * entity end one
1892 */
1893 cur->type = XML_XINCLUDE_START;
1894 end = xmlNewNode(cur->ns, cur->name);
1895 if (end == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001896 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED,
1897 "failed to build node\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001898 return(-1);
1899 }
1900 end->type = XML_XINCLUDE_END;
1901 xmlAddNextSibling(cur, end);
1902
1903 /*
1904 * Add the list of nodes
1905 */
Owen Taylor3473f882001-02-23 17:55:21 +00001906 while (list != NULL) {
1907 cur = list;
1908 list = list->next;
1909
1910 xmlAddPrevSibling(end, cur);
1911 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001912
1913
Owen Taylor3473f882001-02-23 17:55:21 +00001914 return(0);
1915}
1916
1917/**
1918 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001919 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001920 * @node: an XInclude node
1921 *
1922 * test if the node is an XInclude node
1923 *
1924 * Returns 1 true, 0 otherwise
1925 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001926static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001927xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001928 if (node == NULL)
1929 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00001930 if (node->type != XML_ELEMENT_NODE)
1931 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001932 if (node->ns == NULL)
1933 return(0);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001934 if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
1935 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
1936 xmlNodePtr child = node->children;
1937 int nb_fallback = 0;
1938
1939 while (child != NULL) {
1940 if ((child->type == XML_ELEMENT_NODE) &&
1941 (child->ns != NULL) &&
1942 (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
1943 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001944 xmlXIncludeErr(ctxt, node,
1945 XML_XINCLUDE_INCLUDE_IN_INCLUDE,
1946 "%s has an 'include' child\n",
1947 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001948 return(0);
1949 }
1950 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
1951 nb_fallback++;
1952 }
1953 }
1954 child = child->next;
1955 }
1956 if (nb_fallback > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001957 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
1958 "%s has multiple fallback children\n",
1959 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001960 return(0);
1961 }
1962 return(1);
1963 }
1964 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
1965 if ((node->parent == NULL) ||
1966 (node->parent->type != XML_ELEMENT_NODE) ||
1967 (node->parent->ns == NULL) ||
1968 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
1969 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001970 xmlXIncludeErr(ctxt, node,
1971 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
1972 "%s is not the child of an 'include'\n",
1973 XINCLUDE_FALLBACK);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001974 }
1975 }
1976 }
Owen Taylor3473f882001-02-23 17:55:21 +00001977 return(0);
1978}
1979
1980/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001981 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001982 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001983 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001984 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00001985 *
1986 * Implement the XInclude substitution on the XML document @doc
1987 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001988 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001989 * or the number of substitutions done.
1990 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001991static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001992xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00001993 xmlNodePtr cur;
1994 int ret = 0;
1995 int i;
1996
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001997 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001998 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001999 if (ctxt == NULL)
2000 return(-1);
2001
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002002 if (doc->URL != NULL) {
2003 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2004 if (ret < 0)
2005 return(-1);
2006 }
2007
Owen Taylor3473f882001-02-23 17:55:21 +00002008 /*
2009 * First phase: lookup the elements in the document
2010 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002011 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002012 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002013 xmlXIncludePreProcessNode(ctxt, cur);
2014 while (cur != NULL) {
2015 /* TODO: need to work on entities -> stack */
2016 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002017 (cur->children->type != XML_ENTITY_DECL) &&
2018 (cur->children->type != XML_XINCLUDE_START) &&
2019 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002020 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002021 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002022 xmlXIncludePreProcessNode(ctxt, cur);
2023 } else if (cur->next != NULL) {
2024 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002025 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002026 xmlXIncludePreProcessNode(ctxt, cur);
2027 } else {
2028 do {
2029 cur = cur->parent;
2030 if (cur == NULL) break; /* do */
2031 if (cur->next != NULL) {
2032 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002033 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002034 xmlXIncludePreProcessNode(ctxt, cur);
2035 break; /* do */
2036 }
2037 } while (cur != NULL);
2038 }
2039 }
2040
2041 /*
2042 * Second Phase : collect the infosets fragments
2043 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002044 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002045 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002046 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002047 }
2048
2049 /*
2050 * Third phase: extend the original document infoset.
2051 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002052 if (ctxt->nbErrors == 0) {
2053 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2054 xmlXIncludeIncludeNode(ctxt, i);
2055 }
Owen Taylor3473f882001-02-23 17:55:21 +00002056 }
2057
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002058 if (doc->URL != NULL)
2059 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002060 return(ret);
2061}
2062
2063/**
2064 * xmlXIncludeProcess:
2065 * @doc: an XML document
2066 *
2067 * Implement the XInclude substitution on the XML document @doc
2068 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002069 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002070 * or the number of substitutions done.
2071 */
2072int
2073xmlXIncludeProcess(xmlDocPtr doc) {
2074 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002075 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002076 int ret = 0;
2077
2078 if (doc == NULL)
2079 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002080 tree = xmlDocGetRootElement(doc);
2081 if (tree == NULL)
2082 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002083 ctxt = xmlXIncludeNewContext(doc);
2084 if (ctxt == NULL)
2085 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002086 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2087 if ((ret >= 0) && (ctxt->nbErrors > 0))
2088 ret = -1;
2089
2090 xmlXIncludeFreeContext(ctxt);
2091 return(ret);
2092}
2093
2094/**
2095 * xmlXIncludeProcessTree:
2096 * @tree: a node in an XML document
2097 *
2098 * Implement the XInclude substitution for the given subtree
2099 *
2100 * Returns 0 if no substitution were done, -1 if some processing failed
2101 * or the number of substitutions done.
2102 */
2103int
2104xmlXIncludeProcessTree(xmlNodePtr tree) {
2105 xmlXIncludeCtxtPtr ctxt;
2106 int ret = 0;
2107
2108 if ((tree == NULL) || (tree->doc == NULL))
2109 return(-1);
2110 ctxt = xmlXIncludeNewContext(tree->doc);
2111 if (ctxt == NULL)
2112 return(-1);
2113 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00002114 if ((ret >= 0) && (ctxt->nbErrors > 0))
2115 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002116
Owen Taylor3473f882001-02-23 17:55:21 +00002117 xmlXIncludeFreeContext(ctxt);
2118 return(ret);
2119}
2120
2121#else /* !LIBXML_XINCLUDE_ENABLED */
2122#endif