blob: 196f4a9dae0ea3d24b7469144595c3d9d7a2b035 [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;
Daniel Veillard98485322003-08-14 15:44:40 +00001462 for (i = nr + 1; i < ctxt->incNr; i++) {
1463 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1464 ctxt->incTab[nr]->count++;
1465#ifdef DEBUG_XINCLUDE
1466 printf("Increasing %s count since reused\n", URL);
1467#endif
1468 break;
1469 }
1470 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001471
1472 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001473 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001474 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001475 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001476
1477 /*
1478 * We don't need the DTD anymore, free up space
1479 if (doc->intSubset != NULL) {
1480 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1481 xmlFreeNode((xmlNodePtr) doc->intSubset);
1482 doc->intSubset = NULL;
1483 }
1484 if (doc->extSubset != NULL) {
1485 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1486 xmlFreeNode((xmlNodePtr) doc->extSubset);
1487 doc->extSubset = NULL;
1488 }
1489 */
1490 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001491
1492loaded:
1493 if (fragment == NULL) {
1494 /*
1495 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001496 */
1497 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001498 {
1499 /* Hopefully a DTD declaration won't be copied from
1500 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001501 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001502 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001503 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001504 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001505 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001506 }
1507#ifdef LIBXML_XPTR_ENABLED
1508 else {
Owen Taylor3473f882001-02-23 17:55:21 +00001509 /*
1510 * Computes the XPointer expression and make a copy used
1511 * as the replacement copy.
1512 */
1513 xmlXPathObjectPtr xptr;
1514 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001515 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001516
1517 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001518 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1519 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001520 } else {
1521 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1522 }
1523 if (xptrctxt == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001524 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1525 XML_XINCLUDE_XPTR_FAILED,
Daniel Veillarda152c4d2003-11-19 16:24:26 +00001526 "could not create XPointer context\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001527 xmlFree(URL);
1528 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001529 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001530 }
1531 xptr = xmlXPtrEval(fragment, xptrctxt);
1532 if (xptr == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001533 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1534 XML_XINCLUDE_XPTR_FAILED,
1535 "XPointer evaluation failed: #%s\n",
1536 fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001537 xmlXPathFreeContext(xptrctxt);
1538 xmlFree(URL);
1539 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001540 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001541 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001542 switch (xptr->type) {
1543 case XPATH_UNDEFINED:
1544 case XPATH_BOOLEAN:
1545 case XPATH_NUMBER:
1546 case XPATH_STRING:
1547 case XPATH_POINT:
1548 case XPATH_USERS:
1549 case XPATH_XSLT_TREE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001550 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1551 XML_XINCLUDE_XPTR_RESULT,
1552 "XPointer is not a range: #%s\n",
1553 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001554 xmlXPathFreeContext(xptrctxt);
1555 xmlFree(URL);
1556 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001557 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001558 case XPATH_NODESET:
Daniel Veillard798ae542003-11-03 17:13:52 +00001559 if ((xptr->nodesetval == NULL) ||
1560 (xptr->nodesetval->nodeNr <= 0)) {
1561 xmlXPathFreeContext(xptrctxt);
1562 xmlFree(URL);
1563 xmlFree(fragment);
1564 return(-1);
1565 }
William M. Brackabf598b2004-06-08 02:01:28 +00001566
Daniel Veillard39196eb2001-06-19 18:09:42 +00001567 case XPATH_RANGE:
1568 case XPATH_LOCATIONSET:
1569 break;
1570 }
1571 set = xptr->nodesetval;
1572 if (set != NULL) {
1573 for (i = 0;i < set->nodeNr;i++) {
1574 if (set->nodeTab[i] == NULL)
1575 continue;
1576 switch (set->nodeTab[i]->type) {
1577 case XML_TEXT_NODE:
1578 case XML_CDATA_SECTION_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00001579 case XML_ENTITY_REF_NODE:
1580 case XML_ENTITY_NODE:
1581 case XML_PI_NODE:
1582 case XML_COMMENT_NODE:
1583 case XML_DOCUMENT_NODE:
1584 case XML_HTML_DOCUMENT_NODE:
1585#ifdef LIBXML_DOCB_ENABLED
1586 case XML_DOCB_DOCUMENT_NODE:
1587#endif
1588 continue;
William M. Brackabf598b2004-06-08 02:01:28 +00001589 case XML_ELEMENT_NODE: {
1590 xmlChar *nodeBase;
1591 xmlNodePtr el = set->nodeTab[i];
1592
1593 nodeBase = xmlNodeGetBase(el->doc, el);
1594 if (nodeBase != NULL) {
1595 if (!xmlStrEqual(nodeBase, el->doc->URL))
1596 xmlNodeSetBase(el, nodeBase);
1597 xmlFree(nodeBase);
1598 }
1599 continue;
1600 }
1601
Daniel Veillard39196eb2001-06-19 18:09:42 +00001602 case XML_ATTRIBUTE_NODE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001603 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1604 XML_XINCLUDE_XPTR_RESULT,
1605 "XPointer selects an attribute: #%s\n",
1606 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001607 set->nodeTab[i] = NULL;
1608 continue;
1609 case XML_NAMESPACE_DECL:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001610 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1611 XML_XINCLUDE_XPTR_RESULT,
1612 "XPointer selects a namespace: #%s\n",
1613 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001614 set->nodeTab[i] = NULL;
1615 continue;
1616 case XML_DOCUMENT_TYPE_NODE:
1617 case XML_DOCUMENT_FRAG_NODE:
1618 case XML_NOTATION_NODE:
1619 case XML_DTD_NODE:
1620 case XML_ELEMENT_DECL:
1621 case XML_ATTRIBUTE_DECL:
1622 case XML_ENTITY_DECL:
1623 case XML_XINCLUDE_START:
1624 case XML_XINCLUDE_END:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001625 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1626 XML_XINCLUDE_XPTR_RESULT,
1627 "XPointer selects unexpected nodes: #%s\n",
1628 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001629 set->nodeTab[i] = NULL;
1630 set->nodeTab[i] = NULL;
1631 continue; /* for */
1632 }
1633 }
1634 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001635 if (doc == NULL) {
1636 ctxt->incTab[nr]->xptr = xptr;
1637 ctxt->incTab[nr]->inc = NULL;
1638 } else {
1639 ctxt->incTab[nr]->inc =
1640 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1641 xmlXPathFreeObject(xptr);
1642 }
Owen Taylor3473f882001-02-23 17:55:21 +00001643 xmlXPathFreeContext(xptrctxt);
1644 xmlFree(fragment);
1645 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001646#endif
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001647
1648 /*
1649 * Do the xml:base fixup if needed
1650 */
1651 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1652 xmlNodePtr node;
William M. Brackf7789b12004-06-07 08:57:27 +00001653 xmlChar *relURI;
William M. Brackabf598b2004-06-08 02:01:28 +00001654 xmlChar *curBase;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001655
William M. Brackf7789b12004-06-07 08:57:27 +00001656 /*
1657 * The base is only adjusted if necessary for the existing base
1658 */
1659 relURI = xmlBuildRelativeURI(URL, ctxt->base);
1660 if (relURI == NULL) { /* Error return */
1661 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1662 XML_XINCLUDE_HREF_URI,
1663 "trying to build relative URI from %s\n", URL);
1664 } else {
1665 if (xmlStrchr(relURI, (xmlChar) '/')) {
1666 node = ctxt->incTab[nr]->inc;
1667 while (node != NULL) {
William M. Brackabf598b2004-06-08 02:01:28 +00001668 if (node->type == XML_ELEMENT_NODE) {
1669 curBase = xmlNodeGetBase(node->doc, node);
1670 if ((curBase == NULL) || xmlStrEqual(curBase, node->doc->URL))
1671 xmlNodeSetBase(node, relURI);
1672 if (curBase != NULL)
1673 xmlFree(curBase);
1674 }
William M. Brackf7789b12004-06-07 08:57:27 +00001675 node = node->next;
1676 }
1677 }
1678 xmlFree(relURI);
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001679 }
1680 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001681 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1682 (ctxt->incTab[nr]->count <= 1)) {
1683#ifdef DEBUG_XINCLUDE
1684 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1685#endif
1686 xmlFreeDoc(ctxt->incTab[nr]->doc);
1687 ctxt->incTab[nr]->doc = NULL;
1688 }
Owen Taylor3473f882001-02-23 17:55:21 +00001689 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001690 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001691}
1692
1693/**
1694 * xmlXIncludeLoadTxt:
1695 * @ctxt: the XInclude context
1696 * @url: the associated URL
1697 * @nr: the xinclude node number
1698 *
1699 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001700 *
1701 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001702 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001703static int
Owen Taylor3473f882001-02-23 17:55:21 +00001704xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1705 xmlParserInputBufferPtr buf;
1706 xmlNodePtr node;
1707 xmlURIPtr uri;
1708 xmlChar *URL;
1709 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001710 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001711 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001712
Owen Taylor3473f882001-02-23 17:55:21 +00001713 /*
1714 * Check the URL and remove any fragment identifier
1715 */
1716 uri = xmlParseURI((const char *)url);
1717 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001718 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1719 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001720 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001721 }
1722 if (uri->fragment != NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001723 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1724 "fragment identifier forbidden for text: %s\n",
1725 (const xmlChar *) uri->fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001726 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001727 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001728 }
1729 URL = xmlSaveUri(uri);
1730 xmlFreeURI(uri);
1731 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001732 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1733 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001734 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001735 }
1736
1737 /*
1738 * Handling of references to the local document are done
1739 * directly through ctxt->doc.
1740 */
1741 if (URL[0] == 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001742 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1743 XML_XINCLUDE_TEXT_DOCUMENT,
1744 "text serialization of document not available\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001745 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001746 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001747 }
1748
1749 /*
1750 * Prevent reloading twice the document.
1751 */
1752 for (i = 0; i < ctxt->txtNr; i++) {
1753 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1754 node = xmlCopyNode(ctxt->txtTab[i], 1);
1755 goto loaded;
1756 }
1757 }
1758 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001759 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001760 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001761 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1762 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1763 }
1764 if (encoding != NULL) {
1765 /*
1766 * TODO: we should not have to remap to the xmlCharEncoding
1767 * predefined set, a better interface than
1768 * xmlParserInputBufferCreateFilename should allow any
1769 * encoding supported by iconv
1770 */
1771 enc = xmlParseCharEncoding((const char *) encoding);
1772 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001773 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1774 XML_XINCLUDE_UNKNOWN_ENCODING,
1775 "encoding %s not supported\n", encoding);
Daniel Veillardd076a202002-11-20 13:28:31 +00001776 xmlFree(encoding);
1777 xmlFree(URL);
1778 return(-1);
1779 }
1780 xmlFree(encoding);
1781 }
1782
1783 /*
1784 * Load it.
1785 */
1786 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001787 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001788 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001789 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001790 }
1791 node = xmlNewText(NULL);
1792
1793 /*
1794 * Scan all chars from the resource and add the to the node
1795 */
1796 while (xmlParserInputBufferRead(buf, 128) > 0) {
1797 int len;
1798 const xmlChar *content;
1799
1800 content = xmlBufferContent(buf->buffer);
1801 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001802 for (i = 0;i < len;) {
1803 int cur;
1804 int l;
1805
1806 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1807 if (!IS_CHAR(cur)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001808 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1809 XML_XINCLUDE_INVALID_CHAR,
1810 "%s contains invalid char\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001811 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001812 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001813 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001814 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001815 }
1816 xmlBufferShrink(buf->buffer, len);
1817 }
1818 xmlFreeParserInputBuffer(buf);
1819 xmlXIncludeAddTxt(ctxt, node, URL);
1820
1821loaded:
1822 /*
1823 * Add the element as the replacement copy.
1824 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001825 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001826 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001827 return(0);
1828}
1829
1830/**
1831 * xmlXIncludeLoadFallback:
1832 * @ctxt: the XInclude context
1833 * @fallback: the fallback node
1834 * @nr: the xinclude node number
1835 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001836 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001837 * in the XInclude context
1838 *
1839 * Returns 0 in case of success, -1 in case of failure
1840 */
1841static int
1842xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
William M. Brackaae10522004-01-02 14:59:41 +00001843 xmlXIncludeCtxtPtr newctxt;
1844 int ret = 0;
1845
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001846 if ((fallback == NULL) || (ctxt == NULL))
1847 return(-1);
William M. Brackef245fd2004-02-06 09:33:59 +00001848 if (fallback->children != NULL) {
1849 /*
1850 * It's possible that the fallback also has 'includes'
1851 * (Bug 129969), so we re-process the fallback just in case
1852 */
1853 newctxt = xmlXIncludeNewContext(ctxt->doc);
1854 if (newctxt == NULL)
1855 return (-1);
William M. Brackf7789b12004-06-07 08:57:27 +00001856 newctxt->base = ctxt->base; /* Inherit the base from the existing context */
William M. Brackef245fd2004-02-06 09:33:59 +00001857 xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
1858 ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
William M. Brack87640d52004-04-17 14:58:15 +00001859 if (ctxt->nbErrors > 0)
William M. Brackef245fd2004-02-06 09:33:59 +00001860 ret = -1;
William M. Brack87640d52004-04-17 14:58:15 +00001861 else if (ret > 0)
1862 ret = 0; /* xmlXIncludeDoProcess can return +ve number */
William M. Brackef245fd2004-02-06 09:33:59 +00001863 xmlXIncludeFreeContext(newctxt);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001864
William M. Brackef245fd2004-02-06 09:33:59 +00001865 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
1866 } else {
1867 ctxt->incTab[nr]->inc = NULL;
William M. Brack95af5942004-02-08 04:12:49 +00001868 ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */
William M. Brackef245fd2004-02-06 09:33:59 +00001869 }
William M. Brackaae10522004-01-02 14:59:41 +00001870 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001871}
1872
1873/************************************************************************
1874 * *
1875 * XInclude Processing *
1876 * *
1877 ************************************************************************/
1878
1879/**
1880 * xmlXIncludePreProcessNode:
1881 * @ctxt: an XInclude context
1882 * @node: an XInclude node
1883 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001884 * Implement the XInclude preprocessing, currently just adding the element
1885 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001886 *
1887 * Returns the result list or NULL in case of error
1888 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001889static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001890xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1891 xmlXIncludeAddNode(ctxt, node);
1892 return(0);
1893}
1894
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001895/**
Owen Taylor3473f882001-02-23 17:55:21 +00001896 * xmlXIncludeLoadNode:
1897 * @ctxt: an XInclude context
1898 * @nr: the node number
1899 *
1900 * Find and load the infoset replacement for the given node.
1901 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001902 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001903 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001904static int
Owen Taylor3473f882001-02-23 17:55:21 +00001905xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1906 xmlNodePtr cur;
1907 xmlChar *href;
1908 xmlChar *parse;
1909 xmlChar *base;
William M. Brackf7789b12004-06-07 08:57:27 +00001910 xmlChar *oldBase;
Owen Taylor3473f882001-02-23 17:55:21 +00001911 xmlChar *URI;
1912 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001913 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001914
1915 if (ctxt == NULL)
1916 return(-1);
1917 if ((nr < 0) || (nr >= ctxt->incNr))
1918 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001919 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001920 if (cur == NULL)
1921 return(-1);
1922
Owen Taylor3473f882001-02-23 17:55:21 +00001923 /*
1924 * read the attributes
1925 */
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001926 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
Owen Taylor3473f882001-02-23 17:55:21 +00001927 if (href == NULL) {
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001928 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
1929 if (href == NULL)
1930 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001931 }
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001932 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
Owen Taylor3473f882001-02-23 17:55:21 +00001933 if (parse != NULL) {
1934 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1935 xml = 1;
1936 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1937 xml = 0;
1938 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001939 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1940 XML_XINCLUDE_PARSE_VALUE,
1941 "invalid value %s for 'parse'\n", parse);
Owen Taylor3473f882001-02-23 17:55:21 +00001942 if (href != NULL)
1943 xmlFree(href);
1944 if (parse != NULL)
1945 xmlFree(parse);
1946 return(-1);
1947 }
1948 }
1949
1950 /*
1951 * compute the URI
1952 */
1953 base = xmlNodeGetBase(ctxt->doc, cur);
1954 if (base == NULL) {
1955 URI = xmlBuildURI(href, ctxt->doc->URL);
1956 } else {
1957 URI = xmlBuildURI(href, base);
1958 }
1959 if (URI == NULL) {
1960 xmlChar *escbase;
1961 xmlChar *eschref;
1962 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001963 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001964 */
1965 escbase = xmlURIEscape(base);
1966 eschref = xmlURIEscape(href);
1967 URI = xmlBuildURI(eschref, escbase);
1968 if (escbase != NULL)
1969 xmlFree(escbase);
1970 if (eschref != NULL)
1971 xmlFree(eschref);
1972 }
1973 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001974 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1975 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001976 if (parse != NULL)
1977 xmlFree(parse);
1978 if (href != NULL)
1979 xmlFree(href);
1980 if (base != NULL)
1981 xmlFree(base);
1982 return(-1);
1983 }
1984#ifdef DEBUG_XINCLUDE
1985 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1986 xml ? "xml": "text");
1987 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1988#endif
1989
1990 /*
William M. Brackf7789b12004-06-07 08:57:27 +00001991 * Save the base for this include (saving the current one)
Owen Taylor3473f882001-02-23 17:55:21 +00001992 */
William M. Brackf7789b12004-06-07 08:57:27 +00001993 oldBase = ctxt->base;
1994 ctxt->base = base;
1995
Owen Taylor3473f882001-02-23 17:55:21 +00001996 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001997 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001998 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1999 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002000 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
2001 }
William M. Brackf7789b12004-06-07 08:57:27 +00002002
2003 /*
2004 * Restore the original base before checking for fallback
2005 */
2006 ctxt->base = oldBase;
2007
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002008 if (ret < 0) {
2009 xmlNodePtr children;
2010
2011 /*
2012 * Time to try a fallback if availble
2013 */
2014#ifdef DEBUG_XINCLUDE
2015 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
2016#endif
2017 children = cur->children;
2018 while (children != NULL) {
2019 if ((children->type == XML_ELEMENT_NODE) &&
2020 (children->ns != NULL) &&
2021 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002022 ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
2023 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002024 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
William M. Brack1ff42132003-12-31 14:05:15 +00002025 if (ret == 0)
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00002026 break;
2027 }
2028 children = children->next;
2029 }
2030 }
2031 if (ret < 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002032 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2033 XML_XINCLUDE_NO_FALLBACK,
2034 "could not load %s, and no fallback was found\n",
2035 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00002036 }
2037
2038 /*
2039 * Cleanup
2040 */
2041 if (URI != NULL)
2042 xmlFree(URI);
2043 if (parse != NULL)
2044 xmlFree(parse);
2045 if (href != NULL)
2046 xmlFree(href);
2047 if (base != NULL)
2048 xmlFree(base);
2049 return(0);
2050}
2051
2052/**
2053 * xmlXIncludeIncludeNode:
2054 * @ctxt: an XInclude context
2055 * @nr: the node number
2056 *
2057 * Inplement the infoset replacement for the given node
2058 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002059 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002060 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002061static int
Owen Taylor3473f882001-02-23 17:55:21 +00002062xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002063 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00002064
2065 if (ctxt == NULL)
2066 return(-1);
2067 if ((nr < 0) || (nr >= ctxt->incNr))
2068 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002069 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00002070 if (cur == NULL)
2071 return(-1);
2072
2073 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002074 * If we stored an XPointer a late computation may be needed
2075 */
2076 if ((ctxt->incTab[nr]->inc == NULL) &&
2077 (ctxt->incTab[nr]->xptr != NULL)) {
2078 ctxt->incTab[nr]->inc =
2079 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
2080 ctxt->incTab[nr]->xptr);
2081 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
2082 ctxt->incTab[nr]->xptr = NULL;
2083 }
2084 list = ctxt->incTab[nr]->inc;
2085 ctxt->incTab[nr]->inc = NULL;
2086
2087 /*
2088 * Check against the risk of generating a multi-rooted document
2089 */
2090 if ((cur->parent != NULL) &&
2091 (cur->parent->type != XML_ELEMENT_NODE)) {
2092 int nb_elem = 0;
2093
2094 tmp = list;
2095 while (tmp != NULL) {
2096 if (tmp->type == XML_ELEMENT_NODE)
2097 nb_elem++;
2098 tmp = tmp->next;
2099 }
2100 if (nb_elem > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002101 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2102 XML_XINCLUDE_MULTIPLE_ROOT,
2103 "XInclude error: would result in multiple root nodes\n",
2104 NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002105 return(-1);
2106 }
2107 }
2108
2109 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002110 * Change the current node as an XInclude start one, and add an
2111 * entity end one
2112 */
2113 cur->type = XML_XINCLUDE_START;
2114 end = xmlNewNode(cur->ns, cur->name);
2115 if (end == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002116 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED,
2117 "failed to build node\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002118 return(-1);
2119 }
2120 end->type = XML_XINCLUDE_END;
2121 xmlAddNextSibling(cur, end);
2122
2123 /*
2124 * Add the list of nodes
2125 */
Owen Taylor3473f882001-02-23 17:55:21 +00002126 while (list != NULL) {
2127 cur = list;
2128 list = list->next;
2129
2130 xmlAddPrevSibling(end, cur);
2131 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002132
2133
Owen Taylor3473f882001-02-23 17:55:21 +00002134 return(0);
2135}
2136
2137/**
2138 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002139 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002140 * @node: an XInclude node
2141 *
2142 * test if the node is an XInclude node
2143 *
2144 * Returns 1 true, 0 otherwise
2145 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002146static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002147xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002148 if (node == NULL)
2149 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002150 if (node->type != XML_ELEMENT_NODE)
2151 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002152 if (node->ns == NULL)
2153 return(0);
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002154 if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
2155 (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
2156 if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
2157 if (ctxt->legacy == 0) {
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00002158#if 0 /* wait for the XML Core Working Group to get something stable ! */
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002159 xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
2160 "Deprecated XInclude namespace found, use %s",
2161 XINCLUDE_NS);
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00002162#endif
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002163 ctxt->legacy = 1;
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002164 }
2165 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002166 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2167 xmlNodePtr child = node->children;
2168 int nb_fallback = 0;
2169
2170 while (child != NULL) {
2171 if ((child->type == XML_ELEMENT_NODE) &&
2172 (child->ns != NULL) &&
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002173 ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
2174 (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002175 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002176 xmlXIncludeErr(ctxt, node,
2177 XML_XINCLUDE_INCLUDE_IN_INCLUDE,
2178 "%s has an 'include' child\n",
2179 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002180 return(0);
2181 }
2182 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2183 nb_fallback++;
2184 }
2185 }
2186 child = child->next;
2187 }
2188 if (nb_fallback > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002189 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
2190 "%s has multiple fallback children\n",
2191 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002192 return(0);
2193 }
2194 return(1);
2195 }
2196 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2197 if ((node->parent == NULL) ||
2198 (node->parent->type != XML_ELEMENT_NODE) ||
2199 (node->parent->ns == NULL) ||
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002200 ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
2201 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002202 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002203 xmlXIncludeErr(ctxt, node,
2204 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
2205 "%s is not the child of an 'include'\n",
2206 XINCLUDE_FALLBACK);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002207 }
2208 }
2209 }
Owen Taylor3473f882001-02-23 17:55:21 +00002210 return(0);
2211}
2212
2213/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002214 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002215 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002216 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002217 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00002218 *
2219 * Implement the XInclude substitution on the XML document @doc
2220 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002221 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002222 * or the number of substitutions done.
2223 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002224static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002225xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00002226 xmlNodePtr cur;
2227 int ret = 0;
2228 int i;
2229
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002230 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002231 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002232 if (ctxt == NULL)
2233 return(-1);
2234
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002235 if (doc->URL != NULL) {
2236 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2237 if (ret < 0)
2238 return(-1);
2239 }
2240
Owen Taylor3473f882001-02-23 17:55:21 +00002241 /*
2242 * First phase: lookup the elements in the document
2243 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002244 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002245 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlXIncludePreProcessNode(ctxt, cur);
William M. Brack7b0e2762004-05-12 09:33:23 +00002247 while ((cur != NULL) && (cur != tree->parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002248 /* TODO: need to work on entities -> stack */
2249 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002250 (cur->children->type != XML_ENTITY_DECL) &&
2251 (cur->children->type != XML_XINCLUDE_START) &&
2252 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002253 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002254 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002255 xmlXIncludePreProcessNode(ctxt, cur);
2256 } else if (cur->next != NULL) {
2257 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002258 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002259 xmlXIncludePreProcessNode(ctxt, cur);
2260 } else {
William M. Brack5d8d10b2004-04-16 08:11:26 +00002261 if (cur == tree)
2262 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002263 do {
2264 cur = cur->parent;
William M. Brack7b0e2762004-05-12 09:33:23 +00002265 if ((cur == NULL) || (cur == tree->parent))
2266 break; /* do */
Owen Taylor3473f882001-02-23 17:55:21 +00002267 if (cur->next != NULL) {
2268 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002269 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002270 xmlXIncludePreProcessNode(ctxt, cur);
2271 break; /* do */
2272 }
2273 } while (cur != NULL);
2274 }
2275 }
2276
2277 /*
2278 * Second Phase : collect the infosets fragments
2279 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002280 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002281 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002282 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002283 }
2284
2285 /*
2286 * Third phase: extend the original document infoset.
William M. Brack6b1a28d2004-02-06 11:24:44 +00002287 *
2288 * Originally we bypassed the inclusion if there were any errors
2289 * encountered on any of the XIncludes. A bug was raised (bug
2290 * 132588) requesting that we output the XIncludes without error,
2291 * so the check for inc!=NULL || xptr!=NULL was put in. This may
2292 * give some other problems in the future, but for now it seems to
2293 * work ok.
2294 *
Owen Taylor3473f882001-02-23 17:55:21 +00002295 */
William M. Brack6b1a28d2004-02-06 11:24:44 +00002296 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
William M. Brack95af5942004-02-08 04:12:49 +00002297 if ((ctxt->incTab[i]->inc != NULL) ||
2298 (ctxt->incTab[i]->xptr != NULL) ||
2299 (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002300 xmlXIncludeIncludeNode(ctxt, i);
Owen Taylor3473f882001-02-23 17:55:21 +00002301 }
2302
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002303 if (doc->URL != NULL)
2304 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002305 return(ret);
2306}
2307
2308/**
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002309 * xmlXIncludeSetFlags:
2310 * @ctxt: an XInclude processing context
2311 * @flags: a set of xmlParserOption used for parsing XML includes
2312 *
2313 * Set the flags used for further processing of XML resources.
2314 *
2315 * Returns 0 in case of success and -1 in case of error.
2316 */
2317int
2318xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
2319 if (ctxt == NULL)
2320 return(-1);
2321 ctxt->parseFlags = flags;
2322 return(0);
2323}
2324
2325/**
2326 * xmlXIncludeProcessFlags:
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002327 * @doc: an XML document
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002328 * @flags: a set of xmlParserOption used for parsing XML includes
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002329 *
2330 * Implement the XInclude substitution on the XML document @doc
2331 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002332 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002333 * or the number of substitutions done.
2334 */
2335int
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002336xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002337 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002338 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002339 int ret = 0;
2340
2341 if (doc == NULL)
2342 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002343 tree = xmlDocGetRootElement(doc);
2344 if (tree == NULL)
2345 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002346 ctxt = xmlXIncludeNewContext(doc);
2347 if (ctxt == NULL)
2348 return(-1);
William M. Brackf7789b12004-06-07 08:57:27 +00002349 ctxt->base = (xmlChar *)doc->URL;
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002350 xmlXIncludeSetFlags(ctxt, flags);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002351 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2352 if ((ret >= 0) && (ctxt->nbErrors > 0))
2353 ret = -1;
2354
2355 xmlXIncludeFreeContext(ctxt);
2356 return(ret);
2357}
2358
2359/**
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002360 * xmlXIncludeProcess:
2361 * @doc: an XML document
2362 *
2363 * Implement the XInclude substitution on the XML document @doc
2364 *
2365 * Returns 0 if no substitution were done, -1 if some processing failed
2366 * or the number of substitutions done.
2367 */
2368int
2369xmlXIncludeProcess(xmlDocPtr doc) {
2370 return(xmlXIncludeProcessFlags(doc, 0));
2371}
2372
2373/**
2374 * xmlXIncludeProcessTreeFlags:
2375 * @tree: a node in an XML document
2376 * @flags: a set of xmlParserOption used for parsing XML includes
2377 *
2378 * Implement the XInclude substitution for the given subtree
2379 *
2380 * Returns 0 if no substitution were done, -1 if some processing failed
2381 * or the number of substitutions done.
2382 */
2383int
2384xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
2385 xmlXIncludeCtxtPtr ctxt;
2386 int ret = 0;
2387
2388 if ((tree == NULL) || (tree->doc == NULL))
2389 return(-1);
2390 ctxt = xmlXIncludeNewContext(tree->doc);
2391 if (ctxt == NULL)
2392 return(-1);
William M. Brackf7789b12004-06-07 08:57:27 +00002393 ctxt->base = xmlNodeGetBase(tree->doc, tree);
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002394 xmlXIncludeSetFlags(ctxt, flags);
2395 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
2396 if ((ret >= 0) && (ctxt->nbErrors > 0))
2397 ret = -1;
2398
2399 xmlXIncludeFreeContext(ctxt);
2400 return(ret);
2401}
2402
2403/**
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002404 * xmlXIncludeProcessTree:
2405 * @tree: a node in an XML document
2406 *
2407 * Implement the XInclude substitution for the given subtree
2408 *
2409 * Returns 0 if no substitution were done, -1 if some processing failed
2410 * or the number of substitutions done.
2411 */
2412int
2413xmlXIncludeProcessTree(xmlNodePtr tree) {
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002414 return(xmlXIncludeProcessTreeFlags(tree, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00002415}
2416
Daniel Veillard7899c5c2003-11-03 12:31:38 +00002417/**
2418 * xmlXIncludeProcessNode:
2419 * @ctxt: an existing XInclude context
2420 * @node: a node in an XML document
2421 *
2422 * Implement the XInclude substitution for the given subtree reusing
2423 * the informations and data coming from the given context.
2424 *
2425 * Returns 0 if no substitution were done, -1 if some processing failed
2426 * or the number of substitutions done.
2427 */
2428int
2429xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2430 int ret = 0;
2431
2432 if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
2433 return(-1);
2434 ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
2435 if ((ret >= 0) && (ctxt->nbErrors > 0))
2436 ret = -1;
2437 return(ret);
2438}
2439
Owen Taylor3473f882001-02-23 17:55:21 +00002440#else /* !LIBXML_XINCLUDE_ENABLED */
2441#endif