blob: aa14b2c684b1ec61c5c0539d20e166bba5cc48e2 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xinclude.c : Code to implement XInclude processing
3 *
Daniel Veillarde74d2e12003-12-09 11:35:37 +00004 * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003
5 * http://www.w3.org/TR/2003/WD-xinclude-20031110
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 * *
William M. Brack72ee48d2003-12-30 08:30:19 +000041 * XInclude context handling *
Owen Taylor3473f882001-02-23 17:55:21 +000042 * *
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 {
William M. Brack72ee48d2003-12-30 08:30:19 +000053 xmlChar *URI; /* the fully resolved resource URL */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000054 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 */
William M. Brack95af5942004-02-08 04:12:49 +000061 int emptyFb; /* flag to show fallback empty */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000062};
63
Owen Taylor3473f882001-02-23 17:55:21 +000064struct _xmlXIncludeCtxt {
65 xmlDocPtr doc; /* the source document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000066 int incBase; /* the first include for this document */
Owen Taylor3473f882001-02-23 17:55:21 +000067 int incNr; /* number of includes */
68 int incMax; /* size of includes tab */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000069 xmlXIncludeRefPtr *incTab; /* array of included references */
70
Owen Taylor3473f882001-02-23 17:55:21 +000071 int txtNr; /* number of unparsed documents */
72 int txtMax; /* size of unparsed documents tab */
73 xmlNodePtr *txtTab; /* array of unparsed text nodes */
William M. Brack72ee48d2003-12-30 08:30:19 +000074 xmlURL *txturlTab; /* array of unparsed text URLs */
Daniel Veillardd581b7e2003-02-11 18:03:05 +000075
Daniel Veillardf4b4f982003-02-13 11:02:08 +000076 xmlChar * url; /* the current URL processed */
William M. Brack72ee48d2003-12-30 08:30:19 +000077 int urlNr; /* number of URLs stacked */
78 int urlMax; /* size of URL stack */
79 xmlChar * *urlTab; /* URL stack */
Daniel Veillardf4b4f982003-02-13 11:02:08 +000080
Daniel Veillardd581b7e2003-02-11 18:03:05 +000081 int nbErrors; /* the number of errors detected */
Daniel Veillardb5fa0202003-12-08 17:41:29 +000082 int legacy; /* using XINCLUDE_OLD_NS */
Daniel Veillarde74d2e12003-12-09 11:35:37 +000083 int parseFlags; /* the flags used for parsing XML documents */
William M. Brackf7789b12004-06-07 08:57:27 +000084 xmlChar * base; /* the current xml:base */
Owen Taylor3473f882001-02-23 17:55:21 +000085};
86
Daniel Veillardd16df9f2001-05-23 13:44:21 +000087static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +000088xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
Owen Taylor3473f882001-02-23 17:55:21 +000089
Daniel Veillard98485322003-08-14 15:44:40 +000090
Daniel Veillardcd6ff282003-10-08 22:38:13 +000091/************************************************************************
92 * *
Daniel Veillard69d2c172003-10-09 11:46:07 +000093 * XInclude error handler *
Daniel Veillardcd6ff282003-10-08 22:38:13 +000094 * *
95 ************************************************************************/
96
Daniel Veillard98485322003-08-14 15:44:40 +000097/**
Daniel Veillardcd6ff282003-10-08 22:38:13 +000098 * xmlXIncludeErrMemory:
William M. Brack72ee48d2003-12-30 08:30:19 +000099 * @extra: extra information
Daniel Veillard98485322003-08-14 15:44:40 +0000100 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000101 * Handle an out of memory condition
Daniel Veillard98485322003-08-14 15:44:40 +0000102 */
103static void
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000104xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
105 const char *extra)
Daniel Veillard98485322003-08-14 15:44:40 +0000106{
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000107 if (ctxt != NULL)
108 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000109 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000110 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
111 extra, NULL, NULL, 0, 0,
112 "Memory allocation failed : %s\n", extra);
113}
Daniel Veillard98485322003-08-14 15:44:40 +0000114
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000115/**
116 * xmlXIncludeErr:
117 * @ctxt: the XInclude context
118 * @node: the context node
119 * @msg: the error message
William M. Brack72ee48d2003-12-30 08:30:19 +0000120 * @extra: extra information
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000121 *
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000122 * Handle an XInclude error
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000123 */
124static void
125xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
126 const char *msg, const xmlChar *extra)
127{
128 if (ctxt != NULL)
129 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000130 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000131 error, XML_ERR_ERROR, NULL, 0,
132 (const char *) extra, NULL, NULL, 0, 0,
133 msg, (const char *) extra);
Daniel Veillard98485322003-08-14 15:44:40 +0000134}
135
Daniel Veillardf54cd532004-02-25 11:52:31 +0000136#if 0
Owen Taylor3473f882001-02-23 17:55:21 +0000137/**
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000138 * xmlXIncludeWarn:
139 * @ctxt: the XInclude context
140 * @node: the context node
141 * @msg: the error message
William M. Brack72ee48d2003-12-30 08:30:19 +0000142 * @extra: extra information
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000143 *
144 * Emit an XInclude warning.
145 */
146static void
147xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
148 const char *msg, const xmlChar *extra)
149{
150 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
151 error, XML_ERR_WARNING, NULL, 0,
152 (const char *) extra, NULL, NULL, 0, 0,
153 msg, (const char *) extra);
154}
Daniel Veillardf54cd532004-02-25 11:52:31 +0000155#endif
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000156
157/**
158 * xmlXIncludeGetProp:
159 * @ctxt: the XInclude context
160 * @cur: the node
161 * @name: the attribute name
162 *
163 * Get an XInclude attribute
164 *
165 * Returns the value (to be freed) or NULL if not found
166 */
167static xmlChar *
168xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
169 const xmlChar *name) {
170 xmlChar *ret;
171
172 ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
173 if (ret != NULL)
174 return(ret);
175 if (ctxt->legacy != 0) {
176 ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
177 if (ret != NULL)
178 return(ret);
179 }
180 ret = xmlGetProp(cur, name);
181 return(ret);
182}
183/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000184 * xmlXIncludeFreeRef:
185 * @ref: the XInclude reference
186 *
187 * Free an XInclude reference
188 */
189static void
190xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
191 if (ref == NULL)
192 return;
193#ifdef DEBUG_XINCLUDE
194 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
195#endif
196 if (ref->doc != NULL) {
197#ifdef DEBUG_XINCLUDE
198 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
199#endif
200 xmlFreeDoc(ref->doc);
201 }
202 if (ref->URI != NULL)
203 xmlFree(ref->URI);
204 if (ref->fragment != NULL)
205 xmlFree(ref->fragment);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000206 if (ref->xptr != NULL)
207 xmlXPathFreeObject(ref->xptr);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000208 xmlFree(ref);
209}
210
211/**
212 * xmlXIncludeNewRef:
213 * @ctxt: the XInclude context
214 * @URI: the resource URI
215 *
216 * Creates a new reference within an XInclude context
217 *
218 * Returns the new set
219 */
220static xmlXIncludeRefPtr
221xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
222 xmlNodePtr ref) {
223 xmlXIncludeRefPtr ret;
224
225#ifdef DEBUG_XINCLUDE
226 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
227#endif
228 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000229 if (ret == NULL) {
230 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000231 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000232 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000233 memset(ret, 0, sizeof(xmlXIncludeRef));
234 if (URI == NULL)
235 ret->URI = NULL;
236 else
237 ret->URI = xmlStrdup(URI);
238 ret->fragment = NULL;
239 ret->ref = ref;
240 ret->doc = 0;
241 ret->count = 0;
242 ret->xml = 0;
243 ret->inc = NULL;
244 if (ctxt->incMax == 0) {
245 ctxt->incMax = 4;
246 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
247 sizeof(ctxt->incTab[0]));
248 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000249 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000250 xmlXIncludeFreeRef(ret);
251 return(NULL);
252 }
253 }
254 if (ctxt->incNr >= ctxt->incMax) {
255 ctxt->incMax *= 2;
256 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
257 ctxt->incMax * sizeof(ctxt->incTab[0]));
258 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000259 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000260 xmlXIncludeFreeRef(ret);
261 return(NULL);
262 }
263 }
264 ctxt->incTab[ctxt->incNr++] = ret;
265 return(ret);
266}
267
268/**
Owen Taylor3473f882001-02-23 17:55:21 +0000269 * xmlXIncludeNewContext:
270 * @doc: an XML Document
271 *
272 * Creates a new XInclude context
273 *
274 * Returns the new set
275 */
Daniel Veillard7899c5c2003-11-03 12:31:38 +0000276xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000277xmlXIncludeNewContext(xmlDocPtr doc) {
278 xmlXIncludeCtxtPtr ret;
279
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000280#ifdef DEBUG_XINCLUDE
281 xmlGenericError(xmlGenericErrorContext, "New context\n");
282#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000283 if (doc == NULL)
284 return(NULL);
285 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000286 if (ret == NULL) {
287 xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
288 "creating XInclude context");
Owen Taylor3473f882001-02-23 17:55:21 +0000289 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000290 }
Owen Taylor3473f882001-02-23 17:55:21 +0000291 memset(ret, 0, sizeof(xmlXIncludeCtxt));
292 ret->doc = doc;
293 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000294 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000295 ret->incMax = 0;
296 ret->incTab = NULL;
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000297 ret->nbErrors = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000298 return(ret);
299}
300
301/**
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000302 * xmlXIncludeURLPush:
303 * @ctxt: the parser context
304 * @value: the url
305 *
306 * Pushes a new url on top of the url stack
307 *
308 * Returns -1 in case of error, the index in the stack otherwise
309 */
310static int
311xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
312 const xmlChar *value)
313{
314 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000315 xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
316 "detected a recursion in %s\n", value);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000317 return(-1);
318 }
319 if (ctxt->urlTab == NULL) {
320 ctxt->urlMax = 4;
321 ctxt->urlNr = 0;
322 ctxt->urlTab = (xmlChar * *) xmlMalloc(
323 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
324 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000325 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000326 return (-1);
327 }
328 }
329 if (ctxt->urlNr >= ctxt->urlMax) {
330 ctxt->urlMax *= 2;
331 ctxt->urlTab =
332 (xmlChar * *) xmlRealloc(ctxt->urlTab,
333 ctxt->urlMax *
334 sizeof(ctxt->urlTab[0]));
335 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000336 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000337 return (-1);
338 }
339 }
340 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
341 return (ctxt->urlNr++);
342}
343
344/**
345 * xmlXIncludeURLPop:
346 * @ctxt: the parser context
347 *
William M. Brack72ee48d2003-12-30 08:30:19 +0000348 * Pops the top URL from the URL stack
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000349 */
350static void
351xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
352{
353 xmlChar * ret;
354
355 if (ctxt->urlNr <= 0)
356 return;
357 ctxt->urlNr--;
358 if (ctxt->urlNr > 0)
359 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
360 else
361 ctxt->url = NULL;
362 ret = ctxt->urlTab[ctxt->urlNr];
363 ctxt->urlTab[ctxt->urlNr] = 0;
364 if (ret != NULL)
365 xmlFree(ret);
366}
367
368/**
Owen Taylor3473f882001-02-23 17:55:21 +0000369 * xmlXIncludeFreeContext:
370 * @ctxt: the XInclude context
371 *
372 * Free an XInclude context
373 */
Daniel Veillard7899c5c2003-11-03 12:31:38 +0000374void
Owen Taylor3473f882001-02-23 17:55:21 +0000375xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
376 int i;
377
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000378#ifdef DEBUG_XINCLUDE
379 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
380#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000381 if (ctxt == NULL)
382 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000383 while (ctxt->urlNr > 0)
384 xmlXIncludeURLPop(ctxt);
385 if (ctxt->urlTab != NULL)
386 xmlFree(ctxt->urlTab);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000387 for (i = 0;i < ctxt->incNr;i++) {
388 if (ctxt->incTab[i] != NULL)
389 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000390 }
391 for (i = 0;i < ctxt->txtNr;i++) {
392 if (ctxt->txturlTab[i] != NULL)
393 xmlFree(ctxt->txturlTab[i]);
394 }
395 if (ctxt->incTab != NULL)
396 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000397 if (ctxt->txtTab != NULL)
398 xmlFree(ctxt->txtTab);
399 if (ctxt->txturlTab != NULL)
400 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000401 xmlFree(ctxt);
402}
403
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000404/**
Daniel Veillard98485322003-08-14 15:44:40 +0000405 * xmlXIncludeParseFile:
406 * @ctxt: the XInclude context
407 * @URL: the URL or file path
408 *
William M. Brack72ee48d2003-12-30 08:30:19 +0000409 * parse a document for XInclude
Daniel Veillard98485322003-08-14 15:44:40 +0000410 */
411static xmlDocPtr
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000412xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000413 xmlDocPtr ret;
414 xmlParserCtxtPtr pctxt;
415 char *directory = NULL;
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000416 xmlParserInputPtr inputStream;
Daniel Veillard98485322003-08-14 15:44:40 +0000417
418 xmlInitParser();
419
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000420 pctxt = xmlNewParserCtxt();
Daniel Veillard98485322003-08-14 15:44:40 +0000421 if (pctxt == NULL) {
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000422 xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context");
Daniel Veillard98485322003-08-14 15:44:40 +0000423 return(NULL);
424 }
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000425 /*
William M. Brack72ee48d2003-12-30 08:30:19 +0000426 * try to ensure that new documents included are actually
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000427 * built with the same dictionary as the including document.
428 */
429 if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL) &&
430 (pctxt->dict != NULL)) {
431 xmlDictFree(pctxt->dict);
432 pctxt->dict = ctxt->doc->dict;
433 xmlDictReference(pctxt->dict);
434 }
435
436 xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
437
438 inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
439 if (inputStream == NULL) {
440 xmlFreeParserCtxt(pctxt);
441 return(NULL);
442 }
443
444 inputPush(pctxt, inputStream);
Daniel Veillard98485322003-08-14 15:44:40 +0000445
446 if ((pctxt->directory == NULL) && (directory == NULL))
447 directory = xmlParserGetDirectory(URL);
448 if ((pctxt->directory == NULL) && (directory != NULL))
449 pctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
450
451 pctxt->loadsubset = XML_DETECT_IDS;
452
453 xmlParseDocument(pctxt);
454
William M. Brack1ff42132003-12-31 14:05:15 +0000455 if (pctxt->wellFormed) {
Daniel Veillard98485322003-08-14 15:44:40 +0000456 ret = pctxt->myDoc;
William M. Brack1ff42132003-12-31 14:05:15 +0000457 }
Daniel Veillard98485322003-08-14 15:44:40 +0000458 else {
459 ret = NULL;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000460 if (pctxt->myDoc != NULL)
Daniel Veillard4773df22004-01-23 13:15:13 +0000461 xmlFreeDoc(pctxt->myDoc);
Daniel Veillard98485322003-08-14 15:44:40 +0000462 pctxt->myDoc = NULL;
463 }
464 xmlFreeParserCtxt(pctxt);
465
466 return(ret);
467}
468
469/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000470 * xmlXIncludeAddNode:
471 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000472 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000473 *
474 * Add a new node to process to an XInclude context
475 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000476static int
477xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
478 xmlXIncludeRefPtr ref;
479 xmlURIPtr uri;
480 xmlChar *URL;
481 xmlChar *fragment = NULL;
482 xmlChar *href;
483 xmlChar *parse;
484 xmlChar *base;
485 xmlChar *URI;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000486 int xml = 1, i; /* default Issue 64 */
487 int local = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000488
489
490 if (ctxt == NULL)
491 return(-1);
492 if (cur == NULL)
493 return(-1);
494
495#ifdef DEBUG_XINCLUDE
496 xmlGenericError(xmlGenericErrorContext, "Add node\n");
497#endif
498 /*
499 * read the attributes
500 */
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000501 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000502 if (href == NULL) {
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000503 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
504 if (href == NULL)
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000505 return(-1);
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000506 local = 1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000507 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000508 if (href[0] == '#')
509 local = 1;
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000510 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000511 if (parse != NULL) {
512 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
513 xml = 1;
514 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
515 xml = 0;
516 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000517 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
518 "invalid value %s for 'parse'\n", parse);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000519 if (href != NULL)
520 xmlFree(href);
521 if (parse != NULL)
522 xmlFree(parse);
523 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000524 }
525 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000526
527 /*
528 * compute the URI
529 */
530 base = xmlNodeGetBase(ctxt->doc, cur);
531 if (base == NULL) {
532 URI = xmlBuildURI(href, ctxt->doc->URL);
533 } else {
534 URI = xmlBuildURI(href, base);
535 }
536 if (URI == NULL) {
537 xmlChar *escbase;
538 xmlChar *eschref;
539 /*
540 * Some escaping may be needed
541 */
542 escbase = xmlURIEscape(base);
543 eschref = xmlURIEscape(href);
544 URI = xmlBuildURI(eschref, escbase);
545 if (escbase != NULL)
546 xmlFree(escbase);
547 if (eschref != NULL)
548 xmlFree(eschref);
549 }
550 if (parse != NULL)
551 xmlFree(parse);
552 if (href != NULL)
553 xmlFree(href);
554 if (base != NULL)
555 xmlFree(base);
556 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000557 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
558 "failed build URL\n", NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000559 return(-1);
560 }
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000561 fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000562
563 /*
564 * Check the URL and remove any fragment identifier
565 */
566 uri = xmlParseURI((const char *)URI);
567 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000568 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
569 "invalid value URI %s\n", URI);
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000570 if (fragment != NULL)
571 xmlFree(fragment);
572 xmlFree(URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000573 return(-1);
574 }
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000575
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000576 if (uri->fragment != NULL) {
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000577 if (ctxt->legacy != 0) {
578 if (fragment == NULL) {
579 fragment = (xmlChar *) uri->fragment;
580 } else {
581 xmlFree(uri->fragment);
582 }
583 } else {
584 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID,
585 "Invalid fragment identifier in URI %s use the xpointer attribute\n",
586 URI);
587 if (fragment != NULL)
588 xmlFree(fragment);
589 xmlFreeURI(uri);
590 xmlFree(URI);
591 return(-1);
592 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000593 uri->fragment = NULL;
594 }
595 URL = xmlSaveUri(uri);
596 xmlFreeURI(uri);
597 xmlFree(URI);
598 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000599 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
600 "invalid value URI %s\n", URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000601 if (fragment != NULL)
602 xmlFree(fragment);
603 return(-1);
604 }
605
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000606 /*
607 * Check the URL against the stack for recursions
608 */
609 if (!local) {
610 for (i = 0;i < ctxt->urlNr;i++) {
611 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000612 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
613 "detected a recursion in %s\n", URL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000614 return(-1);
615 }
616 }
617 }
618
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000619 ref = xmlXIncludeNewRef(ctxt, URL, cur);
620 if (ref == NULL) {
621 return(-1);
622 }
623 ref->fragment = fragment;
624 ref->doc = NULL;
625 ref->xml = xml;
626 ref->count = 1;
627 xmlFree(URL);
628 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000629}
630
631/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000632 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000633 * @ctxt: the XInclude context
634 * @doc: the new document
635 * @url: the associated URL
636 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000637 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000638 */
639static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000640xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000641 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000642 xmlXIncludeCtxtPtr newctxt;
643 int i;
644
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000645 /*
646 * Avoid recursion in already substitued resources
647 for (i = 0;i < ctxt->urlNr;i++) {
648 if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
649 return;
650 }
651 */
652
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000653#ifdef DEBUG_XINCLUDE
654 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
655#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000656 /*
657 * Handle recursion here.
658 */
659
660 newctxt = xmlXIncludeNewContext(doc);
661 if (newctxt != NULL) {
662 /*
663 * Copy the existing document set
664 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000665 newctxt->incMax = ctxt->incMax;
666 newctxt->incNr = ctxt->incNr;
667 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
668 sizeof(newctxt->incTab[0]));
669 if (newctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000670 xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000671 xmlFree(newctxt);
672 return;
673 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000674 /*
675 * copy the urlTab
676 */
677 newctxt->urlMax = ctxt->urlMax;
678 newctxt->urlNr = ctxt->urlNr;
679 newctxt->urlTab = ctxt->urlTab;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000680
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000681 /*
William M. Brackf7789b12004-06-07 08:57:27 +0000682 * Inherit the existing base
683 */
684 newctxt->base = ctxt->base;
685
686 /*
William M. Brack72ee48d2003-12-30 08:30:19 +0000687 * Inherit the documents already in use by other includes
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000688 */
689 newctxt->incBase = ctxt->incNr;
690 for (i = 0;i < ctxt->incNr;i++) {
691 newctxt->incTab[i] = ctxt->incTab[i];
692 newctxt->incTab[i]->count++; /* prevent the recursion from
693 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000694 }
William M. Bracka11e4832004-03-07 11:03:43 +0000695 /*
696 * The new context should also inherit the Parse Flags
697 * (bug 132597)
698 */
699 newctxt->parseFlags = ctxt->parseFlags;
Daniel Veillard8edf1c52003-07-22 20:52:14 +0000700 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000701 for (i = 0;i < ctxt->incNr;i++) {
702 newctxt->incTab[i]->count--;
703 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000704 }
Daniel Veillardd9b72832003-03-27 14:24:00 +0000705
706 /* urlTab may have been reallocated */
707 ctxt->urlTab = newctxt->urlTab;
708 ctxt->urlMax = newctxt->urlMax;
709
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000710 newctxt->urlMax = 0;
711 newctxt->urlNr = 0;
712 newctxt->urlTab = NULL;
713
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000714 xmlXIncludeFreeContext(newctxt);
715 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000716#ifdef DEBUG_XINCLUDE
717 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
718#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000719}
720
721/**
722 * xmlXIncludeAddTxt:
723 * @ctxt: the XInclude context
724 * @txt: the new text node
725 * @url: the associated URL
726 *
727 * Add a new txtument to the list
728 */
729static void
730xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000731#ifdef DEBUG_XINCLUDE
732 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
733#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000734 if (ctxt->txtMax == 0) {
735 ctxt->txtMax = 4;
736 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
737 sizeof(ctxt->txtTab[0]));
738 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000739 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000740 return;
741 }
742 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
743 sizeof(ctxt->txturlTab[0]));
744 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000745 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000746 return;
747 }
748 }
749 if (ctxt->txtNr >= ctxt->txtMax) {
750 ctxt->txtMax *= 2;
751 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
752 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
753 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000754 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000755 return;
756 }
757 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000758 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000759 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000760 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000761 return;
762 }
763 }
764 ctxt->txtTab[ctxt->txtNr] = txt;
765 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
766 ctxt->txtNr++;
767}
768
Owen Taylor3473f882001-02-23 17:55:21 +0000769/************************************************************************
770 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000771 * Node copy with specific semantic *
772 * *
773 ************************************************************************/
774
775/**
776 * xmlXIncludeCopyNode:
777 * @ctxt: the XInclude context
778 * @target: the document target
779 * @source: the document source
780 * @elem: the element
781 *
782 * Make a copy of the node while preserving the XInclude semantic
783 * of the Infoset copy
784 */
785static xmlNodePtr
786xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
787 xmlDocPtr source, xmlNodePtr elem) {
788 xmlNodePtr result = NULL;
789
790 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
791 (elem == NULL))
792 return(NULL);
793 if (elem->type == XML_DTD_NODE)
794 return(NULL);
795 result = xmlDocCopyNode(elem, target, 1);
796 return(result);
797}
798
799/**
800 * xmlXIncludeCopyNodeList:
801 * @ctxt: the XInclude context
802 * @target: the document target
803 * @source: the document source
804 * @elem: the element list
805 *
806 * Make a copy of the node list while preserving the XInclude semantic
807 * of the Infoset copy
808 */
809static xmlNodePtr
810xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
811 xmlDocPtr source, xmlNodePtr elem) {
812 xmlNodePtr cur, res, result = NULL, last = NULL;
813
814 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
815 (elem == NULL))
816 return(NULL);
817 cur = elem;
818 while (cur != NULL) {
819 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
820 if (res != NULL) {
821 if (result == NULL) {
822 result = last = res;
823 } else {
824 last->next = res;
825 res->prev = last;
826 last = res;
827 }
828 }
829 cur = cur->next;
830 }
831 return(result);
832}
833
834/**
William M. Brack72ee48d2003-12-30 08:30:19 +0000835 * xmlXIncludeGetNthChild:
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000836 * @cur: the node
837 * @no: the child number
838 *
William M. Brack72ee48d2003-12-30 08:30:19 +0000839 * Returns the @n'th element child of @cur or NULL
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000840 */
841static xmlNodePtr
842xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
843 int i;
844 if (cur == NULL)
845 return(cur);
846 cur = cur->children;
847 for (i = 0;i <= no;cur = cur->next) {
848 if (cur == NULL)
849 return(cur);
850 if ((cur->type == XML_ELEMENT_NODE) ||
851 (cur->type == XML_DOCUMENT_NODE) ||
852 (cur->type == XML_HTML_DOCUMENT_NODE)) {
853 i++;
854 if (i == no)
855 break;
856 }
857 }
858 return(cur);
859}
860
William M. Brackf7eb7942003-12-31 07:59:17 +0000861xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000862/**
863 * xmlXIncludeCopyRange:
864 * @ctxt: the XInclude context
865 * @target: the document target
866 * @source: the document source
867 * @obj: the XPointer result from the evaluation.
868 *
869 * Build a node list tree copy of the XPointer result.
870 *
871 * Returns an xmlNodePtr list or NULL.
William M. Brack72ee48d2003-12-30 08:30:19 +0000872 * The caller has to free the node tree.
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000873 */
874static xmlNodePtr
875xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
876 xmlDocPtr source, xmlXPathObjectPtr range) {
877 /* pointers to generated nodes */
William M. Brackf7eb7942003-12-31 07:59:17 +0000878 xmlNodePtr list = NULL, last = NULL, listParent = NULL;
879 xmlNodePtr tmp, tmp2;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000880 /* pointers to traversal nodes */
881 xmlNodePtr start, cur, end;
882 int index1, index2;
William M. Brack6bdacd72004-02-07 08:53:23 +0000883 int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000884
885 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
886 (range == NULL))
887 return(NULL);
888 if (range->type != XPATH_RANGE)
889 return(NULL);
890 start = (xmlNodePtr) range->user;
891
892 if (start == NULL)
893 return(NULL);
894 end = range->user2;
895 if (end == NULL)
896 return(xmlDocCopyNode(start, target, 1));
897
898 cur = start;
899 index1 = range->index;
900 index2 = range->index2;
William M. Brackf7eb7942003-12-31 07:59:17 +0000901 /*
902 * level is depth of the current node under consideration
903 * list is the pointer to the root of the output tree
904 * listParent is a pointer to the parent of output tree (within
905 the included file) in case we need to add another level
906 * last is a pointer to the last node added to the output tree
907 * lastLevel is the depth of last (relative to the root)
908 */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000909 while (cur != NULL) {
William M. Brackf7eb7942003-12-31 07:59:17 +0000910 /*
911 * Check if our output tree needs a parent
912 */
913 if (level < 0) {
914 while (level < 0) {
William M. Brack57e9e912004-03-09 16:19:02 +0000915 /* copy must include namespaces and properties */
916 tmp2 = xmlDocCopyNode(listParent, target, 2);
William M. Brackf7eb7942003-12-31 07:59:17 +0000917 xmlAddChild(tmp2, list);
918 list = tmp2;
919 listParent = listParent->parent;
920 level++;
921 }
922 last = list;
923 lastLevel = 0;
924 }
925 /*
926 * Check whether we need to change our insertion point
927 */
928 while (level < lastLevel) {
929 last = last->parent;
930 lastLevel --;
931 }
William M. Brack72ee48d2003-12-30 08:30:19 +0000932 if (cur == end) { /* Are we at the end of the range? */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000933 if (cur->type == XML_TEXT_NODE) {
934 const xmlChar *content = cur->content;
935 int len;
936
937 if (content == NULL) {
938 tmp = xmlNewTextLen(NULL, 0);
939 } else {
940 len = index2;
941 if ((cur == start) && (index1 > 1)) {
942 content += (index1 - 1);
943 len -= (index1 - 1);
944 index1 = 0;
945 } else {
946 len = index2;
947 }
948 tmp = xmlNewTextLen(content, len);
949 }
950 /* single sub text node selection */
951 if (list == NULL)
952 return(tmp);
953 /* prune and return full set */
William M. Brackf7eb7942003-12-31 07:59:17 +0000954 if (level == lastLevel)
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000955 xmlAddNextSibling(last, tmp);
956 else
William M. Brackf7eb7942003-12-31 07:59:17 +0000957 xmlAddChild(last, tmp);
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000958 return(list);
William M. Brack72ee48d2003-12-30 08:30:19 +0000959 } else { /* ending node not a text node */
William M. Brack6bdacd72004-02-07 08:53:23 +0000960 endLevel = level; /* remember the level of the end node */
961 endFlag = 1;
William M. Brack57e9e912004-03-09 16:19:02 +0000962 /* last node - need to take care of properties + namespaces */
963 tmp = xmlDocCopyNode(cur, target, 2);
William M. Brackf7eb7942003-12-31 07:59:17 +0000964 if (list == NULL) {
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000965 list = tmp;
William M. Brackf7eb7942003-12-31 07:59:17 +0000966 listParent = cur->parent;
967 } else {
968 if (level == lastLevel)
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000969 xmlAddNextSibling(last, tmp);
William M. Brackf7eb7942003-12-31 07:59:17 +0000970 else {
971 xmlAddChild(last, tmp);
972 lastLevel = level;
973 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000974 }
William M. Brackf7eb7942003-12-31 07:59:17 +0000975 last = tmp;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000976
977 if (index2 > 1) {
978 end = xmlXIncludeGetNthChild(cur, index2 - 1);
979 index2 = 0;
980 }
981 if ((cur == start) && (index1 > 1)) {
982 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
983 index1 = 0;
William M. Brack6bdacd72004-02-07 08:53:23 +0000984 } else {
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000985 cur = cur->children;
986 }
William M. Brack6bdacd72004-02-07 08:53:23 +0000987 level++; /* increment level to show change */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000988 /*
989 * Now gather the remaining nodes from cur to end
990 */
William M. Brack6bdacd72004-02-07 08:53:23 +0000991 continue; /* while */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000992 }
William M. Brackf7eb7942003-12-31 07:59:17 +0000993 } else if (cur == start) { /* Not at the end, are we at start? */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000994 if ((cur->type == XML_TEXT_NODE) ||
995 (cur->type == XML_CDATA_SECTION_NODE)) {
996 const xmlChar *content = cur->content;
997
998 if (content == NULL) {
999 tmp = xmlNewTextLen(NULL, 0);
1000 } else {
1001 if (index1 > 1) {
1002 content += (index1 - 1);
William M. Brack72ee48d2003-12-30 08:30:19 +00001003 index1 = 0;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001004 }
1005 tmp = xmlNewText(content);
1006 }
1007 last = list = tmp;
William M. Brackf7eb7942003-12-31 07:59:17 +00001008 listParent = cur->parent;
William M. Brack72ee48d2003-12-30 08:30:19 +00001009 } else { /* Not text node */
William M. Brack57e9e912004-03-09 16:19:02 +00001010 /*
1011 * start of the range - need to take care of
1012 * properties and namespaces
1013 */
1014 tmp = xmlDocCopyNode(cur, target, 2);
William M. Brackf7eb7942003-12-31 07:59:17 +00001015 list = last = tmp;
1016 listParent = cur->parent;
William M. Brack72ee48d2003-12-30 08:30:19 +00001017 if (index1 > 1) { /* Do we need to position? */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001018 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
William M. Brackf7eb7942003-12-31 07:59:17 +00001019 level = lastLevel = 1;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001020 index1 = 0;
1021 /*
1022 * Now gather the remaining nodes from cur to end
1023 */
1024 continue; /* while */
1025 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001026 }
1027 } else {
1028 tmp = NULL;
1029 switch (cur->type) {
1030 case XML_DTD_NODE:
1031 case XML_ELEMENT_DECL:
1032 case XML_ATTRIBUTE_DECL:
1033 case XML_ENTITY_NODE:
1034 /* Do not copy DTD informations */
1035 break;
1036 case XML_ENTITY_DECL:
1037 /* handle crossing entities -> stack needed */
1038 break;
1039 case XML_XINCLUDE_START:
1040 case XML_XINCLUDE_END:
1041 /* don't consider it part of the tree content */
1042 break;
1043 case XML_ATTRIBUTE_NODE:
1044 /* Humm, should not happen ! */
1045 break;
1046 default:
William M. Brack57e9e912004-03-09 16:19:02 +00001047 /*
1048 * Middle of the range - need to take care of
1049 * properties and namespaces
1050 */
1051 tmp = xmlDocCopyNode(cur, target, 2);
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001052 break;
1053 }
1054 if (tmp != NULL) {
William M. Brackf7eb7942003-12-31 07:59:17 +00001055 if (level == lastLevel)
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001056 xmlAddNextSibling(last, tmp);
1057 else {
William M. Brackf7eb7942003-12-31 07:59:17 +00001058 xmlAddChild(last, tmp);
1059 lastLevel = level;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001060 }
William M. Brackf7eb7942003-12-31 07:59:17 +00001061 last = tmp;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001062 }
1063 }
1064 /*
1065 * Skip to next node in document order
1066 */
William M. Brackf7eb7942003-12-31 07:59:17 +00001067 cur = xmlXPtrAdvanceNode(cur, &level);
William M. Brack6bdacd72004-02-07 08:53:23 +00001068 if (endFlag && (level >= endLevel))
1069 break;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001070 }
1071 return(list);
1072}
1073
1074/**
1075 * xmlXIncludeBuildNodeList:
1076 * @ctxt: the XInclude context
1077 * @target: the document target
1078 * @source: the document source
1079 * @obj: the XPointer result from the evaluation.
1080 *
1081 * Build a node list tree copy of the XPointer result.
1082 * This will drop Attributes and Namespace declarations.
1083 *
1084 * Returns an xmlNodePtr list or NULL.
1085 * the caller has to free the node tree.
1086 */
1087static xmlNodePtr
1088xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
1089 xmlDocPtr source, xmlXPathObjectPtr obj) {
1090 xmlNodePtr list = NULL, last = NULL;
1091 int i;
1092
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001093 if (source == NULL)
1094 source = ctxt->doc;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001095 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
1096 (obj == NULL))
1097 return(NULL);
1098 switch (obj->type) {
1099 case XPATH_NODESET: {
1100 xmlNodeSetPtr set = obj->nodesetval;
1101 if (set == NULL)
1102 return(NULL);
1103 for (i = 0;i < set->nodeNr;i++) {
1104 if (set->nodeTab[i] == NULL)
1105 continue;
1106 switch (set->nodeTab[i]->type) {
1107 case XML_TEXT_NODE:
1108 case XML_CDATA_SECTION_NODE:
1109 case XML_ELEMENT_NODE:
1110 case XML_ENTITY_REF_NODE:
1111 case XML_ENTITY_NODE:
1112 case XML_PI_NODE:
1113 case XML_COMMENT_NODE:
1114 case XML_DOCUMENT_NODE:
1115 case XML_HTML_DOCUMENT_NODE:
1116#ifdef LIBXML_DOCB_ENABLED
1117 case XML_DOCB_DOCUMENT_NODE:
1118#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001119 case XML_XINCLUDE_END:
1120 break;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001121 case XML_XINCLUDE_START: {
1122 xmlNodePtr tmp, cur = set->nodeTab[i];
1123
1124 cur = cur->next;
1125 while (cur != NULL) {
1126 switch(cur->type) {
1127 case XML_TEXT_NODE:
1128 case XML_CDATA_SECTION_NODE:
1129 case XML_ELEMENT_NODE:
1130 case XML_ENTITY_REF_NODE:
1131 case XML_ENTITY_NODE:
1132 case XML_PI_NODE:
1133 case XML_COMMENT_NODE:
1134 tmp = xmlXIncludeCopyNode(ctxt, target,
1135 source, cur);
1136 if (last == NULL) {
1137 list = last = tmp;
1138 } else {
1139 xmlAddNextSibling(last, tmp);
1140 last = tmp;
1141 }
1142 cur = cur->next;
1143 continue;
1144 default:
1145 break;
1146 }
1147 break;
1148 }
1149 continue;
1150 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001151 case XML_ATTRIBUTE_NODE:
1152 case XML_NAMESPACE_DECL:
1153 case XML_DOCUMENT_TYPE_NODE:
1154 case XML_DOCUMENT_FRAG_NODE:
1155 case XML_NOTATION_NODE:
1156 case XML_DTD_NODE:
1157 case XML_ELEMENT_DECL:
1158 case XML_ATTRIBUTE_DECL:
1159 case XML_ENTITY_DECL:
1160 continue; /* for */
1161 }
1162 if (last == NULL)
1163 list = last = xmlXIncludeCopyNode(ctxt, target, source,
1164 set->nodeTab[i]);
1165 else {
1166 xmlAddNextSibling(last,
1167 xmlXIncludeCopyNode(ctxt, target, source,
1168 set->nodeTab[i]));
1169 if (last->next != NULL)
1170 last = last->next;
1171 }
1172 }
1173 break;
1174 }
1175 case XPATH_LOCATIONSET: {
1176 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1177 if (set == NULL)
1178 return(NULL);
1179 for (i = 0;i < set->locNr;i++) {
1180 if (last == NULL)
1181 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
1182 set->locTab[i]);
1183 else
1184 xmlAddNextSibling(last,
1185 xmlXIncludeCopyXPointer(ctxt, target, source,
1186 set->locTab[i]));
1187 if (last != NULL) {
1188 while (last->next != NULL)
1189 last = last->next;
1190 }
1191 }
1192 break;
1193 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001194#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001195 case XPATH_RANGE:
1196 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001197#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001198 case XPATH_POINT:
1199 /* points are ignored in XInclude */
1200 break;
1201 default:
1202 break;
1203 }
1204 return(list);
1205}
1206/************************************************************************
1207 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001208 * XInclude I/O handling *
1209 * *
1210 ************************************************************************/
1211
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001212typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1213typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1214struct _xmlXIncludeMergeData {
1215 xmlDocPtr doc;
1216 xmlXIncludeCtxtPtr ctxt;
1217};
1218
Owen Taylor3473f882001-02-23 17:55:21 +00001219/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001220 * xmlXIncludeMergeOneEntity:
1221 * @ent: the entity
1222 * @doc: the including doc
1223 * @nr: the entity name
1224 *
1225 * Inplements the merge of one entity
1226 */
1227static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001228xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001229 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001230 xmlEntityPtr ret, prev;
1231 xmlDocPtr doc;
1232 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001233
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001234 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001235 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001236 ctxt = data->ctxt;
1237 doc = data->doc;
1238 if ((ctxt == NULL) || (doc == NULL))
1239 return;
1240 switch (ent->etype) {
1241 case XML_INTERNAL_PARAMETER_ENTITY:
1242 case XML_EXTERNAL_PARAMETER_ENTITY:
1243 case XML_INTERNAL_PREDEFINED_ENTITY:
1244 return;
1245 case XML_INTERNAL_GENERAL_ENTITY:
1246 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1247 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1248 break;
1249 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001250 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1251 ent->SystemID, ent->content);
1252 if (ret != NULL) {
1253 if (ent->URI != NULL)
1254 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001255 } else {
1256 prev = xmlGetDocEntity(doc, ent->name);
1257 if (prev != NULL) {
1258 if (ent->etype != prev->etype)
1259 goto error;
1260
1261 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1262 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1263 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001264 } else if ((ent->ExternalID != NULL) &&
1265 (prev->ExternalID != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001266 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1267 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001268 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1269 if (!xmlStrEqual(ent->content, prev->content))
1270 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001271 } else {
1272 goto error;
1273 }
1274
1275 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001276 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001277 return;
1278error:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001279 switch (ent->etype) {
1280 case XML_INTERNAL_PARAMETER_ENTITY:
1281 case XML_EXTERNAL_PARAMETER_ENTITY:
1282 case XML_INTERNAL_PREDEFINED_ENTITY:
1283 case XML_INTERNAL_GENERAL_ENTITY:
1284 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1285 return;
1286 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1287 break;
1288 }
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001289 xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
1290 "mismatch in redefinition of entity %s\n",
1291 ent->name);
Daniel Veillard4287c572003-02-04 22:48:53 +00001292}
1293
1294/**
1295 * xmlXIncludeMergeEntities:
1296 * @ctxt: an XInclude context
1297 * @doc: the including doc
1298 * @from: the included doc
1299 *
1300 * Inplements the entity merge
1301 *
1302 * Returns 0 if merge succeeded, -1 if some processing failed
1303 */
1304static int
1305xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1306 xmlDocPtr from) {
1307 xmlNodePtr cur;
1308 xmlDtdPtr target, source;
1309
1310 if (ctxt == NULL)
1311 return(-1);
1312
1313 if ((from == NULL) || (from->intSubset == NULL))
1314 return(0);
1315
1316 target = doc->intSubset;
1317 if (target == NULL) {
1318 cur = xmlDocGetRootElement(doc);
1319 if (cur == NULL)
1320 return(-1);
1321 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1322 if (target == NULL)
1323 return(-1);
1324 }
1325
1326 source = from->intSubset;
1327 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001328 xmlXIncludeMergeData data;
1329
1330 data.ctxt = ctxt;
1331 data.doc = doc;
1332
Daniel Veillard4287c572003-02-04 22:48:53 +00001333 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001334 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001335 }
1336 source = from->extSubset;
1337 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001338 xmlXIncludeMergeData data;
1339
1340 data.ctxt = ctxt;
1341 data.doc = doc;
1342
Daniel Veillard4287c572003-02-04 22:48:53 +00001343 /*
1344 * don't duplicate existing stuff when external subsets are the same
1345 */
1346 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1347 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1348 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001349 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001350 }
1351 }
1352 return(0);
1353}
1354
1355/**
Owen Taylor3473f882001-02-23 17:55:21 +00001356 * xmlXIncludeLoadDoc:
1357 * @ctxt: the XInclude context
1358 * @url: the associated URL
1359 * @nr: the xinclude node number
1360 *
1361 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001362 *
1363 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001364 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001365static int
Owen Taylor3473f882001-02-23 17:55:21 +00001366xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1367 xmlDocPtr doc;
1368 xmlURIPtr uri;
1369 xmlChar *URL;
1370 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001371 int i = 0;
William M. Brack4d59e222004-03-08 14:42:31 +00001372#ifdef LIBXML_XPTR_ENABLED
1373 int saveFlags;
1374#endif
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001375
1376#ifdef DEBUG_XINCLUDE
1377 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1378#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001379 /*
1380 * Check the URL and remove any fragment identifier
1381 */
1382 uri = xmlParseURI((const char *)url);
1383 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001384 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1385 XML_XINCLUDE_HREF_URI,
1386 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001387 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001388 }
1389 if (uri->fragment != NULL) {
1390 fragment = (xmlChar *) uri->fragment;
1391 uri->fragment = NULL;
1392 }
Daniel Veillardb98d0822003-12-24 11:06:25 +00001393 if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
1394 (ctxt->incTab[nr]->fragment != NULL)) {
1395 if (fragment != NULL) xmlFree(fragment);
1396 fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
1397 }
Owen Taylor3473f882001-02-23 17:55:21 +00001398 URL = xmlSaveUri(uri);
1399 xmlFreeURI(uri);
1400 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001401 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1402 XML_XINCLUDE_HREF_URI,
1403 "invalid value URI %s\n", url);
Owen Taylor3473f882001-02-23 17:55:21 +00001404 if (fragment != NULL)
1405 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001406 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001407 }
1408
1409 /*
1410 * Handling of references to the local document are done
1411 * directly through ctxt->doc.
1412 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001413 if ((URL[0] == 0) || (URL[0] == '#') ||
1414 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001415 doc = NULL;
1416 goto loaded;
1417 }
1418
1419 /*
1420 * Prevent reloading twice the document.
1421 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001422 for (i = 0; i < ctxt->incNr; i++) {
1423 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1424 (ctxt->incTab[i]->doc != NULL)) {
1425 doc = ctxt->incTab[i]->doc;
1426#ifdef DEBUG_XINCLUDE
1427 printf("Already loaded %s\n", URL);
1428#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001429 goto loaded;
1430 }
1431 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001432
Owen Taylor3473f882001-02-23 17:55:21 +00001433 /*
1434 * Load it.
1435 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001436#ifdef DEBUG_XINCLUDE
1437 printf("loading %s\n", URL);
1438#endif
William M. Brack4d59e222004-03-08 14:42:31 +00001439#ifdef LIBXML_XPTR_ENABLED
1440 /*
1441 * If this is an XPointer evaluation, we want to assure that
1442 * all entities have been resolved prior to processing the
1443 * referenced document
1444 */
1445 saveFlags = ctxt->parseFlags;
1446 if (fragment != NULL) { /* if this is an XPointer eval */
1447 ctxt->parseFlags |= XML_PARSE_NOENT;
1448 }
1449#endif
1450
Daniel Veillard98485322003-08-14 15:44:40 +00001451 doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
William M. Brack4d59e222004-03-08 14:42:31 +00001452#ifdef LIBXML_XPTR_ENABLED
1453 ctxt->parseFlags = saveFlags;
1454#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001455 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001456 xmlFree(URL);
1457 if (fragment != NULL)
1458 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001459 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001460 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001461 ctxt->incTab[nr]->doc = doc;
William M. Brackb85c9202004-07-26 00:20:13 +00001462 /*
1463 * It's possible that the requested URL has been mapped to a
1464 * completely different location (e.g. through a catalog entry).
1465 * To check for this, we compare the URL with that of the doc
1466 * and change it if they disagree (bug 146988).
1467 */
1468 if (!xmlStrEqual(URL, doc->URL)) {
1469 xmlFree(URL);
1470 URL = xmlStrdup(doc->URL);
1471 }
Daniel Veillard98485322003-08-14 15:44:40 +00001472 for (i = nr + 1; i < ctxt->incNr; i++) {
1473 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1474 ctxt->incTab[nr]->count++;
1475#ifdef DEBUG_XINCLUDE
1476 printf("Increasing %s count since reused\n", URL);
1477#endif
1478 break;
1479 }
1480 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001481
1482 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001483 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001484 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001485 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001486
1487 /*
1488 * We don't need the DTD anymore, free up space
1489 if (doc->intSubset != NULL) {
1490 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1491 xmlFreeNode((xmlNodePtr) doc->intSubset);
1492 doc->intSubset = NULL;
1493 }
1494 if (doc->extSubset != NULL) {
1495 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1496 xmlFreeNode((xmlNodePtr) doc->extSubset);
1497 doc->extSubset = NULL;
1498 }
1499 */
1500 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001501
1502loaded:
1503 if (fragment == NULL) {
1504 /*
1505 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001506 */
1507 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001508 {
1509 /* Hopefully a DTD declaration won't be copied from
1510 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001511 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001512 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001513 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001514 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001515 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001516 }
1517#ifdef LIBXML_XPTR_ENABLED
1518 else {
Owen Taylor3473f882001-02-23 17:55:21 +00001519 /*
1520 * Computes the XPointer expression and make a copy used
1521 * as the replacement copy.
1522 */
1523 xmlXPathObjectPtr xptr;
1524 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001525 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001526
1527 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001528 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1529 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001530 } else {
1531 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1532 }
1533 if (xptrctxt == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001534 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1535 XML_XINCLUDE_XPTR_FAILED,
Daniel Veillarda152c4d2003-11-19 16:24:26 +00001536 "could not create XPointer context\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001537 xmlFree(URL);
1538 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001539 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001540 }
1541 xptr = xmlXPtrEval(fragment, xptrctxt);
1542 if (xptr == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001543 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1544 XML_XINCLUDE_XPTR_FAILED,
1545 "XPointer evaluation failed: #%s\n",
1546 fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001547 xmlXPathFreeContext(xptrctxt);
1548 xmlFree(URL);
1549 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001550 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001551 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001552 switch (xptr->type) {
1553 case XPATH_UNDEFINED:
1554 case XPATH_BOOLEAN:
1555 case XPATH_NUMBER:
1556 case XPATH_STRING:
1557 case XPATH_POINT:
1558 case XPATH_USERS:
1559 case XPATH_XSLT_TREE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001560 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1561 XML_XINCLUDE_XPTR_RESULT,
1562 "XPointer is not a range: #%s\n",
1563 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001564 xmlXPathFreeContext(xptrctxt);
1565 xmlFree(URL);
1566 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001567 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001568 case XPATH_NODESET:
Daniel Veillard798ae542003-11-03 17:13:52 +00001569 if ((xptr->nodesetval == NULL) ||
1570 (xptr->nodesetval->nodeNr <= 0)) {
1571 xmlXPathFreeContext(xptrctxt);
1572 xmlFree(URL);
1573 xmlFree(fragment);
1574 return(-1);
1575 }
William M. Brackabf598b2004-06-08 02:01:28 +00001576
Daniel Veillard39196eb2001-06-19 18:09:42 +00001577 case XPATH_RANGE:
1578 case XPATH_LOCATIONSET:
1579 break;
1580 }
1581 set = xptr->nodesetval;
1582 if (set != NULL) {
1583 for (i = 0;i < set->nodeNr;i++) {
1584 if (set->nodeTab[i] == NULL)
1585 continue;
1586 switch (set->nodeTab[i]->type) {
1587 case XML_TEXT_NODE:
1588 case XML_CDATA_SECTION_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00001589 case XML_ENTITY_REF_NODE:
1590 case XML_ENTITY_NODE:
1591 case XML_PI_NODE:
1592 case XML_COMMENT_NODE:
1593 case XML_DOCUMENT_NODE:
1594 case XML_HTML_DOCUMENT_NODE:
1595#ifdef LIBXML_DOCB_ENABLED
1596 case XML_DOCB_DOCUMENT_NODE:
1597#endif
1598 continue;
William M. Brackabf598b2004-06-08 02:01:28 +00001599 case XML_ELEMENT_NODE: {
1600 xmlChar *nodeBase;
1601 xmlNodePtr el = set->nodeTab[i];
1602
1603 nodeBase = xmlNodeGetBase(el->doc, el);
1604 if (nodeBase != NULL) {
1605 if (!xmlStrEqual(nodeBase, el->doc->URL))
1606 xmlNodeSetBase(el, nodeBase);
1607 xmlFree(nodeBase);
1608 }
1609 continue;
1610 }
1611
Daniel Veillard39196eb2001-06-19 18:09:42 +00001612 case XML_ATTRIBUTE_NODE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001613 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1614 XML_XINCLUDE_XPTR_RESULT,
1615 "XPointer selects an attribute: #%s\n",
1616 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001617 set->nodeTab[i] = NULL;
1618 continue;
1619 case XML_NAMESPACE_DECL:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001620 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1621 XML_XINCLUDE_XPTR_RESULT,
1622 "XPointer selects a namespace: #%s\n",
1623 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001624 set->nodeTab[i] = NULL;
1625 continue;
1626 case XML_DOCUMENT_TYPE_NODE:
1627 case XML_DOCUMENT_FRAG_NODE:
1628 case XML_NOTATION_NODE:
1629 case XML_DTD_NODE:
1630 case XML_ELEMENT_DECL:
1631 case XML_ATTRIBUTE_DECL:
1632 case XML_ENTITY_DECL:
1633 case XML_XINCLUDE_START:
1634 case XML_XINCLUDE_END:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001635 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1636 XML_XINCLUDE_XPTR_RESULT,
1637 "XPointer selects unexpected nodes: #%s\n",
1638 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001639 set->nodeTab[i] = NULL;
1640 set->nodeTab[i] = NULL;
1641 continue; /* for */
1642 }
1643 }
1644 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001645 if (doc == NULL) {
1646 ctxt->incTab[nr]->xptr = xptr;
1647 ctxt->incTab[nr]->inc = NULL;
1648 } else {
1649 ctxt->incTab[nr]->inc =
1650 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1651 xmlXPathFreeObject(xptr);
1652 }
Owen Taylor3473f882001-02-23 17:55:21 +00001653 xmlXPathFreeContext(xptrctxt);
1654 xmlFree(fragment);
1655 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001656#endif
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001657
1658 /*
1659 * Do the xml:base fixup if needed
1660 */
1661 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1662 xmlNodePtr node;
William M. Brackf7789b12004-06-07 08:57:27 +00001663 xmlChar *relURI;
William M. Brackabf598b2004-06-08 02:01:28 +00001664 xmlChar *curBase;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001665
William M. Brackf7789b12004-06-07 08:57:27 +00001666 /*
1667 * The base is only adjusted if necessary for the existing base
1668 */
1669 relURI = xmlBuildRelativeURI(URL, ctxt->base);
1670 if (relURI == NULL) { /* Error return */
1671 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1672 XML_XINCLUDE_HREF_URI,
1673 "trying to build relative URI from %s\n", URL);
1674 } else {
1675 if (xmlStrchr(relURI, (xmlChar) '/')) {
1676 node = ctxt->incTab[nr]->inc;
1677 while (node != NULL) {
William M. Brackabf598b2004-06-08 02:01:28 +00001678 if (node->type == XML_ELEMENT_NODE) {
1679 curBase = xmlNodeGetBase(node->doc, node);
1680 if ((curBase == NULL) || xmlStrEqual(curBase, node->doc->URL))
1681 xmlNodeSetBase(node, relURI);
1682 if (curBase != NULL)
1683 xmlFree(curBase);
1684 }
William M. Brackf7789b12004-06-07 08:57:27 +00001685 node = node->next;
1686 }
1687 }
1688 xmlFree(relURI);
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001689 }
1690 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001691 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1692 (ctxt->incTab[nr]->count <= 1)) {
1693#ifdef DEBUG_XINCLUDE
1694 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1695#endif
1696 xmlFreeDoc(ctxt->incTab[nr]->doc);
1697 ctxt->incTab[nr]->doc = NULL;
1698 }
Owen Taylor3473f882001-02-23 17:55:21 +00001699 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001700 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001701}
1702
1703/**
1704 * xmlXIncludeLoadTxt:
1705 * @ctxt: the XInclude context
1706 * @url: the associated URL
1707 * @nr: the xinclude node number
1708 *
1709 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001710 *
1711 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001712 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001713static int
Owen Taylor3473f882001-02-23 17:55:21 +00001714xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1715 xmlParserInputBufferPtr buf;
1716 xmlNodePtr node;
1717 xmlURIPtr uri;
1718 xmlChar *URL;
1719 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001720 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001721 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001722
Owen Taylor3473f882001-02-23 17:55:21 +00001723 /*
1724 * Check the URL and remove any fragment identifier
1725 */
1726 uri = xmlParseURI((const char *)url);
1727 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001728 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1729 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001730 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001731 }
1732 if (uri->fragment != NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001733 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1734 "fragment identifier forbidden for text: %s\n",
1735 (const xmlChar *) uri->fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001736 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001737 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001738 }
1739 URL = xmlSaveUri(uri);
1740 xmlFreeURI(uri);
1741 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001742 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1743 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001744 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001745 }
1746
1747 /*
1748 * Handling of references to the local document are done
1749 * directly through ctxt->doc.
1750 */
1751 if (URL[0] == 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001752 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1753 XML_XINCLUDE_TEXT_DOCUMENT,
1754 "text serialization of document not available\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001755 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001756 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001757 }
1758
1759 /*
1760 * Prevent reloading twice the document.
1761 */
1762 for (i = 0; i < ctxt->txtNr; i++) {
1763 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1764 node = xmlCopyNode(ctxt->txtTab[i], 1);
1765 goto loaded;
1766 }
1767 }
1768 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001769 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001770 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001771 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1772 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1773 }
1774 if (encoding != NULL) {
1775 /*
1776 * TODO: we should not have to remap to the xmlCharEncoding
1777 * predefined set, a better interface than
1778 * xmlParserInputBufferCreateFilename should allow any
1779 * encoding supported by iconv
1780 */
1781 enc = xmlParseCharEncoding((const char *) encoding);
1782 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001783 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1784 XML_XINCLUDE_UNKNOWN_ENCODING,
1785 "encoding %s not supported\n", encoding);
Daniel Veillardd076a202002-11-20 13:28:31 +00001786 xmlFree(encoding);
1787 xmlFree(URL);
1788 return(-1);
1789 }
1790 xmlFree(encoding);
1791 }
1792
1793 /*
1794 * Load it.
1795 */
1796 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001797 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001798 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001799 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001800 }
1801 node = xmlNewText(NULL);
1802
1803 /*
1804 * Scan all chars from the resource and add the to the node
1805 */
1806 while (xmlParserInputBufferRead(buf, 128) > 0) {
1807 int len;
1808 const xmlChar *content;
1809
1810 content = xmlBufferContent(buf->buffer);
1811 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001812 for (i = 0;i < len;) {
1813 int cur;
1814 int l;
1815
1816 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1817 if (!IS_CHAR(cur)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001818 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1819 XML_XINCLUDE_INVALID_CHAR,
1820 "%s contains invalid char\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001821 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001822 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001823 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001824 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001825 }
1826 xmlBufferShrink(buf->buffer, len);
1827 }
1828 xmlFreeParserInputBuffer(buf);
1829 xmlXIncludeAddTxt(ctxt, node, URL);
1830
1831loaded:
1832 /*
1833 * Add the element as the replacement copy.
1834 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001835 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001836 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001837 return(0);
1838}
1839
1840/**
1841 * xmlXIncludeLoadFallback:
1842 * @ctxt: the XInclude context
1843 * @fallback: the fallback node
1844 * @nr: the xinclude node number
1845 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001846 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001847 * in the XInclude context
1848 *
1849 * Returns 0 in case of success, -1 in case of failure
1850 */
1851static int
1852xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
William M. Brackaae10522004-01-02 14:59:41 +00001853 xmlXIncludeCtxtPtr newctxt;
1854 int ret = 0;
1855
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001856 if ((fallback == NULL) || (ctxt == NULL))
1857 return(-1);
William M. Brackef245fd2004-02-06 09:33:59 +00001858 if (fallback->children != NULL) {
1859 /*
1860 * It's possible that the fallback also has 'includes'
1861 * (Bug 129969), so we re-process the fallback just in case
1862 */
1863 newctxt = xmlXIncludeNewContext(ctxt->doc);
1864 if (newctxt == NULL)
1865 return (-1);
William M. Brackf7789b12004-06-07 08:57:27 +00001866 newctxt->base = ctxt->base; /* Inherit the base from the existing context */
William M. Brackef245fd2004-02-06 09:33:59 +00001867 xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
1868 ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
William M. Brack87640d52004-04-17 14:58:15 +00001869 if (ctxt->nbErrors > 0)
William M. Brackef245fd2004-02-06 09:33:59 +00001870 ret = -1;
William M. Brack87640d52004-04-17 14:58:15 +00001871 else if (ret > 0)
1872 ret = 0; /* xmlXIncludeDoProcess can return +ve number */
William M. Brackef245fd2004-02-06 09:33:59 +00001873 xmlXIncludeFreeContext(newctxt);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001874
William M. Brackef245fd2004-02-06 09:33:59 +00001875 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
1876 } else {
1877 ctxt->incTab[nr]->inc = NULL;
William M. Brack95af5942004-02-08 04:12:49 +00001878 ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */
William M. Brackef245fd2004-02-06 09:33:59 +00001879 }
William M. Brackaae10522004-01-02 14:59:41 +00001880 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001881}
1882
1883/************************************************************************
1884 * *
1885 * XInclude Processing *
1886 * *
1887 ************************************************************************/
1888
1889/**
1890 * xmlXIncludePreProcessNode:
1891 * @ctxt: an XInclude context
1892 * @node: an XInclude node
1893 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001894 * Implement the XInclude preprocessing, currently just adding the element
1895 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001896 *
1897 * Returns the result list or NULL in case of error
1898 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001899static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001900xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1901 xmlXIncludeAddNode(ctxt, node);
1902 return(0);
1903}
1904
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001905/**
Owen Taylor3473f882001-02-23 17:55:21 +00001906 * xmlXIncludeLoadNode:
1907 * @ctxt: an XInclude context
1908 * @nr: the node number
1909 *
1910 * Find and load the infoset replacement for the given node.
1911 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001912 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001913 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001914static int
Owen Taylor3473f882001-02-23 17:55:21 +00001915xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1916 xmlNodePtr cur;
1917 xmlChar *href;
1918 xmlChar *parse;
1919 xmlChar *base;
William M. Brackf7789b12004-06-07 08:57:27 +00001920 xmlChar *oldBase;
Owen Taylor3473f882001-02-23 17:55:21 +00001921 xmlChar *URI;
1922 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001923 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001924
1925 if (ctxt == NULL)
1926 return(-1);
1927 if ((nr < 0) || (nr >= ctxt->incNr))
1928 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001929 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001930 if (cur == NULL)
1931 return(-1);
1932
Owen Taylor3473f882001-02-23 17:55:21 +00001933 /*
1934 * read the attributes
1935 */
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001936 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
Owen Taylor3473f882001-02-23 17:55:21 +00001937 if (href == NULL) {
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001938 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
1939 if (href == NULL)
1940 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001941 }
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001942 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 if (parse != NULL) {
1944 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1945 xml = 1;
1946 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1947 xml = 0;
1948 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001949 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1950 XML_XINCLUDE_PARSE_VALUE,
1951 "invalid value %s for 'parse'\n", parse);
Owen Taylor3473f882001-02-23 17:55:21 +00001952 if (href != NULL)
1953 xmlFree(href);
1954 if (parse != NULL)
1955 xmlFree(parse);
1956 return(-1);
1957 }
1958 }
1959
1960 /*
1961 * compute the URI
1962 */
1963 base = xmlNodeGetBase(ctxt->doc, cur);
1964 if (base == NULL) {
1965 URI = xmlBuildURI(href, ctxt->doc->URL);
1966 } else {
1967 URI = xmlBuildURI(href, base);
1968 }
1969 if (URI == NULL) {
1970 xmlChar *escbase;
1971 xmlChar *eschref;
1972 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001973 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001974 */
1975 escbase = xmlURIEscape(base);
1976 eschref = xmlURIEscape(href);
1977 URI = xmlBuildURI(eschref, escbase);
1978 if (escbase != NULL)
1979 xmlFree(escbase);
1980 if (eschref != NULL)
1981 xmlFree(eschref);
1982 }
1983 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001984 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1985 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001986 if (parse != NULL)
1987 xmlFree(parse);
1988 if (href != NULL)
1989 xmlFree(href);
1990 if (base != NULL)
1991 xmlFree(base);
1992 return(-1);
1993 }
1994#ifdef DEBUG_XINCLUDE
1995 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1996 xml ? "xml": "text");
1997 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1998#endif
1999
2000 /*
William M. Brackf7789b12004-06-07 08:57:27 +00002001 * Save the base for this include (saving the current one)
Owen Taylor3473f882001-02-23 17:55:21 +00002002 */
William M. Brackf7789b12004-06-07 08:57:27 +00002003 oldBase = ctxt->base;
2004 ctxt->base = base;
2005
Owen Taylor3473f882001-02-23 17:55:21 +00002006 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002007 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00002008 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
2009 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002010 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
2011 }
William M. Brackf7789b12004-06-07 08:57:27 +00002012
2013 /*
2014 * Restore the original base before checking for fallback
2015 */
2016 ctxt->base = oldBase;
2017
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002018 if (ret < 0) {
2019 xmlNodePtr children;
2020
2021 /*
2022 * Time to try a fallback if availble
2023 */
2024#ifdef DEBUG_XINCLUDE
2025 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
2026#endif
2027 children = cur->children;
2028 while (children != NULL) {
2029 if ((children->type == XML_ELEMENT_NODE) &&
2030 (children->ns != NULL) &&
2031 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002032 ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
2033 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002034 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
William M. Brack1ff42132003-12-31 14:05:15 +00002035 if (ret == 0)
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002036 break;
2037 }
2038 children = children->next;
2039 }
2040 }
2041 if (ret < 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002042 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2043 XML_XINCLUDE_NO_FALLBACK,
2044 "could not load %s, and no fallback was found\n",
2045 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00002046 }
2047
2048 /*
2049 * Cleanup
2050 */
2051 if (URI != NULL)
2052 xmlFree(URI);
2053 if (parse != NULL)
2054 xmlFree(parse);
2055 if (href != NULL)
2056 xmlFree(href);
2057 if (base != NULL)
2058 xmlFree(base);
2059 return(0);
2060}
2061
2062/**
2063 * xmlXIncludeIncludeNode:
2064 * @ctxt: an XInclude context
2065 * @nr: the node number
2066 *
2067 * Inplement the infoset replacement for the given node
2068 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002069 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002070 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002071static int
Owen Taylor3473f882001-02-23 17:55:21 +00002072xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002073 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00002074
2075 if (ctxt == NULL)
2076 return(-1);
2077 if ((nr < 0) || (nr >= ctxt->incNr))
2078 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002079 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00002080 if (cur == NULL)
2081 return(-1);
2082
2083 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002084 * If we stored an XPointer a late computation may be needed
2085 */
2086 if ((ctxt->incTab[nr]->inc == NULL) &&
2087 (ctxt->incTab[nr]->xptr != NULL)) {
2088 ctxt->incTab[nr]->inc =
2089 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
2090 ctxt->incTab[nr]->xptr);
2091 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
2092 ctxt->incTab[nr]->xptr = NULL;
2093 }
2094 list = ctxt->incTab[nr]->inc;
2095 ctxt->incTab[nr]->inc = NULL;
2096
2097 /*
2098 * Check against the risk of generating a multi-rooted document
2099 */
2100 if ((cur->parent != NULL) &&
2101 (cur->parent->type != XML_ELEMENT_NODE)) {
2102 int nb_elem = 0;
2103
2104 tmp = list;
2105 while (tmp != NULL) {
2106 if (tmp->type == XML_ELEMENT_NODE)
2107 nb_elem++;
2108 tmp = tmp->next;
2109 }
2110 if (nb_elem > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002111 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2112 XML_XINCLUDE_MULTIPLE_ROOT,
2113 "XInclude error: would result in multiple root nodes\n",
2114 NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002115 return(-1);
2116 }
2117 }
2118
2119 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002120 * Change the current node as an XInclude start one, and add an
2121 * entity end one
2122 */
2123 cur->type = XML_XINCLUDE_START;
2124 end = xmlNewNode(cur->ns, cur->name);
2125 if (end == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002126 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED,
2127 "failed to build node\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002128 return(-1);
2129 }
2130 end->type = XML_XINCLUDE_END;
2131 xmlAddNextSibling(cur, end);
2132
2133 /*
2134 * Add the list of nodes
2135 */
Owen Taylor3473f882001-02-23 17:55:21 +00002136 while (list != NULL) {
2137 cur = list;
2138 list = list->next;
2139
2140 xmlAddPrevSibling(end, cur);
2141 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002142
2143
Owen Taylor3473f882001-02-23 17:55:21 +00002144 return(0);
2145}
2146
2147/**
2148 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002149 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002150 * @node: an XInclude node
2151 *
2152 * test if the node is an XInclude node
2153 *
2154 * Returns 1 true, 0 otherwise
2155 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002156static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002157xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002158 if (node == NULL)
2159 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002160 if (node->type != XML_ELEMENT_NODE)
2161 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002162 if (node->ns == NULL)
2163 return(0);
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002164 if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
2165 (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
2166 if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
2167 if (ctxt->legacy == 0) {
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00002168#if 0 /* wait for the XML Core Working Group to get something stable ! */
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002169 xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
2170 "Deprecated XInclude namespace found, use %s",
2171 XINCLUDE_NS);
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00002172#endif
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002173 ctxt->legacy = 1;
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002174 }
2175 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002176 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2177 xmlNodePtr child = node->children;
2178 int nb_fallback = 0;
2179
2180 while (child != NULL) {
2181 if ((child->type == XML_ELEMENT_NODE) &&
2182 (child->ns != NULL) &&
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002183 ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
2184 (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002185 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002186 xmlXIncludeErr(ctxt, node,
2187 XML_XINCLUDE_INCLUDE_IN_INCLUDE,
2188 "%s has an 'include' child\n",
2189 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002190 return(0);
2191 }
2192 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2193 nb_fallback++;
2194 }
2195 }
2196 child = child->next;
2197 }
2198 if (nb_fallback > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002199 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
2200 "%s has multiple fallback children\n",
2201 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002202 return(0);
2203 }
2204 return(1);
2205 }
2206 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2207 if ((node->parent == NULL) ||
2208 (node->parent->type != XML_ELEMENT_NODE) ||
2209 (node->parent->ns == NULL) ||
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002210 ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
2211 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002212 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002213 xmlXIncludeErr(ctxt, node,
2214 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
2215 "%s is not the child of an 'include'\n",
2216 XINCLUDE_FALLBACK);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002217 }
2218 }
2219 }
Owen Taylor3473f882001-02-23 17:55:21 +00002220 return(0);
2221}
2222
2223/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002224 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002225 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002226 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002227 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00002228 *
2229 * Implement the XInclude substitution on the XML document @doc
2230 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002231 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002232 * or the number of substitutions done.
2233 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002234static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002235xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00002236 xmlNodePtr cur;
2237 int ret = 0;
2238 int i;
2239
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002240 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002241 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002242 if (ctxt == NULL)
2243 return(-1);
2244
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002245 if (doc->URL != NULL) {
2246 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2247 if (ret < 0)
2248 return(-1);
2249 }
2250
Owen Taylor3473f882001-02-23 17:55:21 +00002251 /*
2252 * First phase: lookup the elements in the document
2253 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002254 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002255 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002256 xmlXIncludePreProcessNode(ctxt, cur);
William M. Brack7b0e2762004-05-12 09:33:23 +00002257 while ((cur != NULL) && (cur != tree->parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002258 /* TODO: need to work on entities -> stack */
2259 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002260 (cur->children->type != XML_ENTITY_DECL) &&
2261 (cur->children->type != XML_XINCLUDE_START) &&
2262 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002263 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002264 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002265 xmlXIncludePreProcessNode(ctxt, cur);
2266 } else if (cur->next != NULL) {
2267 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002268 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002269 xmlXIncludePreProcessNode(ctxt, cur);
2270 } else {
William M. Brack5d8d10b2004-04-16 08:11:26 +00002271 if (cur == tree)
2272 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002273 do {
2274 cur = cur->parent;
William M. Brack7b0e2762004-05-12 09:33:23 +00002275 if ((cur == NULL) || (cur == tree->parent))
2276 break; /* do */
Owen Taylor3473f882001-02-23 17:55:21 +00002277 if (cur->next != NULL) {
2278 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002279 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002280 xmlXIncludePreProcessNode(ctxt, cur);
2281 break; /* do */
2282 }
2283 } while (cur != NULL);
2284 }
2285 }
2286
2287 /*
2288 * Second Phase : collect the infosets fragments
2289 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002290 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002291 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002292 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002293 }
2294
2295 /*
2296 * Third phase: extend the original document infoset.
William M. Brack6b1a28d2004-02-06 11:24:44 +00002297 *
2298 * Originally we bypassed the inclusion if there were any errors
2299 * encountered on any of the XIncludes. A bug was raised (bug
2300 * 132588) requesting that we output the XIncludes without error,
2301 * so the check for inc!=NULL || xptr!=NULL was put in. This may
2302 * give some other problems in the future, but for now it seems to
2303 * work ok.
2304 *
Owen Taylor3473f882001-02-23 17:55:21 +00002305 */
William M. Brack6b1a28d2004-02-06 11:24:44 +00002306 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
William M. Brack95af5942004-02-08 04:12:49 +00002307 if ((ctxt->incTab[i]->inc != NULL) ||
2308 (ctxt->incTab[i]->xptr != NULL) ||
2309 (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002310 xmlXIncludeIncludeNode(ctxt, i);
Owen Taylor3473f882001-02-23 17:55:21 +00002311 }
2312
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002313 if (doc->URL != NULL)
2314 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002315 return(ret);
2316}
2317
2318/**
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002319 * xmlXIncludeSetFlags:
2320 * @ctxt: an XInclude processing context
2321 * @flags: a set of xmlParserOption used for parsing XML includes
2322 *
2323 * Set the flags used for further processing of XML resources.
2324 *
2325 * Returns 0 in case of success and -1 in case of error.
2326 */
2327int
2328xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
2329 if (ctxt == NULL)
2330 return(-1);
2331 ctxt->parseFlags = flags;
2332 return(0);
2333}
2334
2335/**
2336 * xmlXIncludeProcessFlags:
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002337 * @doc: an XML document
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002338 * @flags: a set of xmlParserOption used for parsing XML includes
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002339 *
2340 * Implement the XInclude substitution on the XML document @doc
2341 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002342 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002343 * or the number of substitutions done.
2344 */
2345int
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002346xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002347 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002348 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002349 int ret = 0;
2350
2351 if (doc == NULL)
2352 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002353 tree = xmlDocGetRootElement(doc);
2354 if (tree == NULL)
2355 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002356 ctxt = xmlXIncludeNewContext(doc);
2357 if (ctxt == NULL)
2358 return(-1);
William M. Brackf7789b12004-06-07 08:57:27 +00002359 ctxt->base = (xmlChar *)doc->URL;
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002360 xmlXIncludeSetFlags(ctxt, flags);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002361 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2362 if ((ret >= 0) && (ctxt->nbErrors > 0))
2363 ret = -1;
2364
2365 xmlXIncludeFreeContext(ctxt);
2366 return(ret);
2367}
2368
2369/**
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002370 * xmlXIncludeProcess:
2371 * @doc: an XML document
2372 *
2373 * Implement the XInclude substitution on the XML document @doc
2374 *
2375 * Returns 0 if no substitution were done, -1 if some processing failed
2376 * or the number of substitutions done.
2377 */
2378int
2379xmlXIncludeProcess(xmlDocPtr doc) {
2380 return(xmlXIncludeProcessFlags(doc, 0));
2381}
2382
2383/**
2384 * xmlXIncludeProcessTreeFlags:
2385 * @tree: a node in an XML document
2386 * @flags: a set of xmlParserOption used for parsing XML includes
2387 *
2388 * Implement the XInclude substitution for the given subtree
2389 *
2390 * Returns 0 if no substitution were done, -1 if some processing failed
2391 * or the number of substitutions done.
2392 */
2393int
2394xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
2395 xmlXIncludeCtxtPtr ctxt;
2396 int ret = 0;
2397
2398 if ((tree == NULL) || (tree->doc == NULL))
2399 return(-1);
2400 ctxt = xmlXIncludeNewContext(tree->doc);
2401 if (ctxt == NULL)
2402 return(-1);
William M. Brackf7789b12004-06-07 08:57:27 +00002403 ctxt->base = xmlNodeGetBase(tree->doc, tree);
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002404 xmlXIncludeSetFlags(ctxt, flags);
2405 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
2406 if ((ret >= 0) && (ctxt->nbErrors > 0))
2407 ret = -1;
2408
2409 xmlXIncludeFreeContext(ctxt);
2410 return(ret);
2411}
2412
2413/**
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002414 * xmlXIncludeProcessTree:
2415 * @tree: a node in an XML document
2416 *
2417 * Implement the XInclude substitution for the given subtree
2418 *
2419 * Returns 0 if no substitution were done, -1 if some processing failed
2420 * or the number of substitutions done.
2421 */
2422int
2423xmlXIncludeProcessTree(xmlNodePtr tree) {
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002424 return(xmlXIncludeProcessTreeFlags(tree, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00002425}
2426
Daniel Veillard7899c5c2003-11-03 12:31:38 +00002427/**
2428 * xmlXIncludeProcessNode:
2429 * @ctxt: an existing XInclude context
2430 * @node: a node in an XML document
2431 *
2432 * Implement the XInclude substitution for the given subtree reusing
2433 * the informations and data coming from the given context.
2434 *
2435 * Returns 0 if no substitution were done, -1 if some processing failed
2436 * or the number of substitutions done.
2437 */
2438int
2439xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2440 int ret = 0;
2441
2442 if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
2443 return(-1);
2444 ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
2445 if ((ret >= 0) && (ctxt->nbErrors > 0))
2446 ret = -1;
2447 return(ret);
2448}
2449
Owen Taylor3473f882001-02-23 17:55:21 +00002450#else /* !LIBXML_XINCLUDE_ENABLED */
2451#endif