blob: d7dc1304e573bc50b1d7dec9cd35135bc554137c [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 */
Daniel Veillardb5fa0202003-12-08 17:41:29 +000081 int legacy; /* using XINCLUDE_OLD_NS */
Owen Taylor3473f882001-02-23 17:55:21 +000082};
83
Daniel Veillardd16df9f2001-05-23 13:44:21 +000084static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +000085xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
Owen Taylor3473f882001-02-23 17:55:21 +000086
Daniel Veillard98485322003-08-14 15:44:40 +000087
Daniel Veillardcd6ff282003-10-08 22:38:13 +000088/************************************************************************
89 * *
Daniel Veillard69d2c172003-10-09 11:46:07 +000090 * XInclude error handler *
Daniel Veillardcd6ff282003-10-08 22:38:13 +000091 * *
92 ************************************************************************/
93
Daniel Veillard98485322003-08-14 15:44:40 +000094/**
Daniel Veillardcd6ff282003-10-08 22:38:13 +000095 * xmlXIncludeErrMemory:
96 * @extra: extra informations
Daniel Veillard98485322003-08-14 15:44:40 +000097 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +000098 * Handle an out of memory condition
Daniel Veillard98485322003-08-14 15:44:40 +000099 */
100static void
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000101xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
102 const char *extra)
Daniel Veillard98485322003-08-14 15:44:40 +0000103{
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000104 if (ctxt != NULL)
105 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000106 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000107 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
108 extra, NULL, NULL, 0, 0,
109 "Memory allocation failed : %s\n", extra);
110}
Daniel Veillard98485322003-08-14 15:44:40 +0000111
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000112/**
113 * xmlXIncludeErr:
114 * @ctxt: the XInclude context
115 * @node: the context node
116 * @msg: the error message
117 * @extra: extra informations
118 *
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000119 * Handle an XInclude error
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000120 */
121static void
122xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
123 const char *msg, const xmlChar *extra)
124{
125 if (ctxt != NULL)
126 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000127 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000128 error, XML_ERR_ERROR, NULL, 0,
129 (const char *) extra, NULL, NULL, 0, 0,
130 msg, (const char *) extra);
Daniel Veillard98485322003-08-14 15:44:40 +0000131}
132
Owen Taylor3473f882001-02-23 17:55:21 +0000133/**
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000134 * xmlXIncludeWarn:
135 * @ctxt: the XInclude context
136 * @node: the context node
137 * @msg: the error message
138 * @extra: extra informations
139 *
140 * Emit an XInclude warning.
141 */
142static void
143xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
144 const char *msg, const xmlChar *extra)
145{
146 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
147 error, XML_ERR_WARNING, NULL, 0,
148 (const char *) extra, NULL, NULL, 0, 0,
149 msg, (const char *) extra);
150}
151
152/**
153 * xmlXIncludeGetProp:
154 * @ctxt: the XInclude context
155 * @cur: the node
156 * @name: the attribute name
157 *
158 * Get an XInclude attribute
159 *
160 * Returns the value (to be freed) or NULL if not found
161 */
162static xmlChar *
163xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
164 const xmlChar *name) {
165 xmlChar *ret;
166
167 ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
168 if (ret != NULL)
169 return(ret);
170 if (ctxt->legacy != 0) {
171 ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
172 if (ret != NULL)
173 return(ret);
174 }
175 ret = xmlGetProp(cur, name);
176 return(ret);
177}
178/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000179 * xmlXIncludeFreeRef:
180 * @ref: the XInclude reference
181 *
182 * Free an XInclude reference
183 */
184static void
185xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
186 if (ref == NULL)
187 return;
188#ifdef DEBUG_XINCLUDE
189 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
190#endif
191 if (ref->doc != NULL) {
192#ifdef DEBUG_XINCLUDE
193 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
194#endif
195 xmlFreeDoc(ref->doc);
196 }
197 if (ref->URI != NULL)
198 xmlFree(ref->URI);
199 if (ref->fragment != NULL)
200 xmlFree(ref->fragment);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000201 if (ref->xptr != NULL)
202 xmlXPathFreeObject(ref->xptr);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000203 xmlFree(ref);
204}
205
206/**
207 * xmlXIncludeNewRef:
208 * @ctxt: the XInclude context
209 * @URI: the resource URI
210 *
211 * Creates a new reference within an XInclude context
212 *
213 * Returns the new set
214 */
215static xmlXIncludeRefPtr
216xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
217 xmlNodePtr ref) {
218 xmlXIncludeRefPtr ret;
219
220#ifdef DEBUG_XINCLUDE
221 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
222#endif
223 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000224 if (ret == NULL) {
225 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000226 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000227 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000228 memset(ret, 0, sizeof(xmlXIncludeRef));
229 if (URI == NULL)
230 ret->URI = NULL;
231 else
232 ret->URI = xmlStrdup(URI);
233 ret->fragment = NULL;
234 ret->ref = ref;
235 ret->doc = 0;
236 ret->count = 0;
237 ret->xml = 0;
238 ret->inc = NULL;
239 if (ctxt->incMax == 0) {
240 ctxt->incMax = 4;
241 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
242 sizeof(ctxt->incTab[0]));
243 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000244 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000245 xmlXIncludeFreeRef(ret);
246 return(NULL);
247 }
248 }
249 if (ctxt->incNr >= ctxt->incMax) {
250 ctxt->incMax *= 2;
251 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
252 ctxt->incMax * sizeof(ctxt->incTab[0]));
253 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000254 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000255 xmlXIncludeFreeRef(ret);
256 return(NULL);
257 }
258 }
259 ctxt->incTab[ctxt->incNr++] = ret;
260 return(ret);
261}
262
263/**
Owen Taylor3473f882001-02-23 17:55:21 +0000264 * xmlXIncludeNewContext:
265 * @doc: an XML Document
266 *
267 * Creates a new XInclude context
268 *
269 * Returns the new set
270 */
Daniel Veillard7899c5c2003-11-03 12:31:38 +0000271xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000272xmlXIncludeNewContext(xmlDocPtr doc) {
273 xmlXIncludeCtxtPtr ret;
274
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000275#ifdef DEBUG_XINCLUDE
276 xmlGenericError(xmlGenericErrorContext, "New context\n");
277#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000278 if (doc == NULL)
279 return(NULL);
280 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000281 if (ret == NULL) {
282 xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
283 "creating XInclude context");
Owen Taylor3473f882001-02-23 17:55:21 +0000284 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000285 }
Owen Taylor3473f882001-02-23 17:55:21 +0000286 memset(ret, 0, sizeof(xmlXIncludeCtxt));
287 ret->doc = doc;
288 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000289 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000290 ret->incMax = 0;
291 ret->incTab = NULL;
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000292 ret->nbErrors = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000293 return(ret);
294}
295
296/**
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000297 * xmlXIncludeURLPush:
298 * @ctxt: the parser context
299 * @value: the url
300 *
301 * Pushes a new url on top of the url stack
302 *
303 * Returns -1 in case of error, the index in the stack otherwise
304 */
305static int
306xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
307 const xmlChar *value)
308{
309 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000310 xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
311 "detected a recursion in %s\n", value);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000312 return(-1);
313 }
314 if (ctxt->urlTab == NULL) {
315 ctxt->urlMax = 4;
316 ctxt->urlNr = 0;
317 ctxt->urlTab = (xmlChar * *) xmlMalloc(
318 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
319 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000320 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000321 return (-1);
322 }
323 }
324 if (ctxt->urlNr >= ctxt->urlMax) {
325 ctxt->urlMax *= 2;
326 ctxt->urlTab =
327 (xmlChar * *) xmlRealloc(ctxt->urlTab,
328 ctxt->urlMax *
329 sizeof(ctxt->urlTab[0]));
330 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000331 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000332 return (-1);
333 }
334 }
335 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
336 return (ctxt->urlNr++);
337}
338
339/**
340 * xmlXIncludeURLPop:
341 * @ctxt: the parser context
342 *
343 * Pops the top url from the url stack
344 */
345static void
346xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
347{
348 xmlChar * ret;
349
350 if (ctxt->urlNr <= 0)
351 return;
352 ctxt->urlNr--;
353 if (ctxt->urlNr > 0)
354 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
355 else
356 ctxt->url = NULL;
357 ret = ctxt->urlTab[ctxt->urlNr];
358 ctxt->urlTab[ctxt->urlNr] = 0;
359 if (ret != NULL)
360 xmlFree(ret);
361}
362
363/**
Owen Taylor3473f882001-02-23 17:55:21 +0000364 * xmlXIncludeFreeContext:
365 * @ctxt: the XInclude context
366 *
367 * Free an XInclude context
368 */
Daniel Veillard7899c5c2003-11-03 12:31:38 +0000369void
Owen Taylor3473f882001-02-23 17:55:21 +0000370xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
371 int i;
372
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000373#ifdef DEBUG_XINCLUDE
374 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
375#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000376 if (ctxt == NULL)
377 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000378 while (ctxt->urlNr > 0)
379 xmlXIncludeURLPop(ctxt);
380 if (ctxt->urlTab != NULL)
381 xmlFree(ctxt->urlTab);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000382 for (i = 0;i < ctxt->incNr;i++) {
383 if (ctxt->incTab[i] != NULL)
384 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000385 }
386 for (i = 0;i < ctxt->txtNr;i++) {
387 if (ctxt->txturlTab[i] != NULL)
388 xmlFree(ctxt->txturlTab[i]);
389 }
390 if (ctxt->incTab != NULL)
391 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000392 if (ctxt->txtTab != NULL)
393 xmlFree(ctxt->txtTab);
394 if (ctxt->txturlTab != NULL)
395 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000396 xmlFree(ctxt);
397}
398
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000399/**
Daniel Veillard98485322003-08-14 15:44:40 +0000400 * xmlXIncludeParseFile:
401 * @ctxt: the XInclude context
402 * @URL: the URL or file path
403 *
404 * parse an document for XInclude
405 */
406static xmlDocPtr
407xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt ATTRIBUTE_UNUSED, const char *URL) {
408 xmlDocPtr ret;
409 xmlParserCtxtPtr pctxt;
410 char *directory = NULL;
411
412 xmlInitParser();
413
414 pctxt = xmlCreateFileParserCtxt(URL);
415 if (pctxt == NULL) {
416 return(NULL);
417 }
418
419 if ((pctxt->directory == NULL) && (directory == NULL))
420 directory = xmlParserGetDirectory(URL);
421 if ((pctxt->directory == NULL) && (directory != NULL))
422 pctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
423
424 pctxt->loadsubset = XML_DETECT_IDS;
425
426 xmlParseDocument(pctxt);
427
428 if (pctxt->wellFormed)
429 ret = pctxt->myDoc;
430 else {
431 ret = NULL;
432 xmlFreeDoc(pctxt->myDoc);
433 pctxt->myDoc = NULL;
434 }
435 xmlFreeParserCtxt(pctxt);
436
437 return(ret);
438}
439
440/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000441 * xmlXIncludeAddNode:
442 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000443 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000444 *
445 * Add a new node to process to an XInclude context
446 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000447static int
448xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
449 xmlXIncludeRefPtr ref;
450 xmlURIPtr uri;
451 xmlChar *URL;
452 xmlChar *fragment = NULL;
453 xmlChar *href;
454 xmlChar *parse;
455 xmlChar *base;
456 xmlChar *URI;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000457 int xml = 1, i; /* default Issue 64 */
458 int local = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000459
460
461 if (ctxt == NULL)
462 return(-1);
463 if (cur == NULL)
464 return(-1);
465
466#ifdef DEBUG_XINCLUDE
467 xmlGenericError(xmlGenericErrorContext, "Add node\n");
468#endif
469 /*
470 * read the attributes
471 */
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000472 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000473 if (href == NULL) {
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000474 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
475 if (href == NULL)
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000476 return(-1);
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000477 local = 1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000478 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000479 if (href[0] == '#')
480 local = 1;
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000481 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000482 if (parse != NULL) {
483 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
484 xml = 1;
485 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
486 xml = 0;
487 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000488 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
489 "invalid value %s for 'parse'\n", parse);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000490 if (href != NULL)
491 xmlFree(href);
492 if (parse != NULL)
493 xmlFree(parse);
494 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000495 }
496 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000497
498 /*
499 * compute the URI
500 */
501 base = xmlNodeGetBase(ctxt->doc, cur);
502 if (base == NULL) {
503 URI = xmlBuildURI(href, ctxt->doc->URL);
504 } else {
505 URI = xmlBuildURI(href, base);
506 }
507 if (URI == NULL) {
508 xmlChar *escbase;
509 xmlChar *eschref;
510 /*
511 * Some escaping may be needed
512 */
513 escbase = xmlURIEscape(base);
514 eschref = xmlURIEscape(href);
515 URI = xmlBuildURI(eschref, escbase);
516 if (escbase != NULL)
517 xmlFree(escbase);
518 if (eschref != NULL)
519 xmlFree(eschref);
520 }
521 if (parse != NULL)
522 xmlFree(parse);
523 if (href != NULL)
524 xmlFree(href);
525 if (base != NULL)
526 xmlFree(base);
527 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000528 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
529 "failed build URL\n", NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000530 return(-1);
531 }
532
533 /*
534 * Check the URL and remove any fragment identifier
535 */
536 uri = xmlParseURI((const char *)URI);
537 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000538 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
539 "invalid value URI %s\n", URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000540 return(-1);
541 }
542 if (uri->fragment != NULL) {
543 fragment = (xmlChar *) uri->fragment;
544 uri->fragment = NULL;
545 }
546 URL = xmlSaveUri(uri);
547 xmlFreeURI(uri);
548 xmlFree(URI);
549 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000550 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
551 "invalid value URI %s\n", URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000552 if (fragment != NULL)
553 xmlFree(fragment);
554 return(-1);
555 }
556
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000557 /*
558 * Check the URL against the stack for recursions
559 */
560 if (!local) {
561 for (i = 0;i < ctxt->urlNr;i++) {
562 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000563 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
564 "detected a recursion in %s\n", URL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000565 return(-1);
566 }
567 }
568 }
569
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000570 ref = xmlXIncludeNewRef(ctxt, URL, cur);
571 if (ref == NULL) {
572 return(-1);
573 }
574 ref->fragment = fragment;
575 ref->doc = NULL;
576 ref->xml = xml;
577 ref->count = 1;
578 xmlFree(URL);
579 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000580}
581
582/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000583 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000584 * @ctxt: the XInclude context
585 * @doc: the new document
586 * @url: the associated URL
587 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000588 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000589 */
590static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000591xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000592 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000593 xmlXIncludeCtxtPtr newctxt;
594 int i;
595
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000596 /*
597 * Avoid recursion in already substitued resources
598 for (i = 0;i < ctxt->urlNr;i++) {
599 if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
600 return;
601 }
602 */
603
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000604#ifdef DEBUG_XINCLUDE
605 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
606#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000607 /*
608 * Handle recursion here.
609 */
610
611 newctxt = xmlXIncludeNewContext(doc);
612 if (newctxt != NULL) {
613 /*
614 * Copy the existing document set
615 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000616 newctxt->incMax = ctxt->incMax;
617 newctxt->incNr = ctxt->incNr;
618 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
619 sizeof(newctxt->incTab[0]));
620 if (newctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000621 xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000622 xmlFree(newctxt);
623 return;
624 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000625 /*
626 * copy the urlTab
627 */
628 newctxt->urlMax = ctxt->urlMax;
629 newctxt->urlNr = ctxt->urlNr;
630 newctxt->urlTab = ctxt->urlTab;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000631
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000632 /*
633 * Inherit the documents already in use by others includes
634 */
635 newctxt->incBase = ctxt->incNr;
636 for (i = 0;i < ctxt->incNr;i++) {
637 newctxt->incTab[i] = ctxt->incTab[i];
638 newctxt->incTab[i]->count++; /* prevent the recursion from
639 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000640 }
Daniel Veillard8edf1c52003-07-22 20:52:14 +0000641 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000642 for (i = 0;i < ctxt->incNr;i++) {
643 newctxt->incTab[i]->count--;
644 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000645 }
Daniel Veillardd9b72832003-03-27 14:24:00 +0000646
647 /* urlTab may have been reallocated */
648 ctxt->urlTab = newctxt->urlTab;
649 ctxt->urlMax = newctxt->urlMax;
650
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000651 newctxt->urlMax = 0;
652 newctxt->urlNr = 0;
653 newctxt->urlTab = NULL;
654
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000655 xmlXIncludeFreeContext(newctxt);
656 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000657#ifdef DEBUG_XINCLUDE
658 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
659#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000660}
661
662/**
663 * xmlXIncludeAddTxt:
664 * @ctxt: the XInclude context
665 * @txt: the new text node
666 * @url: the associated URL
667 *
668 * Add a new txtument to the list
669 */
670static void
671xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000672#ifdef DEBUG_XINCLUDE
673 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
674#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000675 if (ctxt->txtMax == 0) {
676 ctxt->txtMax = 4;
677 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
678 sizeof(ctxt->txtTab[0]));
679 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000680 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000681 return;
682 }
683 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
684 sizeof(ctxt->txturlTab[0]));
685 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000686 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000687 return;
688 }
689 }
690 if (ctxt->txtNr >= ctxt->txtMax) {
691 ctxt->txtMax *= 2;
692 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
693 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
694 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000695 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000696 return;
697 }
698 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000699 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000700 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000701 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000702 return;
703 }
704 }
705 ctxt->txtTab[ctxt->txtNr] = txt;
706 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
707 ctxt->txtNr++;
708}
709
Owen Taylor3473f882001-02-23 17:55:21 +0000710/************************************************************************
711 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000712 * Node copy with specific semantic *
713 * *
714 ************************************************************************/
715
716/**
717 * xmlXIncludeCopyNode:
718 * @ctxt: the XInclude context
719 * @target: the document target
720 * @source: the document source
721 * @elem: the element
722 *
723 * Make a copy of the node while preserving the XInclude semantic
724 * of the Infoset copy
725 */
726static xmlNodePtr
727xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
728 xmlDocPtr source, xmlNodePtr elem) {
729 xmlNodePtr result = NULL;
730
731 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
732 (elem == NULL))
733 return(NULL);
734 if (elem->type == XML_DTD_NODE)
735 return(NULL);
736 result = xmlDocCopyNode(elem, target, 1);
737 return(result);
738}
739
740/**
741 * xmlXIncludeCopyNodeList:
742 * @ctxt: the XInclude context
743 * @target: the document target
744 * @source: the document source
745 * @elem: the element list
746 *
747 * Make a copy of the node list while preserving the XInclude semantic
748 * of the Infoset copy
749 */
750static xmlNodePtr
751xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
752 xmlDocPtr source, xmlNodePtr elem) {
753 xmlNodePtr cur, res, result = NULL, last = NULL;
754
755 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
756 (elem == NULL))
757 return(NULL);
758 cur = elem;
759 while (cur != NULL) {
760 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
761 if (res != NULL) {
762 if (result == NULL) {
763 result = last = res;
764 } else {
765 last->next = res;
766 res->prev = last;
767 last = res;
768 }
769 }
770 cur = cur->next;
771 }
772 return(result);
773}
774
775/**
776 * xmlXInclueGetNthChild:
777 * @cur: the node
778 * @no: the child number
779 *
780 * Returns the @no'th element child of @cur or NULL
781 */
782static xmlNodePtr
783xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
784 int i;
785 if (cur == NULL)
786 return(cur);
787 cur = cur->children;
788 for (i = 0;i <= no;cur = cur->next) {
789 if (cur == NULL)
790 return(cur);
791 if ((cur->type == XML_ELEMENT_NODE) ||
792 (cur->type == XML_DOCUMENT_NODE) ||
793 (cur->type == XML_HTML_DOCUMENT_NODE)) {
794 i++;
795 if (i == no)
796 break;
797 }
798 }
799 return(cur);
800}
801
802xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
803
804/**
805 * xmlXIncludeCopyRange:
806 * @ctxt: the XInclude context
807 * @target: the document target
808 * @source: the document source
809 * @obj: the XPointer result from the evaluation.
810 *
811 * Build a node list tree copy of the XPointer result.
812 *
813 * Returns an xmlNodePtr list or NULL.
814 * the caller has to free the node tree.
815 */
816static xmlNodePtr
817xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
818 xmlDocPtr source, xmlXPathObjectPtr range) {
819 /* pointers to generated nodes */
820 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
821 /* pointers to traversal nodes */
822 xmlNodePtr start, cur, end;
823 int index1, index2;
824
825 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
826 (range == NULL))
827 return(NULL);
828 if (range->type != XPATH_RANGE)
829 return(NULL);
830 start = (xmlNodePtr) range->user;
831
832 if (start == NULL)
833 return(NULL);
834 end = range->user2;
835 if (end == NULL)
836 return(xmlDocCopyNode(start, target, 1));
837
838 cur = start;
839 index1 = range->index;
840 index2 = range->index2;
841 while (cur != NULL) {
842 if (cur == end) {
843 if (cur->type == XML_TEXT_NODE) {
844 const xmlChar *content = cur->content;
845 int len;
846
847 if (content == NULL) {
848 tmp = xmlNewTextLen(NULL, 0);
849 } else {
850 len = index2;
851 if ((cur == start) && (index1 > 1)) {
852 content += (index1 - 1);
853 len -= (index1 - 1);
854 index1 = 0;
855 } else {
856 len = index2;
857 }
858 tmp = xmlNewTextLen(content, len);
859 }
860 /* single sub text node selection */
861 if (list == NULL)
862 return(tmp);
863 /* prune and return full set */
864 if (last != NULL)
865 xmlAddNextSibling(last, tmp);
866 else
867 xmlAddChild(parent, tmp);
868 return(list);
869 } else {
870 tmp = xmlDocCopyNode(cur, target, 0);
871 if (list == NULL)
872 list = tmp;
873 else {
874 if (last != NULL)
875 xmlAddNextSibling(last, tmp);
876 else
877 xmlAddChild(parent, tmp);
878 }
879 last = NULL;
880 parent = tmp;
881
882 if (index2 > 1) {
883 end = xmlXIncludeGetNthChild(cur, index2 - 1);
884 index2 = 0;
885 }
886 if ((cur == start) && (index1 > 1)) {
887 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
888 index1 = 0;
889 } else {
890 cur = cur->children;
891 }
892 /*
893 * Now gather the remaining nodes from cur to end
894 */
895 continue; /* while */
896 }
897 } else if ((cur == start) &&
898 (list == NULL) /* looks superfluous but ... */ ) {
899 if ((cur->type == XML_TEXT_NODE) ||
900 (cur->type == XML_CDATA_SECTION_NODE)) {
901 const xmlChar *content = cur->content;
902
903 if (content == NULL) {
904 tmp = xmlNewTextLen(NULL, 0);
905 } else {
906 if (index1 > 1) {
907 content += (index1 - 1);
908 }
909 tmp = xmlNewText(content);
910 }
911 last = list = tmp;
912 } else {
913 if ((cur == start) && (index1 > 1)) {
914 tmp = xmlDocCopyNode(cur, target, 0);
915 list = tmp;
916 parent = tmp;
917 last = NULL;
918 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
919 index1 = 0;
920 /*
921 * Now gather the remaining nodes from cur to end
922 */
923 continue; /* while */
924 }
925 tmp = xmlDocCopyNode(cur, target, 1);
926 list = tmp;
927 parent = NULL;
928 last = tmp;
929 }
930 } else {
931 tmp = NULL;
932 switch (cur->type) {
933 case XML_DTD_NODE:
934 case XML_ELEMENT_DECL:
935 case XML_ATTRIBUTE_DECL:
936 case XML_ENTITY_NODE:
937 /* Do not copy DTD informations */
938 break;
939 case XML_ENTITY_DECL:
940 /* handle crossing entities -> stack needed */
941 break;
942 case XML_XINCLUDE_START:
943 case XML_XINCLUDE_END:
944 /* don't consider it part of the tree content */
945 break;
946 case XML_ATTRIBUTE_NODE:
947 /* Humm, should not happen ! */
948 break;
949 default:
950 tmp = xmlDocCopyNode(cur, target, 1);
951 break;
952 }
953 if (tmp != NULL) {
954 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
955 return(NULL);
956 }
957 if (last != NULL)
958 xmlAddNextSibling(last, tmp);
959 else {
960 xmlAddChild(parent, tmp);
961 last = tmp;
962 }
963 }
964 }
965 /*
966 * Skip to next node in document order
967 */
968 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
969 return(NULL);
970 }
971 cur = xmlXPtrAdvanceNode(cur);
972 }
973 return(list);
974}
975
976/**
977 * xmlXIncludeBuildNodeList:
978 * @ctxt: the XInclude context
979 * @target: the document target
980 * @source: the document source
981 * @obj: the XPointer result from the evaluation.
982 *
983 * Build a node list tree copy of the XPointer result.
984 * This will drop Attributes and Namespace declarations.
985 *
986 * Returns an xmlNodePtr list or NULL.
987 * the caller has to free the node tree.
988 */
989static xmlNodePtr
990xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
991 xmlDocPtr source, xmlXPathObjectPtr obj) {
992 xmlNodePtr list = NULL, last = NULL;
993 int i;
994
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000995 if (source == NULL)
996 source = ctxt->doc;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000997 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
998 (obj == NULL))
999 return(NULL);
1000 switch (obj->type) {
1001 case XPATH_NODESET: {
1002 xmlNodeSetPtr set = obj->nodesetval;
1003 if (set == NULL)
1004 return(NULL);
1005 for (i = 0;i < set->nodeNr;i++) {
1006 if (set->nodeTab[i] == NULL)
1007 continue;
1008 switch (set->nodeTab[i]->type) {
1009 case XML_TEXT_NODE:
1010 case XML_CDATA_SECTION_NODE:
1011 case XML_ELEMENT_NODE:
1012 case XML_ENTITY_REF_NODE:
1013 case XML_ENTITY_NODE:
1014 case XML_PI_NODE:
1015 case XML_COMMENT_NODE:
1016 case XML_DOCUMENT_NODE:
1017 case XML_HTML_DOCUMENT_NODE:
1018#ifdef LIBXML_DOCB_ENABLED
1019 case XML_DOCB_DOCUMENT_NODE:
1020#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001021 case XML_XINCLUDE_END:
1022 break;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001023 case XML_XINCLUDE_START: {
1024 xmlNodePtr tmp, cur = set->nodeTab[i];
1025
1026 cur = cur->next;
1027 while (cur != NULL) {
1028 switch(cur->type) {
1029 case XML_TEXT_NODE:
1030 case XML_CDATA_SECTION_NODE:
1031 case XML_ELEMENT_NODE:
1032 case XML_ENTITY_REF_NODE:
1033 case XML_ENTITY_NODE:
1034 case XML_PI_NODE:
1035 case XML_COMMENT_NODE:
1036 tmp = xmlXIncludeCopyNode(ctxt, target,
1037 source, cur);
1038 if (last == NULL) {
1039 list = last = tmp;
1040 } else {
1041 xmlAddNextSibling(last, tmp);
1042 last = tmp;
1043 }
1044 cur = cur->next;
1045 continue;
1046 default:
1047 break;
1048 }
1049 break;
1050 }
1051 continue;
1052 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001053 case XML_ATTRIBUTE_NODE:
1054 case XML_NAMESPACE_DECL:
1055 case XML_DOCUMENT_TYPE_NODE:
1056 case XML_DOCUMENT_FRAG_NODE:
1057 case XML_NOTATION_NODE:
1058 case XML_DTD_NODE:
1059 case XML_ELEMENT_DECL:
1060 case XML_ATTRIBUTE_DECL:
1061 case XML_ENTITY_DECL:
1062 continue; /* for */
1063 }
1064 if (last == NULL)
1065 list = last = xmlXIncludeCopyNode(ctxt, target, source,
1066 set->nodeTab[i]);
1067 else {
1068 xmlAddNextSibling(last,
1069 xmlXIncludeCopyNode(ctxt, target, source,
1070 set->nodeTab[i]));
1071 if (last->next != NULL)
1072 last = last->next;
1073 }
1074 }
1075 break;
1076 }
1077 case XPATH_LOCATIONSET: {
1078 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1079 if (set == NULL)
1080 return(NULL);
1081 for (i = 0;i < set->locNr;i++) {
1082 if (last == NULL)
1083 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
1084 set->locTab[i]);
1085 else
1086 xmlAddNextSibling(last,
1087 xmlXIncludeCopyXPointer(ctxt, target, source,
1088 set->locTab[i]));
1089 if (last != NULL) {
1090 while (last->next != NULL)
1091 last = last->next;
1092 }
1093 }
1094 break;
1095 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001096#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001097 case XPATH_RANGE:
1098 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001099#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001100 case XPATH_POINT:
1101 /* points are ignored in XInclude */
1102 break;
1103 default:
1104 break;
1105 }
1106 return(list);
1107}
1108/************************************************************************
1109 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001110 * XInclude I/O handling *
1111 * *
1112 ************************************************************************/
1113
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001114typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1115typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1116struct _xmlXIncludeMergeData {
1117 xmlDocPtr doc;
1118 xmlXIncludeCtxtPtr ctxt;
1119};
1120
Owen Taylor3473f882001-02-23 17:55:21 +00001121/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001122 * xmlXIncludeMergeOneEntity:
1123 * @ent: the entity
1124 * @doc: the including doc
1125 * @nr: the entity name
1126 *
1127 * Inplements the merge of one entity
1128 */
1129static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001130xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001131 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001132 xmlEntityPtr ret, prev;
1133 xmlDocPtr doc;
1134 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001135
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001136 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001137 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001138 ctxt = data->ctxt;
1139 doc = data->doc;
1140 if ((ctxt == NULL) || (doc == NULL))
1141 return;
1142 switch (ent->etype) {
1143 case XML_INTERNAL_PARAMETER_ENTITY:
1144 case XML_EXTERNAL_PARAMETER_ENTITY:
1145 case XML_INTERNAL_PREDEFINED_ENTITY:
1146 return;
1147 case XML_INTERNAL_GENERAL_ENTITY:
1148 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1149 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1150 break;
1151 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001152 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1153 ent->SystemID, ent->content);
1154 if (ret != NULL) {
1155 if (ent->URI != NULL)
1156 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001157 } else {
1158 prev = xmlGetDocEntity(doc, ent->name);
1159 if (prev != NULL) {
1160 if (ent->etype != prev->etype)
1161 goto error;
1162
1163 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1164 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1165 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001166 } else if ((ent->ExternalID != NULL) &&
1167 (prev->ExternalID != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001168 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1169 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001170 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1171 if (!xmlStrEqual(ent->content, prev->content))
1172 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001173 } else {
1174 goto error;
1175 }
1176
1177 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001178 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001179 return;
1180error:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001181 switch (ent->etype) {
1182 case XML_INTERNAL_PARAMETER_ENTITY:
1183 case XML_EXTERNAL_PARAMETER_ENTITY:
1184 case XML_INTERNAL_PREDEFINED_ENTITY:
1185 case XML_INTERNAL_GENERAL_ENTITY:
1186 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1187 return;
1188 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1189 break;
1190 }
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001191 xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
1192 "mismatch in redefinition of entity %s\n",
1193 ent->name);
Daniel Veillard4287c572003-02-04 22:48:53 +00001194}
1195
1196/**
1197 * xmlXIncludeMergeEntities:
1198 * @ctxt: an XInclude context
1199 * @doc: the including doc
1200 * @from: the included doc
1201 *
1202 * Inplements the entity merge
1203 *
1204 * Returns 0 if merge succeeded, -1 if some processing failed
1205 */
1206static int
1207xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1208 xmlDocPtr from) {
1209 xmlNodePtr cur;
1210 xmlDtdPtr target, source;
1211
1212 if (ctxt == NULL)
1213 return(-1);
1214
1215 if ((from == NULL) || (from->intSubset == NULL))
1216 return(0);
1217
1218 target = doc->intSubset;
1219 if (target == NULL) {
1220 cur = xmlDocGetRootElement(doc);
1221 if (cur == NULL)
1222 return(-1);
1223 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1224 if (target == NULL)
1225 return(-1);
1226 }
1227
1228 source = from->intSubset;
1229 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001230 xmlXIncludeMergeData data;
1231
1232 data.ctxt = ctxt;
1233 data.doc = doc;
1234
Daniel Veillard4287c572003-02-04 22:48:53 +00001235 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001236 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001237 }
1238 source = from->extSubset;
1239 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001240 xmlXIncludeMergeData data;
1241
1242 data.ctxt = ctxt;
1243 data.doc = doc;
1244
Daniel Veillard4287c572003-02-04 22:48:53 +00001245 /*
1246 * don't duplicate existing stuff when external subsets are the same
1247 */
1248 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1249 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1250 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001251 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001252 }
1253 }
1254 return(0);
1255}
1256
1257/**
Owen Taylor3473f882001-02-23 17:55:21 +00001258 * xmlXIncludeLoadDoc:
1259 * @ctxt: the XInclude context
1260 * @url: the associated URL
1261 * @nr: the xinclude node number
1262 *
1263 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001264 *
1265 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001266 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001267static int
Owen Taylor3473f882001-02-23 17:55:21 +00001268xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1269 xmlDocPtr doc;
1270 xmlURIPtr uri;
1271 xmlChar *URL;
1272 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001273 int i = 0;
1274
1275#ifdef DEBUG_XINCLUDE
1276 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1277#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001278 /*
1279 * Check the URL and remove any fragment identifier
1280 */
1281 uri = xmlParseURI((const char *)url);
1282 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001283 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1284 XML_XINCLUDE_HREF_URI,
1285 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001286 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001287 }
1288 if (uri->fragment != NULL) {
1289 fragment = (xmlChar *) uri->fragment;
1290 uri->fragment = NULL;
1291 }
1292 URL = xmlSaveUri(uri);
1293 xmlFreeURI(uri);
1294 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001295 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1296 XML_XINCLUDE_HREF_URI,
1297 "invalid value URI %s\n", url);
Owen Taylor3473f882001-02-23 17:55:21 +00001298 if (fragment != NULL)
1299 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001300 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001301 }
1302
1303 /*
1304 * Handling of references to the local document are done
1305 * directly through ctxt->doc.
1306 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001307 if ((URL[0] == 0) || (URL[0] == '#') ||
1308 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001309 doc = NULL;
1310 goto loaded;
1311 }
1312
1313 /*
1314 * Prevent reloading twice the document.
1315 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001316 for (i = 0; i < ctxt->incNr; i++) {
1317 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1318 (ctxt->incTab[i]->doc != NULL)) {
1319 doc = ctxt->incTab[i]->doc;
1320#ifdef DEBUG_XINCLUDE
1321 printf("Already loaded %s\n", URL);
1322#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001323 goto loaded;
1324 }
1325 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001326
Owen Taylor3473f882001-02-23 17:55:21 +00001327 /*
1328 * Load it.
1329 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001330#ifdef DEBUG_XINCLUDE
1331 printf("loading %s\n", URL);
1332#endif
Daniel Veillard98485322003-08-14 15:44:40 +00001333 doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001334 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001335 xmlFree(URL);
1336 if (fragment != NULL)
1337 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001338 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001339 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001340 ctxt->incTab[nr]->doc = doc;
Daniel Veillard98485322003-08-14 15:44:40 +00001341 for (i = nr + 1; i < ctxt->incNr; i++) {
1342 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1343 ctxt->incTab[nr]->count++;
1344#ifdef DEBUG_XINCLUDE
1345 printf("Increasing %s count since reused\n", URL);
1346#endif
1347 break;
1348 }
1349 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001350
1351 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001352 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001353 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001354 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001355
1356 /*
1357 * We don't need the DTD anymore, free up space
1358 if (doc->intSubset != NULL) {
1359 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1360 xmlFreeNode((xmlNodePtr) doc->intSubset);
1361 doc->intSubset = NULL;
1362 }
1363 if (doc->extSubset != NULL) {
1364 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1365 xmlFreeNode((xmlNodePtr) doc->extSubset);
1366 doc->extSubset = NULL;
1367 }
1368 */
1369 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001370
1371loaded:
1372 if (fragment == NULL) {
1373 /*
1374 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001375 */
1376 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001377 {
1378 /* Hopefully a DTD declaration won't be copied from
1379 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001380 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001381 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001382 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001383 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001384 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001385 }
1386#ifdef LIBXML_XPTR_ENABLED
1387 else {
Owen Taylor3473f882001-02-23 17:55:21 +00001388 /*
1389 * Computes the XPointer expression and make a copy used
1390 * as the replacement copy.
1391 */
1392 xmlXPathObjectPtr xptr;
1393 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001394 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001395
1396 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001397 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1398 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001399 } else {
1400 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1401 }
1402 if (xptrctxt == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001403 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1404 XML_XINCLUDE_XPTR_FAILED,
Daniel Veillarda152c4d2003-11-19 16:24:26 +00001405 "could not create XPointer context\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001406 xmlFree(URL);
1407 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001408 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001409 }
1410 xptr = xmlXPtrEval(fragment, xptrctxt);
1411 if (xptr == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001412 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1413 XML_XINCLUDE_XPTR_FAILED,
1414 "XPointer evaluation failed: #%s\n",
1415 fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001416 xmlXPathFreeContext(xptrctxt);
1417 xmlFree(URL);
1418 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001419 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001420 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001421 switch (xptr->type) {
1422 case XPATH_UNDEFINED:
1423 case XPATH_BOOLEAN:
1424 case XPATH_NUMBER:
1425 case XPATH_STRING:
1426 case XPATH_POINT:
1427 case XPATH_USERS:
1428 case XPATH_XSLT_TREE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001429 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1430 XML_XINCLUDE_XPTR_RESULT,
1431 "XPointer is not a range: #%s\n",
1432 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001433 xmlXPathFreeContext(xptrctxt);
1434 xmlFree(URL);
1435 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001436 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001437 case XPATH_NODESET:
Daniel Veillard798ae542003-11-03 17:13:52 +00001438 if ((xptr->nodesetval == NULL) ||
1439 (xptr->nodesetval->nodeNr <= 0)) {
1440 xmlXPathFreeContext(xptrctxt);
1441 xmlFree(URL);
1442 xmlFree(fragment);
1443 return(-1);
1444 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001445 case XPATH_RANGE:
1446 case XPATH_LOCATIONSET:
1447 break;
1448 }
1449 set = xptr->nodesetval;
1450 if (set != NULL) {
1451 for (i = 0;i < set->nodeNr;i++) {
1452 if (set->nodeTab[i] == NULL)
1453 continue;
1454 switch (set->nodeTab[i]->type) {
1455 case XML_TEXT_NODE:
1456 case XML_CDATA_SECTION_NODE:
1457 case XML_ELEMENT_NODE:
1458 case XML_ENTITY_REF_NODE:
1459 case XML_ENTITY_NODE:
1460 case XML_PI_NODE:
1461 case XML_COMMENT_NODE:
1462 case XML_DOCUMENT_NODE:
1463 case XML_HTML_DOCUMENT_NODE:
1464#ifdef LIBXML_DOCB_ENABLED
1465 case XML_DOCB_DOCUMENT_NODE:
1466#endif
1467 continue;
1468 case XML_ATTRIBUTE_NODE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001469 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1470 XML_XINCLUDE_XPTR_RESULT,
1471 "XPointer selects an attribute: #%s\n",
1472 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001473 set->nodeTab[i] = NULL;
1474 continue;
1475 case XML_NAMESPACE_DECL:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001476 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1477 XML_XINCLUDE_XPTR_RESULT,
1478 "XPointer selects a namespace: #%s\n",
1479 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001480 set->nodeTab[i] = NULL;
1481 continue;
1482 case XML_DOCUMENT_TYPE_NODE:
1483 case XML_DOCUMENT_FRAG_NODE:
1484 case XML_NOTATION_NODE:
1485 case XML_DTD_NODE:
1486 case XML_ELEMENT_DECL:
1487 case XML_ATTRIBUTE_DECL:
1488 case XML_ENTITY_DECL:
1489 case XML_XINCLUDE_START:
1490 case XML_XINCLUDE_END:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001491 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1492 XML_XINCLUDE_XPTR_RESULT,
1493 "XPointer selects unexpected nodes: #%s\n",
1494 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001495 set->nodeTab[i] = NULL;
1496 set->nodeTab[i] = NULL;
1497 continue; /* for */
1498 }
1499 }
1500 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001501 if (doc == NULL) {
1502 ctxt->incTab[nr]->xptr = xptr;
1503 ctxt->incTab[nr]->inc = NULL;
1504 } else {
1505 ctxt->incTab[nr]->inc =
1506 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1507 xmlXPathFreeObject(xptr);
1508 }
Owen Taylor3473f882001-02-23 17:55:21 +00001509 xmlXPathFreeContext(xptrctxt);
1510 xmlFree(fragment);
1511 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001512#endif
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001513
1514 /*
1515 * Do the xml:base fixup if needed
1516 */
1517 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1518 xmlNodePtr node;
1519
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001520 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001521 while (node != NULL) {
1522 if (node->type == XML_ELEMENT_NODE)
1523 xmlNodeSetBase(node, URL);
1524 node = node->next;
1525 }
1526 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001527 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1528 (ctxt->incTab[nr]->count <= 1)) {
1529#ifdef DEBUG_XINCLUDE
1530 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1531#endif
1532 xmlFreeDoc(ctxt->incTab[nr]->doc);
1533 ctxt->incTab[nr]->doc = NULL;
1534 }
Owen Taylor3473f882001-02-23 17:55:21 +00001535 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001536 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001537}
1538
1539/**
1540 * xmlXIncludeLoadTxt:
1541 * @ctxt: the XInclude context
1542 * @url: the associated URL
1543 * @nr: the xinclude node number
1544 *
1545 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001546 *
1547 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001548 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001549static int
Owen Taylor3473f882001-02-23 17:55:21 +00001550xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1551 xmlParserInputBufferPtr buf;
1552 xmlNodePtr node;
1553 xmlURIPtr uri;
1554 xmlChar *URL;
1555 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001556 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001557 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001558
Owen Taylor3473f882001-02-23 17:55:21 +00001559 /*
1560 * Check the URL and remove any fragment identifier
1561 */
1562 uri = xmlParseURI((const char *)url);
1563 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001564 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1565 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001566 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001567 }
1568 if (uri->fragment != NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001569 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1570 "fragment identifier forbidden for text: %s\n",
1571 (const xmlChar *) uri->fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001572 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001573 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001574 }
1575 URL = xmlSaveUri(uri);
1576 xmlFreeURI(uri);
1577 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001578 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1579 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001580 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001581 }
1582
1583 /*
1584 * Handling of references to the local document are done
1585 * directly through ctxt->doc.
1586 */
1587 if (URL[0] == 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001588 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1589 XML_XINCLUDE_TEXT_DOCUMENT,
1590 "text serialization of document not available\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001591 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001592 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001593 }
1594
1595 /*
1596 * Prevent reloading twice the document.
1597 */
1598 for (i = 0; i < ctxt->txtNr; i++) {
1599 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1600 node = xmlCopyNode(ctxt->txtTab[i], 1);
1601 goto loaded;
1602 }
1603 }
1604 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001605 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001606 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001607 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1608 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1609 }
1610 if (encoding != NULL) {
1611 /*
1612 * TODO: we should not have to remap to the xmlCharEncoding
1613 * predefined set, a better interface than
1614 * xmlParserInputBufferCreateFilename should allow any
1615 * encoding supported by iconv
1616 */
1617 enc = xmlParseCharEncoding((const char *) encoding);
1618 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001619 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1620 XML_XINCLUDE_UNKNOWN_ENCODING,
1621 "encoding %s not supported\n", encoding);
Daniel Veillardd076a202002-11-20 13:28:31 +00001622 xmlFree(encoding);
1623 xmlFree(URL);
1624 return(-1);
1625 }
1626 xmlFree(encoding);
1627 }
1628
1629 /*
1630 * Load it.
1631 */
1632 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001633 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001634 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001635 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001636 }
1637 node = xmlNewText(NULL);
1638
1639 /*
1640 * Scan all chars from the resource and add the to the node
1641 */
1642 while (xmlParserInputBufferRead(buf, 128) > 0) {
1643 int len;
1644 const xmlChar *content;
1645
1646 content = xmlBufferContent(buf->buffer);
1647 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001648 for (i = 0;i < len;) {
1649 int cur;
1650 int l;
1651
1652 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1653 if (!IS_CHAR(cur)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001654 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1655 XML_XINCLUDE_INVALID_CHAR,
1656 "%s contains invalid char\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001657 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001658 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001659 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001660 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001661 }
1662 xmlBufferShrink(buf->buffer, len);
1663 }
1664 xmlFreeParserInputBuffer(buf);
1665 xmlXIncludeAddTxt(ctxt, node, URL);
1666
1667loaded:
1668 /*
1669 * Add the element as the replacement copy.
1670 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001671 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001672 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001673 return(0);
1674}
1675
1676/**
1677 * xmlXIncludeLoadFallback:
1678 * @ctxt: the XInclude context
1679 * @fallback: the fallback node
1680 * @nr: the xinclude node number
1681 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001682 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001683 * in the XInclude context
1684 *
1685 * Returns 0 in case of success, -1 in case of failure
1686 */
1687static int
1688xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1689 if ((fallback == NULL) || (ctxt == NULL))
1690 return(-1);
1691
Daniel Veillard06503452002-12-13 10:42:08 +00001692 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001693 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001694}
1695
1696/************************************************************************
1697 * *
1698 * XInclude Processing *
1699 * *
1700 ************************************************************************/
1701
1702/**
1703 * xmlXIncludePreProcessNode:
1704 * @ctxt: an XInclude context
1705 * @node: an XInclude node
1706 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001707 * Implement the XInclude preprocessing, currently just adding the element
1708 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001709 *
1710 * Returns the result list or NULL in case of error
1711 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001712static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001713xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1714 xmlXIncludeAddNode(ctxt, node);
1715 return(0);
1716}
1717
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001718/**
Owen Taylor3473f882001-02-23 17:55:21 +00001719 * xmlXIncludeLoadNode:
1720 * @ctxt: an XInclude context
1721 * @nr: the node number
1722 *
1723 * Find and load the infoset replacement for the given node.
1724 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001725 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001726 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001727static int
Owen Taylor3473f882001-02-23 17:55:21 +00001728xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1729 xmlNodePtr cur;
1730 xmlChar *href;
1731 xmlChar *parse;
1732 xmlChar *base;
1733 xmlChar *URI;
1734 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001735 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001736
1737 if (ctxt == NULL)
1738 return(-1);
1739 if ((nr < 0) || (nr >= ctxt->incNr))
1740 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001741 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001742 if (cur == NULL)
1743 return(-1);
1744
Owen Taylor3473f882001-02-23 17:55:21 +00001745 /*
1746 * read the attributes
1747 */
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001748 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
Owen Taylor3473f882001-02-23 17:55:21 +00001749 if (href == NULL) {
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001750 /* @@@@ */
1751 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1752 XML_XINCLUDE_NO_HREF, "no href\n", NULL);
1753 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001754 }
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001755 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
Owen Taylor3473f882001-02-23 17:55:21 +00001756 if (parse != NULL) {
1757 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1758 xml = 1;
1759 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1760 xml = 0;
1761 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001762 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1763 XML_XINCLUDE_PARSE_VALUE,
1764 "invalid value %s for 'parse'\n", parse);
Owen Taylor3473f882001-02-23 17:55:21 +00001765 if (href != NULL)
1766 xmlFree(href);
1767 if (parse != NULL)
1768 xmlFree(parse);
1769 return(-1);
1770 }
1771 }
1772
1773 /*
1774 * compute the URI
1775 */
1776 base = xmlNodeGetBase(ctxt->doc, cur);
1777 if (base == NULL) {
1778 URI = xmlBuildURI(href, ctxt->doc->URL);
1779 } else {
1780 URI = xmlBuildURI(href, base);
1781 }
1782 if (URI == NULL) {
1783 xmlChar *escbase;
1784 xmlChar *eschref;
1785 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001786 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001787 */
1788 escbase = xmlURIEscape(base);
1789 eschref = xmlURIEscape(href);
1790 URI = xmlBuildURI(eschref, escbase);
1791 if (escbase != NULL)
1792 xmlFree(escbase);
1793 if (eschref != NULL)
1794 xmlFree(eschref);
1795 }
1796 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001797 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1798 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001799 if (parse != NULL)
1800 xmlFree(parse);
1801 if (href != NULL)
1802 xmlFree(href);
1803 if (base != NULL)
1804 xmlFree(base);
1805 return(-1);
1806 }
1807#ifdef DEBUG_XINCLUDE
1808 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1809 xml ? "xml": "text");
1810 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1811#endif
1812
1813 /*
1814 * Cleanup
1815 */
1816 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001817 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001818 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1819 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001820 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1821 }
1822 if (ret < 0) {
1823 xmlNodePtr children;
1824
1825 /*
1826 * Time to try a fallback if availble
1827 */
1828#ifdef DEBUG_XINCLUDE
1829 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1830#endif
1831 children = cur->children;
1832 while (children != NULL) {
1833 if ((children->type == XML_ELEMENT_NODE) &&
1834 (children->ns != NULL) &&
1835 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001836 ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
1837 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001838 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1839 if (ret == 0)
1840 break;
1841 }
1842 children = children->next;
1843 }
1844 }
1845 if (ret < 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001846 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1847 XML_XINCLUDE_NO_FALLBACK,
1848 "could not load %s, and no fallback was found\n",
1849 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001850 }
1851
1852 /*
1853 * Cleanup
1854 */
1855 if (URI != NULL)
1856 xmlFree(URI);
1857 if (parse != NULL)
1858 xmlFree(parse);
1859 if (href != NULL)
1860 xmlFree(href);
1861 if (base != NULL)
1862 xmlFree(base);
1863 return(0);
1864}
1865
1866/**
1867 * xmlXIncludeIncludeNode:
1868 * @ctxt: an XInclude context
1869 * @nr: the node number
1870 *
1871 * Inplement the infoset replacement for the given node
1872 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001873 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001874 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001875static int
Owen Taylor3473f882001-02-23 17:55:21 +00001876xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001877 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001878
1879 if (ctxt == NULL)
1880 return(-1);
1881 if ((nr < 0) || (nr >= ctxt->incNr))
1882 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001883 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001884 if (cur == NULL)
1885 return(-1);
1886
1887 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001888 * If we stored an XPointer a late computation may be needed
1889 */
1890 if ((ctxt->incTab[nr]->inc == NULL) &&
1891 (ctxt->incTab[nr]->xptr != NULL)) {
1892 ctxt->incTab[nr]->inc =
1893 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1894 ctxt->incTab[nr]->xptr);
1895 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1896 ctxt->incTab[nr]->xptr = NULL;
1897 }
1898 list = ctxt->incTab[nr]->inc;
1899 ctxt->incTab[nr]->inc = NULL;
1900
1901 /*
1902 * Check against the risk of generating a multi-rooted document
1903 */
1904 if ((cur->parent != NULL) &&
1905 (cur->parent->type != XML_ELEMENT_NODE)) {
1906 int nb_elem = 0;
1907
1908 tmp = list;
1909 while (tmp != NULL) {
1910 if (tmp->type == XML_ELEMENT_NODE)
1911 nb_elem++;
1912 tmp = tmp->next;
1913 }
1914 if (nb_elem > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001915 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1916 XML_XINCLUDE_MULTIPLE_ROOT,
1917 "XInclude error: would result in multiple root nodes\n",
1918 NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001919 return(-1);
1920 }
1921 }
1922
1923 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001924 * Change the current node as an XInclude start one, and add an
1925 * entity end one
1926 */
1927 cur->type = XML_XINCLUDE_START;
1928 end = xmlNewNode(cur->ns, cur->name);
1929 if (end == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001930 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED,
1931 "failed to build node\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001932 return(-1);
1933 }
1934 end->type = XML_XINCLUDE_END;
1935 xmlAddNextSibling(cur, end);
1936
1937 /*
1938 * Add the list of nodes
1939 */
Owen Taylor3473f882001-02-23 17:55:21 +00001940 while (list != NULL) {
1941 cur = list;
1942 list = list->next;
1943
1944 xmlAddPrevSibling(end, cur);
1945 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001946
1947
Owen Taylor3473f882001-02-23 17:55:21 +00001948 return(0);
1949}
1950
1951/**
1952 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001953 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001954 * @node: an XInclude node
1955 *
1956 * test if the node is an XInclude node
1957 *
1958 * Returns 1 true, 0 otherwise
1959 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001960static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001961xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001962 if (node == NULL)
1963 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00001964 if (node->type != XML_ELEMENT_NODE)
1965 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001966 if (node->ns == NULL)
1967 return(0);
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001968 if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
1969 (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
1970 if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
1971 if (ctxt->legacy == 0) {
1972 xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
1973 "Deprecated XInclude namespace found, use %s",
1974 XINCLUDE_NS);
1975 }
1976 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001977 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
1978 xmlNodePtr child = node->children;
1979 int nb_fallback = 0;
1980
1981 while (child != NULL) {
1982 if ((child->type == XML_ELEMENT_NODE) &&
1983 (child->ns != NULL) &&
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001984 ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
1985 (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001986 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001987 xmlXIncludeErr(ctxt, node,
1988 XML_XINCLUDE_INCLUDE_IN_INCLUDE,
1989 "%s has an 'include' child\n",
1990 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001991 return(0);
1992 }
1993 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
1994 nb_fallback++;
1995 }
1996 }
1997 child = child->next;
1998 }
1999 if (nb_fallback > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002000 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
2001 "%s has multiple fallback children\n",
2002 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002003 return(0);
2004 }
2005 return(1);
2006 }
2007 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2008 if ((node->parent == NULL) ||
2009 (node->parent->type != XML_ELEMENT_NODE) ||
2010 (node->parent->ns == NULL) ||
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002011 ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
2012 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002013 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002014 xmlXIncludeErr(ctxt, node,
2015 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
2016 "%s is not the child of an 'include'\n",
2017 XINCLUDE_FALLBACK);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002018 }
2019 }
2020 }
Owen Taylor3473f882001-02-23 17:55:21 +00002021 return(0);
2022}
2023
2024/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002025 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002026 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002027 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002028 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00002029 *
2030 * Implement the XInclude substitution on the XML document @doc
2031 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002032 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002033 * or the number of substitutions done.
2034 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002035static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002036xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00002037 xmlNodePtr cur;
2038 int ret = 0;
2039 int i;
2040
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002041 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002042 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002043 if (ctxt == NULL)
2044 return(-1);
2045
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002046 if (doc->URL != NULL) {
2047 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2048 if (ret < 0)
2049 return(-1);
2050 }
2051
Owen Taylor3473f882001-02-23 17:55:21 +00002052 /*
2053 * First phase: lookup the elements in the document
2054 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002055 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002056 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002057 xmlXIncludePreProcessNode(ctxt, cur);
2058 while (cur != NULL) {
2059 /* TODO: need to work on entities -> stack */
2060 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002061 (cur->children->type != XML_ENTITY_DECL) &&
2062 (cur->children->type != XML_XINCLUDE_START) &&
2063 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002064 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002065 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002066 xmlXIncludePreProcessNode(ctxt, cur);
2067 } else if (cur->next != NULL) {
2068 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002069 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002070 xmlXIncludePreProcessNode(ctxt, cur);
2071 } else {
2072 do {
2073 cur = cur->parent;
2074 if (cur == NULL) break; /* do */
2075 if (cur->next != NULL) {
2076 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002077 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002078 xmlXIncludePreProcessNode(ctxt, cur);
2079 break; /* do */
2080 }
2081 } while (cur != NULL);
2082 }
2083 }
2084
2085 /*
2086 * Second Phase : collect the infosets fragments
2087 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002088 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002089 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002090 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002091 }
2092
2093 /*
2094 * Third phase: extend the original document infoset.
2095 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002096 if (ctxt->nbErrors == 0) {
2097 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2098 xmlXIncludeIncludeNode(ctxt, i);
2099 }
Owen Taylor3473f882001-02-23 17:55:21 +00002100 }
2101
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002102 if (doc->URL != NULL)
2103 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002104 return(ret);
2105}
2106
2107/**
2108 * xmlXIncludeProcess:
2109 * @doc: an XML document
2110 *
2111 * Implement the XInclude substitution on the XML document @doc
2112 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002113 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002114 * or the number of substitutions done.
2115 */
2116int
2117xmlXIncludeProcess(xmlDocPtr doc) {
2118 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002119 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002120 int ret = 0;
2121
2122 if (doc == NULL)
2123 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002124 tree = xmlDocGetRootElement(doc);
2125 if (tree == NULL)
2126 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002127 ctxt = xmlXIncludeNewContext(doc);
2128 if (ctxt == NULL)
2129 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002130 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2131 if ((ret >= 0) && (ctxt->nbErrors > 0))
2132 ret = -1;
2133
2134 xmlXIncludeFreeContext(ctxt);
2135 return(ret);
2136}
2137
2138/**
2139 * xmlXIncludeProcessTree:
2140 * @tree: a node in an XML document
2141 *
2142 * Implement the XInclude substitution for the given subtree
2143 *
2144 * Returns 0 if no substitution were done, -1 if some processing failed
2145 * or the number of substitutions done.
2146 */
2147int
2148xmlXIncludeProcessTree(xmlNodePtr tree) {
2149 xmlXIncludeCtxtPtr ctxt;
2150 int ret = 0;
2151
2152 if ((tree == NULL) || (tree->doc == NULL))
2153 return(-1);
2154 ctxt = xmlXIncludeNewContext(tree->doc);
2155 if (ctxt == NULL)
2156 return(-1);
2157 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00002158 if ((ret >= 0) && (ctxt->nbErrors > 0))
2159 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002160
Owen Taylor3473f882001-02-23 17:55:21 +00002161 xmlXIncludeFreeContext(ctxt);
2162 return(ret);
2163}
2164
Daniel Veillard7899c5c2003-11-03 12:31:38 +00002165/**
2166 * xmlXIncludeProcessNode:
2167 * @ctxt: an existing XInclude context
2168 * @node: a node in an XML document
2169 *
2170 * Implement the XInclude substitution for the given subtree reusing
2171 * the informations and data coming from the given context.
2172 *
2173 * Returns 0 if no substitution were done, -1 if some processing failed
2174 * or the number of substitutions done.
2175 */
2176int
2177xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2178 int ret = 0;
2179
2180 if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
2181 return(-1);
2182 ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
2183 if ((ret >= 0) && (ctxt->nbErrors > 0))
2184 ret = -1;
2185 return(ret);
2186}
2187
Owen Taylor3473f882001-02-23 17:55:21 +00002188#else /* !LIBXML_XINCLUDE_ENABLED */
2189#endif