blob: 6358f1e144fe155d8034cf23e9ecccb34b307a49 [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:
1397 case XPATH_RANGE:
1398 case XPATH_LOCATIONSET:
1399 break;
1400 }
1401 set = xptr->nodesetval;
1402 if (set != NULL) {
1403 for (i = 0;i < set->nodeNr;i++) {
1404 if (set->nodeTab[i] == NULL)
1405 continue;
1406 switch (set->nodeTab[i]->type) {
1407 case XML_TEXT_NODE:
1408 case XML_CDATA_SECTION_NODE:
1409 case XML_ELEMENT_NODE:
1410 case XML_ENTITY_REF_NODE:
1411 case XML_ENTITY_NODE:
1412 case XML_PI_NODE:
1413 case XML_COMMENT_NODE:
1414 case XML_DOCUMENT_NODE:
1415 case XML_HTML_DOCUMENT_NODE:
1416#ifdef LIBXML_DOCB_ENABLED
1417 case XML_DOCB_DOCUMENT_NODE:
1418#endif
1419 continue;
1420 case XML_ATTRIBUTE_NODE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001421 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1422 XML_XINCLUDE_XPTR_RESULT,
1423 "XPointer selects an attribute: #%s\n",
1424 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001425 set->nodeTab[i] = NULL;
1426 continue;
1427 case XML_NAMESPACE_DECL:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001428 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1429 XML_XINCLUDE_XPTR_RESULT,
1430 "XPointer selects a namespace: #%s\n",
1431 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001432 set->nodeTab[i] = NULL;
1433 continue;
1434 case XML_DOCUMENT_TYPE_NODE:
1435 case XML_DOCUMENT_FRAG_NODE:
1436 case XML_NOTATION_NODE:
1437 case XML_DTD_NODE:
1438 case XML_ELEMENT_DECL:
1439 case XML_ATTRIBUTE_DECL:
1440 case XML_ENTITY_DECL:
1441 case XML_XINCLUDE_START:
1442 case XML_XINCLUDE_END:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001443 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1444 XML_XINCLUDE_XPTR_RESULT,
1445 "XPointer selects unexpected nodes: #%s\n",
1446 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001447 set->nodeTab[i] = NULL;
1448 set->nodeTab[i] = NULL;
1449 continue; /* for */
1450 }
1451 }
1452 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001453 if (doc == NULL) {
1454 ctxt->incTab[nr]->xptr = xptr;
1455 ctxt->incTab[nr]->inc = NULL;
1456 } else {
1457 ctxt->incTab[nr]->inc =
1458 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1459 xmlXPathFreeObject(xptr);
1460 }
Owen Taylor3473f882001-02-23 17:55:21 +00001461 xmlXPathFreeContext(xptrctxt);
1462 xmlFree(fragment);
1463 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001464#endif
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001465
1466 /*
1467 * Do the xml:base fixup if needed
1468 */
1469 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1470 xmlNodePtr node;
1471
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001472 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001473 while (node != NULL) {
1474 if (node->type == XML_ELEMENT_NODE)
1475 xmlNodeSetBase(node, URL);
1476 node = node->next;
1477 }
1478 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001479 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1480 (ctxt->incTab[nr]->count <= 1)) {
1481#ifdef DEBUG_XINCLUDE
1482 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1483#endif
1484 xmlFreeDoc(ctxt->incTab[nr]->doc);
1485 ctxt->incTab[nr]->doc = NULL;
1486 }
Owen Taylor3473f882001-02-23 17:55:21 +00001487 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001488 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001489}
1490
1491/**
1492 * xmlXIncludeLoadTxt:
1493 * @ctxt: the XInclude context
1494 * @url: the associated URL
1495 * @nr: the xinclude node number
1496 *
1497 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001498 *
1499 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001500 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001501static int
Owen Taylor3473f882001-02-23 17:55:21 +00001502xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1503 xmlParserInputBufferPtr buf;
1504 xmlNodePtr node;
1505 xmlURIPtr uri;
1506 xmlChar *URL;
1507 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001508 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001509 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001510
Owen Taylor3473f882001-02-23 17:55:21 +00001511 /*
1512 * Check the URL and remove any fragment identifier
1513 */
1514 uri = xmlParseURI((const char *)url);
1515 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001516 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1517 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001518 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001519 }
1520 if (uri->fragment != NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001521 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1522 "fragment identifier forbidden for text: %s\n",
1523 (const xmlChar *) uri->fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001524 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001525 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001526 }
1527 URL = xmlSaveUri(uri);
1528 xmlFreeURI(uri);
1529 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001530 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1531 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001532 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001533 }
1534
1535 /*
1536 * Handling of references to the local document are done
1537 * directly through ctxt->doc.
1538 */
1539 if (URL[0] == 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001540 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1541 XML_XINCLUDE_TEXT_DOCUMENT,
1542 "text serialization of document not available\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001543 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001544 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001545 }
1546
1547 /*
1548 * Prevent reloading twice the document.
1549 */
1550 for (i = 0; i < ctxt->txtNr; i++) {
1551 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1552 node = xmlCopyNode(ctxt->txtTab[i], 1);
1553 goto loaded;
1554 }
1555 }
1556 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001557 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001558 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001559 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1560 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1561 }
1562 if (encoding != NULL) {
1563 /*
1564 * TODO: we should not have to remap to the xmlCharEncoding
1565 * predefined set, a better interface than
1566 * xmlParserInputBufferCreateFilename should allow any
1567 * encoding supported by iconv
1568 */
1569 enc = xmlParseCharEncoding((const char *) encoding);
1570 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001571 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1572 XML_XINCLUDE_UNKNOWN_ENCODING,
1573 "encoding %s not supported\n", encoding);
Daniel Veillardd076a202002-11-20 13:28:31 +00001574 xmlFree(encoding);
1575 xmlFree(URL);
1576 return(-1);
1577 }
1578 xmlFree(encoding);
1579 }
1580
1581 /*
1582 * Load it.
1583 */
1584 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001585 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001586 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001587 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001588 }
1589 node = xmlNewText(NULL);
1590
1591 /*
1592 * Scan all chars from the resource and add the to the node
1593 */
1594 while (xmlParserInputBufferRead(buf, 128) > 0) {
1595 int len;
1596 const xmlChar *content;
1597
1598 content = xmlBufferContent(buf->buffer);
1599 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001600 for (i = 0;i < len;) {
1601 int cur;
1602 int l;
1603
1604 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1605 if (!IS_CHAR(cur)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001606 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1607 XML_XINCLUDE_INVALID_CHAR,
1608 "%s contains invalid char\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001609 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001610 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001611 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001612 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001613 }
1614 xmlBufferShrink(buf->buffer, len);
1615 }
1616 xmlFreeParserInputBuffer(buf);
1617 xmlXIncludeAddTxt(ctxt, node, URL);
1618
1619loaded:
1620 /*
1621 * Add the element as the replacement copy.
1622 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001623 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001624 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001625 return(0);
1626}
1627
1628/**
1629 * xmlXIncludeLoadFallback:
1630 * @ctxt: the XInclude context
1631 * @fallback: the fallback node
1632 * @nr: the xinclude node number
1633 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001634 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001635 * in the XInclude context
1636 *
1637 * Returns 0 in case of success, -1 in case of failure
1638 */
1639static int
1640xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1641 if ((fallback == NULL) || (ctxt == NULL))
1642 return(-1);
1643
Daniel Veillard06503452002-12-13 10:42:08 +00001644 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001645 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001646}
1647
1648/************************************************************************
1649 * *
1650 * XInclude Processing *
1651 * *
1652 ************************************************************************/
1653
1654/**
1655 * xmlXIncludePreProcessNode:
1656 * @ctxt: an XInclude context
1657 * @node: an XInclude node
1658 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001659 * Implement the XInclude preprocessing, currently just adding the element
1660 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001661 *
1662 * Returns the result list or NULL in case of error
1663 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001664static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001665xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1666 xmlXIncludeAddNode(ctxt, node);
1667 return(0);
1668}
1669
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001670/**
Owen Taylor3473f882001-02-23 17:55:21 +00001671 * xmlXIncludeLoadNode:
1672 * @ctxt: an XInclude context
1673 * @nr: the node number
1674 *
1675 * Find and load the infoset replacement for the given node.
1676 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001677 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001678 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001679static int
Owen Taylor3473f882001-02-23 17:55:21 +00001680xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1681 xmlNodePtr cur;
1682 xmlChar *href;
1683 xmlChar *parse;
1684 xmlChar *base;
1685 xmlChar *URI;
1686 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001687 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001688
1689 if (ctxt == NULL)
1690 return(-1);
1691 if ((nr < 0) || (nr >= ctxt->incNr))
1692 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001693 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001694 if (cur == NULL)
1695 return(-1);
1696
Owen Taylor3473f882001-02-23 17:55:21 +00001697 /*
1698 * read the attributes
1699 */
1700 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1701 if (href == NULL) {
1702 href = xmlGetProp(cur, XINCLUDE_HREF);
1703 if (href == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001704 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1705 XML_XINCLUDE_NO_HREF, "no href\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001706 return(-1);
1707 }
1708 }
1709 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1710 if (parse == NULL) {
1711 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1712 }
1713 if (parse != NULL) {
1714 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1715 xml = 1;
1716 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1717 xml = 0;
1718 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001719 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1720 XML_XINCLUDE_PARSE_VALUE,
1721 "invalid value %s for 'parse'\n", parse);
Owen Taylor3473f882001-02-23 17:55:21 +00001722 if (href != NULL)
1723 xmlFree(href);
1724 if (parse != NULL)
1725 xmlFree(parse);
1726 return(-1);
1727 }
1728 }
1729
1730 /*
1731 * compute the URI
1732 */
1733 base = xmlNodeGetBase(ctxt->doc, cur);
1734 if (base == NULL) {
1735 URI = xmlBuildURI(href, ctxt->doc->URL);
1736 } else {
1737 URI = xmlBuildURI(href, base);
1738 }
1739 if (URI == NULL) {
1740 xmlChar *escbase;
1741 xmlChar *eschref;
1742 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001743 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001744 */
1745 escbase = xmlURIEscape(base);
1746 eschref = xmlURIEscape(href);
1747 URI = xmlBuildURI(eschref, escbase);
1748 if (escbase != NULL)
1749 xmlFree(escbase);
1750 if (eschref != NULL)
1751 xmlFree(eschref);
1752 }
1753 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001754 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1755 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001756 if (parse != NULL)
1757 xmlFree(parse);
1758 if (href != NULL)
1759 xmlFree(href);
1760 if (base != NULL)
1761 xmlFree(base);
1762 return(-1);
1763 }
1764#ifdef DEBUG_XINCLUDE
1765 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1766 xml ? "xml": "text");
1767 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1768#endif
1769
1770 /*
1771 * Cleanup
1772 */
1773 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001774 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001775 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1776 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001777 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1778 }
1779 if (ret < 0) {
1780 xmlNodePtr children;
1781
1782 /*
1783 * Time to try a fallback if availble
1784 */
1785#ifdef DEBUG_XINCLUDE
1786 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1787#endif
1788 children = cur->children;
1789 while (children != NULL) {
1790 if ((children->type == XML_ELEMENT_NODE) &&
1791 (children->ns != NULL) &&
1792 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1793 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1794 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1795 if (ret == 0)
1796 break;
1797 }
1798 children = children->next;
1799 }
1800 }
1801 if (ret < 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001802 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1803 XML_XINCLUDE_NO_FALLBACK,
1804 "could not load %s, and no fallback was found\n",
1805 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001806 }
1807
1808 /*
1809 * Cleanup
1810 */
1811 if (URI != NULL)
1812 xmlFree(URI);
1813 if (parse != NULL)
1814 xmlFree(parse);
1815 if (href != NULL)
1816 xmlFree(href);
1817 if (base != NULL)
1818 xmlFree(base);
1819 return(0);
1820}
1821
1822/**
1823 * xmlXIncludeIncludeNode:
1824 * @ctxt: an XInclude context
1825 * @nr: the node number
1826 *
1827 * Inplement the infoset replacement for the given node
1828 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001829 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001830 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001831static int
Owen Taylor3473f882001-02-23 17:55:21 +00001832xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001833 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001834
1835 if (ctxt == NULL)
1836 return(-1);
1837 if ((nr < 0) || (nr >= ctxt->incNr))
1838 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001839 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001840 if (cur == NULL)
1841 return(-1);
1842
1843 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001844 * If we stored an XPointer a late computation may be needed
1845 */
1846 if ((ctxt->incTab[nr]->inc == NULL) &&
1847 (ctxt->incTab[nr]->xptr != NULL)) {
1848 ctxt->incTab[nr]->inc =
1849 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1850 ctxt->incTab[nr]->xptr);
1851 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1852 ctxt->incTab[nr]->xptr = NULL;
1853 }
1854 list = ctxt->incTab[nr]->inc;
1855 ctxt->incTab[nr]->inc = NULL;
1856
1857 /*
1858 * Check against the risk of generating a multi-rooted document
1859 */
1860 if ((cur->parent != NULL) &&
1861 (cur->parent->type != XML_ELEMENT_NODE)) {
1862 int nb_elem = 0;
1863
1864 tmp = list;
1865 while (tmp != NULL) {
1866 if (tmp->type == XML_ELEMENT_NODE)
1867 nb_elem++;
1868 tmp = tmp->next;
1869 }
1870 if (nb_elem > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001871 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1872 XML_XINCLUDE_MULTIPLE_ROOT,
1873 "XInclude error: would result in multiple root nodes\n",
1874 NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001875 return(-1);
1876 }
1877 }
1878
1879 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001880 * Change the current node as an XInclude start one, and add an
1881 * entity end one
1882 */
1883 cur->type = XML_XINCLUDE_START;
1884 end = xmlNewNode(cur->ns, cur->name);
1885 if (end == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001886 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED,
1887 "failed to build node\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001888 return(-1);
1889 }
1890 end->type = XML_XINCLUDE_END;
1891 xmlAddNextSibling(cur, end);
1892
1893 /*
1894 * Add the list of nodes
1895 */
Owen Taylor3473f882001-02-23 17:55:21 +00001896 while (list != NULL) {
1897 cur = list;
1898 list = list->next;
1899
1900 xmlAddPrevSibling(end, cur);
1901 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001902
1903
Owen Taylor3473f882001-02-23 17:55:21 +00001904 return(0);
1905}
1906
1907/**
1908 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001909 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001910 * @node: an XInclude node
1911 *
1912 * test if the node is an XInclude node
1913 *
1914 * Returns 1 true, 0 otherwise
1915 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001916static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001917xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001918 if (node == NULL)
1919 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00001920 if (node->type != XML_ELEMENT_NODE)
1921 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001922 if (node->ns == NULL)
1923 return(0);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001924 if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
1925 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
1926 xmlNodePtr child = node->children;
1927 int nb_fallback = 0;
1928
1929 while (child != NULL) {
1930 if ((child->type == XML_ELEMENT_NODE) &&
1931 (child->ns != NULL) &&
1932 (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
1933 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001934 xmlXIncludeErr(ctxt, node,
1935 XML_XINCLUDE_INCLUDE_IN_INCLUDE,
1936 "%s has an 'include' child\n",
1937 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001938 return(0);
1939 }
1940 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
1941 nb_fallback++;
1942 }
1943 }
1944 child = child->next;
1945 }
1946 if (nb_fallback > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001947 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
1948 "%s has multiple fallback children\n",
1949 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001950 return(0);
1951 }
1952 return(1);
1953 }
1954 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
1955 if ((node->parent == NULL) ||
1956 (node->parent->type != XML_ELEMENT_NODE) ||
1957 (node->parent->ns == NULL) ||
1958 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
1959 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001960 xmlXIncludeErr(ctxt, node,
1961 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
1962 "%s is not the child of an 'include'\n",
1963 XINCLUDE_FALLBACK);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001964 }
1965 }
1966 }
Owen Taylor3473f882001-02-23 17:55:21 +00001967 return(0);
1968}
1969
1970/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001971 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001972 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001973 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001974 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00001975 *
1976 * Implement the XInclude substitution on the XML document @doc
1977 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001978 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001979 * or the number of substitutions done.
1980 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001981static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001982xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00001983 xmlNodePtr cur;
1984 int ret = 0;
1985 int i;
1986
Daniel Veillard8edf1c52003-07-22 20:52:14 +00001987 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001988 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001989 if (ctxt == NULL)
1990 return(-1);
1991
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001992 if (doc->URL != NULL) {
1993 ret = xmlXIncludeURLPush(ctxt, doc->URL);
1994 if (ret < 0)
1995 return(-1);
1996 }
1997
Owen Taylor3473f882001-02-23 17:55:21 +00001998 /*
1999 * First phase: lookup the elements in the document
2000 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002001 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002002 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002003 xmlXIncludePreProcessNode(ctxt, cur);
2004 while (cur != NULL) {
2005 /* TODO: need to work on entities -> stack */
2006 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002007 (cur->children->type != XML_ENTITY_DECL) &&
2008 (cur->children->type != XML_XINCLUDE_START) &&
2009 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002010 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002011 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002012 xmlXIncludePreProcessNode(ctxt, cur);
2013 } else if (cur->next != NULL) {
2014 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002015 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002016 xmlXIncludePreProcessNode(ctxt, cur);
2017 } else {
2018 do {
2019 cur = cur->parent;
2020 if (cur == NULL) break; /* do */
2021 if (cur->next != NULL) {
2022 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002023 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002024 xmlXIncludePreProcessNode(ctxt, cur);
2025 break; /* do */
2026 }
2027 } while (cur != NULL);
2028 }
2029 }
2030
2031 /*
2032 * Second Phase : collect the infosets fragments
2033 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002034 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002035 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002036 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002037 }
2038
2039 /*
2040 * Third phase: extend the original document infoset.
2041 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002042 if (ctxt->nbErrors == 0) {
2043 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2044 xmlXIncludeIncludeNode(ctxt, i);
2045 }
Owen Taylor3473f882001-02-23 17:55:21 +00002046 }
2047
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002048 if (doc->URL != NULL)
2049 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002050 return(ret);
2051}
2052
2053/**
2054 * xmlXIncludeProcess:
2055 * @doc: an XML document
2056 *
2057 * Implement the XInclude substitution on the XML document @doc
2058 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002059 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002060 * or the number of substitutions done.
2061 */
2062int
2063xmlXIncludeProcess(xmlDocPtr doc) {
2064 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002065 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002066 int ret = 0;
2067
2068 if (doc == NULL)
2069 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002070 tree = xmlDocGetRootElement(doc);
2071 if (tree == NULL)
2072 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002073 ctxt = xmlXIncludeNewContext(doc);
2074 if (ctxt == NULL)
2075 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002076 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2077 if ((ret >= 0) && (ctxt->nbErrors > 0))
2078 ret = -1;
2079
2080 xmlXIncludeFreeContext(ctxt);
2081 return(ret);
2082}
2083
2084/**
2085 * xmlXIncludeProcessTree:
2086 * @tree: a node in an XML document
2087 *
2088 * Implement the XInclude substitution for the given subtree
2089 *
2090 * Returns 0 if no substitution were done, -1 if some processing failed
2091 * or the number of substitutions done.
2092 */
2093int
2094xmlXIncludeProcessTree(xmlNodePtr tree) {
2095 xmlXIncludeCtxtPtr ctxt;
2096 int ret = 0;
2097
2098 if ((tree == NULL) || (tree->doc == NULL))
2099 return(-1);
2100 ctxt = xmlXIncludeNewContext(tree->doc);
2101 if (ctxt == NULL)
2102 return(-1);
2103 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00002104 if ((ret >= 0) && (ctxt->nbErrors > 0))
2105 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002106
Owen Taylor3473f882001-02-23 17:55:21 +00002107 xmlXIncludeFreeContext(ctxt);
2108 return(ret);
2109}
2110
Daniel Veillard7899c5c2003-11-03 12:31:38 +00002111/**
2112 * xmlXIncludeProcessNode:
2113 * @ctxt: an existing XInclude context
2114 * @node: a node in an XML document
2115 *
2116 * Implement the XInclude substitution for the given subtree reusing
2117 * the informations and data coming from the given context.
2118 *
2119 * Returns 0 if no substitution were done, -1 if some processing failed
2120 * or the number of substitutions done.
2121 */
2122int
2123xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2124 int ret = 0;
2125
2126 if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
2127 return(-1);
2128 ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
2129 if ((ret >= 0) && (ctxt->nbErrors > 0))
2130 ret = -1;
2131 return(ret);
2132}
2133
Owen Taylor3473f882001-02-23 17:55:21 +00002134#else /* !LIBXML_XINCLUDE_ENABLED */
2135#endif