blob: a58a779156d1c9f59ea4a906219365d987452f39 [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 */
Owen Taylor3473f882001-02-23 17:55:21 +000084};
85
Daniel Veillardd16df9f2001-05-23 13:44:21 +000086static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +000087xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
Owen Taylor3473f882001-02-23 17:55:21 +000088
Daniel Veillard98485322003-08-14 15:44:40 +000089
Daniel Veillardcd6ff282003-10-08 22:38:13 +000090/************************************************************************
91 * *
Daniel Veillard69d2c172003-10-09 11:46:07 +000092 * XInclude error handler *
Daniel Veillardcd6ff282003-10-08 22:38:13 +000093 * *
94 ************************************************************************/
95
Daniel Veillard98485322003-08-14 15:44:40 +000096/**
Daniel Veillardcd6ff282003-10-08 22:38:13 +000097 * xmlXIncludeErrMemory:
William M. Brack72ee48d2003-12-30 08:30:19 +000098 * @extra: extra information
Daniel Veillard98485322003-08-14 15:44:40 +000099 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000100 * Handle an out of memory condition
Daniel Veillard98485322003-08-14 15:44:40 +0000101 */
102static void
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000103xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
104 const char *extra)
Daniel Veillard98485322003-08-14 15:44:40 +0000105{
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000106 if (ctxt != NULL)
107 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000108 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000109 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
110 extra, NULL, NULL, 0, 0,
111 "Memory allocation failed : %s\n", extra);
112}
Daniel Veillard98485322003-08-14 15:44:40 +0000113
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000114/**
115 * xmlXIncludeErr:
116 * @ctxt: the XInclude context
117 * @node: the context node
118 * @msg: the error message
William M. Brack72ee48d2003-12-30 08:30:19 +0000119 * @extra: extra information
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000120 *
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000121 * Handle an XInclude error
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000122 */
123static void
124xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
125 const char *msg, const xmlChar *extra)
126{
127 if (ctxt != NULL)
128 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000129 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000130 error, XML_ERR_ERROR, NULL, 0,
131 (const char *) extra, NULL, NULL, 0, 0,
132 msg, (const char *) extra);
Daniel Veillard98485322003-08-14 15:44:40 +0000133}
134
Owen Taylor3473f882001-02-23 17:55:21 +0000135/**
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000136 * xmlXIncludeWarn:
137 * @ctxt: the XInclude context
138 * @node: the context node
139 * @msg: the error message
William M. Brack72ee48d2003-12-30 08:30:19 +0000140 * @extra: extra information
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000141 *
142 * Emit an XInclude warning.
143 */
144static void
145xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
146 const char *msg, const xmlChar *extra)
147{
148 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
149 error, XML_ERR_WARNING, NULL, 0,
150 (const char *) extra, NULL, NULL, 0, 0,
151 msg, (const char *) extra);
152}
153
154/**
155 * xmlXIncludeGetProp:
156 * @ctxt: the XInclude context
157 * @cur: the node
158 * @name: the attribute name
159 *
160 * Get an XInclude attribute
161 *
162 * Returns the value (to be freed) or NULL if not found
163 */
164static xmlChar *
165xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
166 const xmlChar *name) {
167 xmlChar *ret;
168
169 ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
170 if (ret != NULL)
171 return(ret);
172 if (ctxt->legacy != 0) {
173 ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
174 if (ret != NULL)
175 return(ret);
176 }
177 ret = xmlGetProp(cur, name);
178 return(ret);
179}
180/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000181 * xmlXIncludeFreeRef:
182 * @ref: the XInclude reference
183 *
184 * Free an XInclude reference
185 */
186static void
187xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
188 if (ref == NULL)
189 return;
190#ifdef DEBUG_XINCLUDE
191 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
192#endif
193 if (ref->doc != NULL) {
194#ifdef DEBUG_XINCLUDE
195 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
196#endif
197 xmlFreeDoc(ref->doc);
198 }
199 if (ref->URI != NULL)
200 xmlFree(ref->URI);
201 if (ref->fragment != NULL)
202 xmlFree(ref->fragment);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000203 if (ref->xptr != NULL)
204 xmlXPathFreeObject(ref->xptr);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000205 xmlFree(ref);
206}
207
208/**
209 * xmlXIncludeNewRef:
210 * @ctxt: the XInclude context
211 * @URI: the resource URI
212 *
213 * Creates a new reference within an XInclude context
214 *
215 * Returns the new set
216 */
217static xmlXIncludeRefPtr
218xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
219 xmlNodePtr ref) {
220 xmlXIncludeRefPtr ret;
221
222#ifdef DEBUG_XINCLUDE
223 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
224#endif
225 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000226 if (ret == NULL) {
227 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000228 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000229 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000230 memset(ret, 0, sizeof(xmlXIncludeRef));
231 if (URI == NULL)
232 ret->URI = NULL;
233 else
234 ret->URI = xmlStrdup(URI);
235 ret->fragment = NULL;
236 ret->ref = ref;
237 ret->doc = 0;
238 ret->count = 0;
239 ret->xml = 0;
240 ret->inc = NULL;
241 if (ctxt->incMax == 0) {
242 ctxt->incMax = 4;
243 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
244 sizeof(ctxt->incTab[0]));
245 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000246 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000247 xmlXIncludeFreeRef(ret);
248 return(NULL);
249 }
250 }
251 if (ctxt->incNr >= ctxt->incMax) {
252 ctxt->incMax *= 2;
253 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
254 ctxt->incMax * sizeof(ctxt->incTab[0]));
255 if (ctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000256 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000257 xmlXIncludeFreeRef(ret);
258 return(NULL);
259 }
260 }
261 ctxt->incTab[ctxt->incNr++] = ret;
262 return(ret);
263}
264
265/**
Owen Taylor3473f882001-02-23 17:55:21 +0000266 * xmlXIncludeNewContext:
267 * @doc: an XML Document
268 *
269 * Creates a new XInclude context
270 *
271 * Returns the new set
272 */
Daniel Veillard7899c5c2003-11-03 12:31:38 +0000273xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000274xmlXIncludeNewContext(xmlDocPtr doc) {
275 xmlXIncludeCtxtPtr ret;
276
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000277#ifdef DEBUG_XINCLUDE
278 xmlGenericError(xmlGenericErrorContext, "New context\n");
279#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000280 if (doc == NULL)
281 return(NULL);
282 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000283 if (ret == NULL) {
284 xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
285 "creating XInclude context");
Owen Taylor3473f882001-02-23 17:55:21 +0000286 return(NULL);
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000287 }
Owen Taylor3473f882001-02-23 17:55:21 +0000288 memset(ret, 0, sizeof(xmlXIncludeCtxt));
289 ret->doc = doc;
290 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000291 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000292 ret->incMax = 0;
293 ret->incTab = NULL;
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000294 ret->nbErrors = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000295 return(ret);
296}
297
298/**
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000299 * xmlXIncludeURLPush:
300 * @ctxt: the parser context
301 * @value: the url
302 *
303 * Pushes a new url on top of the url stack
304 *
305 * Returns -1 in case of error, the index in the stack otherwise
306 */
307static int
308xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
309 const xmlChar *value)
310{
311 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000312 xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
313 "detected a recursion in %s\n", value);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000314 return(-1);
315 }
316 if (ctxt->urlTab == NULL) {
317 ctxt->urlMax = 4;
318 ctxt->urlNr = 0;
319 ctxt->urlTab = (xmlChar * *) xmlMalloc(
320 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
321 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000322 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000323 return (-1);
324 }
325 }
326 if (ctxt->urlNr >= ctxt->urlMax) {
327 ctxt->urlMax *= 2;
328 ctxt->urlTab =
329 (xmlChar * *) xmlRealloc(ctxt->urlTab,
330 ctxt->urlMax *
331 sizeof(ctxt->urlTab[0]));
332 if (ctxt->urlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000333 xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000334 return (-1);
335 }
336 }
337 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
338 return (ctxt->urlNr++);
339}
340
341/**
342 * xmlXIncludeURLPop:
343 * @ctxt: the parser context
344 *
William M. Brack72ee48d2003-12-30 08:30:19 +0000345 * Pops the top URL from the URL stack
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000346 */
347static void
348xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
349{
350 xmlChar * ret;
351
352 if (ctxt->urlNr <= 0)
353 return;
354 ctxt->urlNr--;
355 if (ctxt->urlNr > 0)
356 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
357 else
358 ctxt->url = NULL;
359 ret = ctxt->urlTab[ctxt->urlNr];
360 ctxt->urlTab[ctxt->urlNr] = 0;
361 if (ret != NULL)
362 xmlFree(ret);
363}
364
365/**
Owen Taylor3473f882001-02-23 17:55:21 +0000366 * xmlXIncludeFreeContext:
367 * @ctxt: the XInclude context
368 *
369 * Free an XInclude context
370 */
Daniel Veillard7899c5c2003-11-03 12:31:38 +0000371void
Owen Taylor3473f882001-02-23 17:55:21 +0000372xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
373 int i;
374
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000375#ifdef DEBUG_XINCLUDE
376 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
377#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000378 if (ctxt == NULL)
379 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000380 while (ctxt->urlNr > 0)
381 xmlXIncludeURLPop(ctxt);
382 if (ctxt->urlTab != NULL)
383 xmlFree(ctxt->urlTab);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000384 for (i = 0;i < ctxt->incNr;i++) {
385 if (ctxt->incTab[i] != NULL)
386 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000387 }
388 for (i = 0;i < ctxt->txtNr;i++) {
389 if (ctxt->txturlTab[i] != NULL)
390 xmlFree(ctxt->txturlTab[i]);
391 }
392 if (ctxt->incTab != NULL)
393 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000394 if (ctxt->txtTab != NULL)
395 xmlFree(ctxt->txtTab);
396 if (ctxt->txturlTab != NULL)
397 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000398 xmlFree(ctxt);
399}
400
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000401/**
Daniel Veillard98485322003-08-14 15:44:40 +0000402 * xmlXIncludeParseFile:
403 * @ctxt: the XInclude context
404 * @URL: the URL or file path
405 *
William M. Brack72ee48d2003-12-30 08:30:19 +0000406 * parse a document for XInclude
Daniel Veillard98485322003-08-14 15:44:40 +0000407 */
408static xmlDocPtr
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000409xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000410 xmlDocPtr ret;
411 xmlParserCtxtPtr pctxt;
412 char *directory = NULL;
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000413 xmlParserInputPtr inputStream;
Daniel Veillard98485322003-08-14 15:44:40 +0000414
415 xmlInitParser();
416
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000417 pctxt = xmlNewParserCtxt();
Daniel Veillard98485322003-08-14 15:44:40 +0000418 if (pctxt == NULL) {
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000419 xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context");
Daniel Veillard98485322003-08-14 15:44:40 +0000420 return(NULL);
421 }
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000422 /*
William M. Brack72ee48d2003-12-30 08:30:19 +0000423 * try to ensure that new documents included are actually
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000424 * built with the same dictionary as the including document.
425 */
426 if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL) &&
427 (pctxt->dict != NULL)) {
428 xmlDictFree(pctxt->dict);
429 pctxt->dict = ctxt->doc->dict;
430 xmlDictReference(pctxt->dict);
431 }
432
433 xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
434
435 inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
436 if (inputStream == NULL) {
437 xmlFreeParserCtxt(pctxt);
438 return(NULL);
439 }
440
441 inputPush(pctxt, inputStream);
Daniel Veillard98485322003-08-14 15:44:40 +0000442
443 if ((pctxt->directory == NULL) && (directory == NULL))
444 directory = xmlParserGetDirectory(URL);
445 if ((pctxt->directory == NULL) && (directory != NULL))
446 pctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
447
448 pctxt->loadsubset = XML_DETECT_IDS;
449
450 xmlParseDocument(pctxt);
451
William M. Brack1ff42132003-12-31 14:05:15 +0000452 if (pctxt->wellFormed) {
Daniel Veillard98485322003-08-14 15:44:40 +0000453 ret = pctxt->myDoc;
William M. Brack1ff42132003-12-31 14:05:15 +0000454 xmlDictReference(pctxt->dict);
455 }
Daniel Veillard98485322003-08-14 15:44:40 +0000456 else {
457 ret = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000458 if (pctxt->myDoc != NULL) {
459 if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL) &&
460 (pctxt->myDoc->dict == ctxt->doc->dict))
461 xmlDictReference(ctxt->doc->dict);
William M. Brackb2d25dd2004-02-04 00:51:21 +0000462 else if ((pctxt->dict != NULL) &&
463 (pctxt->dict == pctxt->myDoc->dict))
464 xmlDictReference(pctxt->dict);
Daniel Veillard4773df22004-01-23 13:15:13 +0000465 xmlFreeDoc(pctxt->myDoc);
466 }
Daniel Veillard98485322003-08-14 15:44:40 +0000467 pctxt->myDoc = NULL;
468 }
469 xmlFreeParserCtxt(pctxt);
470
471 return(ret);
472}
473
474/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000475 * xmlXIncludeAddNode:
476 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000477 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000478 *
479 * Add a new node to process to an XInclude context
480 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000481static int
482xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
483 xmlXIncludeRefPtr ref;
484 xmlURIPtr uri;
485 xmlChar *URL;
486 xmlChar *fragment = NULL;
487 xmlChar *href;
488 xmlChar *parse;
489 xmlChar *base;
490 xmlChar *URI;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000491 int xml = 1, i; /* default Issue 64 */
492 int local = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000493
494
495 if (ctxt == NULL)
496 return(-1);
497 if (cur == NULL)
498 return(-1);
499
500#ifdef DEBUG_XINCLUDE
501 xmlGenericError(xmlGenericErrorContext, "Add node\n");
502#endif
503 /*
504 * read the attributes
505 */
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000506 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000507 if (href == NULL) {
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000508 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
509 if (href == NULL)
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000510 return(-1);
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000511 local = 1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000512 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000513 if (href[0] == '#')
514 local = 1;
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000515 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000516 if (parse != NULL) {
517 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
518 xml = 1;
519 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
520 xml = 0;
521 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000522 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
523 "invalid value %s for 'parse'\n", parse);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000524 if (href != NULL)
525 xmlFree(href);
526 if (parse != NULL)
527 xmlFree(parse);
528 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000529 }
530 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000531
532 /*
533 * compute the URI
534 */
535 base = xmlNodeGetBase(ctxt->doc, cur);
536 if (base == NULL) {
537 URI = xmlBuildURI(href, ctxt->doc->URL);
538 } else {
539 URI = xmlBuildURI(href, base);
540 }
541 if (URI == NULL) {
542 xmlChar *escbase;
543 xmlChar *eschref;
544 /*
545 * Some escaping may be needed
546 */
547 escbase = xmlURIEscape(base);
548 eschref = xmlURIEscape(href);
549 URI = xmlBuildURI(eschref, escbase);
550 if (escbase != NULL)
551 xmlFree(escbase);
552 if (eschref != NULL)
553 xmlFree(eschref);
554 }
555 if (parse != NULL)
556 xmlFree(parse);
557 if (href != NULL)
558 xmlFree(href);
559 if (base != NULL)
560 xmlFree(base);
561 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000562 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
563 "failed build URL\n", NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000564 return(-1);
565 }
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000566 fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000567
568 /*
569 * Check the URL and remove any fragment identifier
570 */
571 uri = xmlParseURI((const char *)URI);
572 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000573 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
574 "invalid value URI %s\n", URI);
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000575 if (fragment != NULL)
576 xmlFree(fragment);
577 xmlFree(URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000578 return(-1);
579 }
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000580
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000581 if (uri->fragment != NULL) {
Daniel Veillarde74d2e12003-12-09 11:35:37 +0000582 if (ctxt->legacy != 0) {
583 if (fragment == NULL) {
584 fragment = (xmlChar *) uri->fragment;
585 } else {
586 xmlFree(uri->fragment);
587 }
588 } else {
589 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID,
590 "Invalid fragment identifier in URI %s use the xpointer attribute\n",
591 URI);
592 if (fragment != NULL)
593 xmlFree(fragment);
594 xmlFreeURI(uri);
595 xmlFree(URI);
596 return(-1);
597 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000598 uri->fragment = NULL;
599 }
600 URL = xmlSaveUri(uri);
601 xmlFreeURI(uri);
602 xmlFree(URI);
603 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000604 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
605 "invalid value URI %s\n", URI);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000606 if (fragment != NULL)
607 xmlFree(fragment);
608 return(-1);
609 }
610
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000611 /*
612 * Check the URL against the stack for recursions
613 */
614 if (!local) {
615 for (i = 0;i < ctxt->urlNr;i++) {
616 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000617 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
618 "detected a recursion in %s\n", URL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000619 return(-1);
620 }
621 }
622 }
623
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000624 ref = xmlXIncludeNewRef(ctxt, URL, cur);
625 if (ref == NULL) {
626 return(-1);
627 }
628 ref->fragment = fragment;
629 ref->doc = NULL;
630 ref->xml = xml;
631 ref->count = 1;
632 xmlFree(URL);
633 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000634}
635
636/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000637 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000638 * @ctxt: the XInclude context
639 * @doc: the new document
640 * @url: the associated URL
641 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000642 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000643 */
644static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000645xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000646 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000647 xmlXIncludeCtxtPtr newctxt;
648 int i;
649
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000650 /*
651 * Avoid recursion in already substitued resources
652 for (i = 0;i < ctxt->urlNr;i++) {
653 if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
654 return;
655 }
656 */
657
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000658#ifdef DEBUG_XINCLUDE
659 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
660#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000661 /*
662 * Handle recursion here.
663 */
664
665 newctxt = xmlXIncludeNewContext(doc);
666 if (newctxt != NULL) {
667 /*
668 * Copy the existing document set
669 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000670 newctxt->incMax = ctxt->incMax;
671 newctxt->incNr = ctxt->incNr;
672 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
673 sizeof(newctxt->incTab[0]));
674 if (newctxt->incTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000675 xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000676 xmlFree(newctxt);
677 return;
678 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000679 /*
680 * copy the urlTab
681 */
682 newctxt->urlMax = ctxt->urlMax;
683 newctxt->urlNr = ctxt->urlNr;
684 newctxt->urlTab = ctxt->urlTab;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000685
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000686 /*
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 }
Daniel Veillard8edf1c52003-07-22 20:52:14 +0000695 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000696 for (i = 0;i < ctxt->incNr;i++) {
697 newctxt->incTab[i]->count--;
698 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000699 }
Daniel Veillardd9b72832003-03-27 14:24:00 +0000700
701 /* urlTab may have been reallocated */
702 ctxt->urlTab = newctxt->urlTab;
703 ctxt->urlMax = newctxt->urlMax;
704
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000705 newctxt->urlMax = 0;
706 newctxt->urlNr = 0;
707 newctxt->urlTab = NULL;
708
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000709 xmlXIncludeFreeContext(newctxt);
710 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000711#ifdef DEBUG_XINCLUDE
712 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
713#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000714}
715
716/**
717 * xmlXIncludeAddTxt:
718 * @ctxt: the XInclude context
719 * @txt: the new text node
720 * @url: the associated URL
721 *
722 * Add a new txtument to the list
723 */
724static void
725xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000726#ifdef DEBUG_XINCLUDE
727 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
728#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000729 if (ctxt->txtMax == 0) {
730 ctxt->txtMax = 4;
731 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
732 sizeof(ctxt->txtTab[0]));
733 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000734 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000735 return;
736 }
737 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
738 sizeof(ctxt->txturlTab[0]));
739 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000740 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000741 return;
742 }
743 }
744 if (ctxt->txtNr >= ctxt->txtMax) {
745 ctxt->txtMax *= 2;
746 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
747 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
748 if (ctxt->txtTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000749 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000750 return;
751 }
752 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000753 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000754 if (ctxt->txturlTab == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000755 xmlXIncludeErrMemory(ctxt, NULL, "processing text");
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000756 return;
757 }
758 }
759 ctxt->txtTab[ctxt->txtNr] = txt;
760 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
761 ctxt->txtNr++;
762}
763
Owen Taylor3473f882001-02-23 17:55:21 +0000764/************************************************************************
765 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000766 * Node copy with specific semantic *
767 * *
768 ************************************************************************/
769
770/**
771 * xmlXIncludeCopyNode:
772 * @ctxt: the XInclude context
773 * @target: the document target
774 * @source: the document source
775 * @elem: the element
776 *
777 * Make a copy of the node while preserving the XInclude semantic
778 * of the Infoset copy
779 */
780static xmlNodePtr
781xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
782 xmlDocPtr source, xmlNodePtr elem) {
783 xmlNodePtr result = NULL;
784
785 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
786 (elem == NULL))
787 return(NULL);
788 if (elem->type == XML_DTD_NODE)
789 return(NULL);
790 result = xmlDocCopyNode(elem, target, 1);
791 return(result);
792}
793
794/**
795 * xmlXIncludeCopyNodeList:
796 * @ctxt: the XInclude context
797 * @target: the document target
798 * @source: the document source
799 * @elem: the element list
800 *
801 * Make a copy of the node list while preserving the XInclude semantic
802 * of the Infoset copy
803 */
804static xmlNodePtr
805xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
806 xmlDocPtr source, xmlNodePtr elem) {
807 xmlNodePtr cur, res, result = NULL, last = NULL;
808
809 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
810 (elem == NULL))
811 return(NULL);
812 cur = elem;
813 while (cur != NULL) {
814 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
815 if (res != NULL) {
816 if (result == NULL) {
817 result = last = res;
818 } else {
819 last->next = res;
820 res->prev = last;
821 last = res;
822 }
823 }
824 cur = cur->next;
825 }
826 return(result);
827}
828
829/**
William M. Brack72ee48d2003-12-30 08:30:19 +0000830 * xmlXIncludeGetNthChild:
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000831 * @cur: the node
832 * @no: the child number
833 *
William M. Brack72ee48d2003-12-30 08:30:19 +0000834 * Returns the @n'th element child of @cur or NULL
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000835 */
836static xmlNodePtr
837xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
838 int i;
839 if (cur == NULL)
840 return(cur);
841 cur = cur->children;
842 for (i = 0;i <= no;cur = cur->next) {
843 if (cur == NULL)
844 return(cur);
845 if ((cur->type == XML_ELEMENT_NODE) ||
846 (cur->type == XML_DOCUMENT_NODE) ||
847 (cur->type == XML_HTML_DOCUMENT_NODE)) {
848 i++;
849 if (i == no)
850 break;
851 }
852 }
853 return(cur);
854}
855
William M. Brackf7eb7942003-12-31 07:59:17 +0000856xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000857/**
858 * xmlXIncludeCopyRange:
859 * @ctxt: the XInclude context
860 * @target: the document target
861 * @source: the document source
862 * @obj: the XPointer result from the evaluation.
863 *
864 * Build a node list tree copy of the XPointer result.
865 *
866 * Returns an xmlNodePtr list or NULL.
William M. Brack72ee48d2003-12-30 08:30:19 +0000867 * The caller has to free the node tree.
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000868 */
869static xmlNodePtr
870xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
871 xmlDocPtr source, xmlXPathObjectPtr range) {
872 /* pointers to generated nodes */
William M. Brackf7eb7942003-12-31 07:59:17 +0000873 xmlNodePtr list = NULL, last = NULL, listParent = NULL;
874 xmlNodePtr tmp, tmp2;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000875 /* pointers to traversal nodes */
876 xmlNodePtr start, cur, end;
877 int index1, index2;
William M. Brack6bdacd72004-02-07 08:53:23 +0000878 int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000879
880 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
881 (range == NULL))
882 return(NULL);
883 if (range->type != XPATH_RANGE)
884 return(NULL);
885 start = (xmlNodePtr) range->user;
886
887 if (start == NULL)
888 return(NULL);
889 end = range->user2;
890 if (end == NULL)
891 return(xmlDocCopyNode(start, target, 1));
892
893 cur = start;
894 index1 = range->index;
895 index2 = range->index2;
William M. Brackf7eb7942003-12-31 07:59:17 +0000896 /*
897 * level is depth of the current node under consideration
898 * list is the pointer to the root of the output tree
899 * listParent is a pointer to the parent of output tree (within
900 the included file) in case we need to add another level
901 * last is a pointer to the last node added to the output tree
902 * lastLevel is the depth of last (relative to the root)
903 */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000904 while (cur != NULL) {
William M. Brackf7eb7942003-12-31 07:59:17 +0000905 /*
906 * Check if our output tree needs a parent
907 */
908 if (level < 0) {
909 while (level < 0) {
910 tmp2 = xmlDocCopyNode(listParent, target, 0);
911 xmlAddChild(tmp2, list);
912 list = tmp2;
913 listParent = listParent->parent;
914 level++;
915 }
916 last = list;
917 lastLevel = 0;
918 }
919 /*
920 * Check whether we need to change our insertion point
921 */
922 while (level < lastLevel) {
923 last = last->parent;
924 lastLevel --;
925 }
William M. Brack72ee48d2003-12-30 08:30:19 +0000926 if (cur == end) { /* Are we at the end of the range? */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000927 if (cur->type == XML_TEXT_NODE) {
928 const xmlChar *content = cur->content;
929 int len;
930
931 if (content == NULL) {
932 tmp = xmlNewTextLen(NULL, 0);
933 } else {
934 len = index2;
935 if ((cur == start) && (index1 > 1)) {
936 content += (index1 - 1);
937 len -= (index1 - 1);
938 index1 = 0;
939 } else {
940 len = index2;
941 }
942 tmp = xmlNewTextLen(content, len);
943 }
944 /* single sub text node selection */
945 if (list == NULL)
946 return(tmp);
947 /* prune and return full set */
William M. Brackf7eb7942003-12-31 07:59:17 +0000948 if (level == lastLevel)
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000949 xmlAddNextSibling(last, tmp);
950 else
William M. Brackf7eb7942003-12-31 07:59:17 +0000951 xmlAddChild(last, tmp);
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000952 return(list);
William M. Brack72ee48d2003-12-30 08:30:19 +0000953 } else { /* ending node not a text node */
William M. Brack6bdacd72004-02-07 08:53:23 +0000954 endLevel = level; /* remember the level of the end node */
955 endFlag = 1;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000956 tmp = xmlDocCopyNode(cur, target, 0);
William M. Brackf7eb7942003-12-31 07:59:17 +0000957 if (list == NULL) {
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000958 list = tmp;
William M. Brackf7eb7942003-12-31 07:59:17 +0000959 listParent = cur->parent;
960 } else {
961 if (level == lastLevel)
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000962 xmlAddNextSibling(last, tmp);
William M. Brackf7eb7942003-12-31 07:59:17 +0000963 else {
964 xmlAddChild(last, tmp);
965 lastLevel = level;
966 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000967 }
William M. Brackf7eb7942003-12-31 07:59:17 +0000968 last = tmp;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000969
970 if (index2 > 1) {
971 end = xmlXIncludeGetNthChild(cur, index2 - 1);
972 index2 = 0;
973 }
974 if ((cur == start) && (index1 > 1)) {
975 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
976 index1 = 0;
William M. Brack6bdacd72004-02-07 08:53:23 +0000977 } else {
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000978 cur = cur->children;
979 }
William M. Brack6bdacd72004-02-07 08:53:23 +0000980 level++; /* increment level to show change */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000981 /*
982 * Now gather the remaining nodes from cur to end
983 */
William M. Brack6bdacd72004-02-07 08:53:23 +0000984 continue; /* while */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000985 }
William M. Brackf7eb7942003-12-31 07:59:17 +0000986 } else if (cur == start) { /* Not at the end, are we at start? */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000987 if ((cur->type == XML_TEXT_NODE) ||
988 (cur->type == XML_CDATA_SECTION_NODE)) {
989 const xmlChar *content = cur->content;
990
991 if (content == NULL) {
992 tmp = xmlNewTextLen(NULL, 0);
993 } else {
994 if (index1 > 1) {
995 content += (index1 - 1);
William M. Brack72ee48d2003-12-30 08:30:19 +0000996 index1 = 0;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000997 }
998 tmp = xmlNewText(content);
999 }
1000 last = list = tmp;
William M. Brackf7eb7942003-12-31 07:59:17 +00001001 listParent = cur->parent;
William M. Brack72ee48d2003-12-30 08:30:19 +00001002 } else { /* Not text node */
William M. Brackf7eb7942003-12-31 07:59:17 +00001003 tmp = xmlDocCopyNode(cur, target, 0);
1004 list = last = tmp;
1005 listParent = cur->parent;
William M. Brack72ee48d2003-12-30 08:30:19 +00001006 if (index1 > 1) { /* Do we need to position? */
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001007 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
William M. Brackf7eb7942003-12-31 07:59:17 +00001008 level = lastLevel = 1;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001009 index1 = 0;
1010 /*
1011 * Now gather the remaining nodes from cur to end
1012 */
1013 continue; /* while */
1014 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001015 }
1016 } else {
1017 tmp = NULL;
1018 switch (cur->type) {
1019 case XML_DTD_NODE:
1020 case XML_ELEMENT_DECL:
1021 case XML_ATTRIBUTE_DECL:
1022 case XML_ENTITY_NODE:
1023 /* Do not copy DTD informations */
1024 break;
1025 case XML_ENTITY_DECL:
1026 /* handle crossing entities -> stack needed */
1027 break;
1028 case XML_XINCLUDE_START:
1029 case XML_XINCLUDE_END:
1030 /* don't consider it part of the tree content */
1031 break;
1032 case XML_ATTRIBUTE_NODE:
1033 /* Humm, should not happen ! */
1034 break;
1035 default:
William M. Brack72ee48d2003-12-30 08:30:19 +00001036 tmp = xmlDocCopyNode(cur, target, 0);
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001037 break;
1038 }
1039 if (tmp != NULL) {
William M. Brackf7eb7942003-12-31 07:59:17 +00001040 if (level == lastLevel)
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001041 xmlAddNextSibling(last, tmp);
1042 else {
William M. Brackf7eb7942003-12-31 07:59:17 +00001043 xmlAddChild(last, tmp);
1044 lastLevel = level;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001045 }
William M. Brackf7eb7942003-12-31 07:59:17 +00001046 last = tmp;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001047 }
1048 }
1049 /*
1050 * Skip to next node in document order
1051 */
William M. Brackf7eb7942003-12-31 07:59:17 +00001052 cur = xmlXPtrAdvanceNode(cur, &level);
William M. Brack6bdacd72004-02-07 08:53:23 +00001053 if (endFlag && (level >= endLevel))
1054 break;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001055 }
1056 return(list);
1057}
1058
1059/**
1060 * xmlXIncludeBuildNodeList:
1061 * @ctxt: the XInclude context
1062 * @target: the document target
1063 * @source: the document source
1064 * @obj: the XPointer result from the evaluation.
1065 *
1066 * Build a node list tree copy of the XPointer result.
1067 * This will drop Attributes and Namespace declarations.
1068 *
1069 * Returns an xmlNodePtr list or NULL.
1070 * the caller has to free the node tree.
1071 */
1072static xmlNodePtr
1073xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
1074 xmlDocPtr source, xmlXPathObjectPtr obj) {
1075 xmlNodePtr list = NULL, last = NULL;
1076 int i;
1077
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001078 if (source == NULL)
1079 source = ctxt->doc;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001080 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
1081 (obj == NULL))
1082 return(NULL);
1083 switch (obj->type) {
1084 case XPATH_NODESET: {
1085 xmlNodeSetPtr set = obj->nodesetval;
1086 if (set == NULL)
1087 return(NULL);
1088 for (i = 0;i < set->nodeNr;i++) {
1089 if (set->nodeTab[i] == NULL)
1090 continue;
1091 switch (set->nodeTab[i]->type) {
1092 case XML_TEXT_NODE:
1093 case XML_CDATA_SECTION_NODE:
1094 case XML_ELEMENT_NODE:
1095 case XML_ENTITY_REF_NODE:
1096 case XML_ENTITY_NODE:
1097 case XML_PI_NODE:
1098 case XML_COMMENT_NODE:
1099 case XML_DOCUMENT_NODE:
1100 case XML_HTML_DOCUMENT_NODE:
1101#ifdef LIBXML_DOCB_ENABLED
1102 case XML_DOCB_DOCUMENT_NODE:
1103#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001104 case XML_XINCLUDE_END:
1105 break;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001106 case XML_XINCLUDE_START: {
1107 xmlNodePtr tmp, cur = set->nodeTab[i];
1108
1109 cur = cur->next;
1110 while (cur != NULL) {
1111 switch(cur->type) {
1112 case XML_TEXT_NODE:
1113 case XML_CDATA_SECTION_NODE:
1114 case XML_ELEMENT_NODE:
1115 case XML_ENTITY_REF_NODE:
1116 case XML_ENTITY_NODE:
1117 case XML_PI_NODE:
1118 case XML_COMMENT_NODE:
1119 tmp = xmlXIncludeCopyNode(ctxt, target,
1120 source, cur);
1121 if (last == NULL) {
1122 list = last = tmp;
1123 } else {
1124 xmlAddNextSibling(last, tmp);
1125 last = tmp;
1126 }
1127 cur = cur->next;
1128 continue;
1129 default:
1130 break;
1131 }
1132 break;
1133 }
1134 continue;
1135 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001136 case XML_ATTRIBUTE_NODE:
1137 case XML_NAMESPACE_DECL:
1138 case XML_DOCUMENT_TYPE_NODE:
1139 case XML_DOCUMENT_FRAG_NODE:
1140 case XML_NOTATION_NODE:
1141 case XML_DTD_NODE:
1142 case XML_ELEMENT_DECL:
1143 case XML_ATTRIBUTE_DECL:
1144 case XML_ENTITY_DECL:
1145 continue; /* for */
1146 }
1147 if (last == NULL)
1148 list = last = xmlXIncludeCopyNode(ctxt, target, source,
1149 set->nodeTab[i]);
1150 else {
1151 xmlAddNextSibling(last,
1152 xmlXIncludeCopyNode(ctxt, target, source,
1153 set->nodeTab[i]));
1154 if (last->next != NULL)
1155 last = last->next;
1156 }
1157 }
1158 break;
1159 }
1160 case XPATH_LOCATIONSET: {
1161 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1162 if (set == NULL)
1163 return(NULL);
1164 for (i = 0;i < set->locNr;i++) {
1165 if (last == NULL)
1166 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
1167 set->locTab[i]);
1168 else
1169 xmlAddNextSibling(last,
1170 xmlXIncludeCopyXPointer(ctxt, target, source,
1171 set->locTab[i]));
1172 if (last != NULL) {
1173 while (last->next != NULL)
1174 last = last->next;
1175 }
1176 }
1177 break;
1178 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001179#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001180 case XPATH_RANGE:
1181 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001182#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001183 case XPATH_POINT:
1184 /* points are ignored in XInclude */
1185 break;
1186 default:
1187 break;
1188 }
1189 return(list);
1190}
1191/************************************************************************
1192 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001193 * XInclude I/O handling *
1194 * *
1195 ************************************************************************/
1196
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001197typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1198typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1199struct _xmlXIncludeMergeData {
1200 xmlDocPtr doc;
1201 xmlXIncludeCtxtPtr ctxt;
1202};
1203
Owen Taylor3473f882001-02-23 17:55:21 +00001204/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001205 * xmlXIncludeMergeOneEntity:
1206 * @ent: the entity
1207 * @doc: the including doc
1208 * @nr: the entity name
1209 *
1210 * Inplements the merge of one entity
1211 */
1212static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001213xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001214 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001215 xmlEntityPtr ret, prev;
1216 xmlDocPtr doc;
1217 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001218
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001219 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001220 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001221 ctxt = data->ctxt;
1222 doc = data->doc;
1223 if ((ctxt == NULL) || (doc == NULL))
1224 return;
1225 switch (ent->etype) {
1226 case XML_INTERNAL_PARAMETER_ENTITY:
1227 case XML_EXTERNAL_PARAMETER_ENTITY:
1228 case XML_INTERNAL_PREDEFINED_ENTITY:
1229 return;
1230 case XML_INTERNAL_GENERAL_ENTITY:
1231 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1232 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1233 break;
1234 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001235 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1236 ent->SystemID, ent->content);
1237 if (ret != NULL) {
1238 if (ent->URI != NULL)
1239 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001240 } else {
1241 prev = xmlGetDocEntity(doc, ent->name);
1242 if (prev != NULL) {
1243 if (ent->etype != prev->etype)
1244 goto error;
1245
1246 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1247 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1248 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001249 } else if ((ent->ExternalID != NULL) &&
1250 (prev->ExternalID != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001251 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1252 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001253 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1254 if (!xmlStrEqual(ent->content, prev->content))
1255 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001256 } else {
1257 goto error;
1258 }
1259
1260 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001261 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001262 return;
1263error:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001264 switch (ent->etype) {
1265 case XML_INTERNAL_PARAMETER_ENTITY:
1266 case XML_EXTERNAL_PARAMETER_ENTITY:
1267 case XML_INTERNAL_PREDEFINED_ENTITY:
1268 case XML_INTERNAL_GENERAL_ENTITY:
1269 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1270 return;
1271 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1272 break;
1273 }
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001274 xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
1275 "mismatch in redefinition of entity %s\n",
1276 ent->name);
Daniel Veillard4287c572003-02-04 22:48:53 +00001277}
1278
1279/**
1280 * xmlXIncludeMergeEntities:
1281 * @ctxt: an XInclude context
1282 * @doc: the including doc
1283 * @from: the included doc
1284 *
1285 * Inplements the entity merge
1286 *
1287 * Returns 0 if merge succeeded, -1 if some processing failed
1288 */
1289static int
1290xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1291 xmlDocPtr from) {
1292 xmlNodePtr cur;
1293 xmlDtdPtr target, source;
1294
1295 if (ctxt == NULL)
1296 return(-1);
1297
1298 if ((from == NULL) || (from->intSubset == NULL))
1299 return(0);
1300
1301 target = doc->intSubset;
1302 if (target == NULL) {
1303 cur = xmlDocGetRootElement(doc);
1304 if (cur == NULL)
1305 return(-1);
1306 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1307 if (target == NULL)
1308 return(-1);
1309 }
1310
1311 source = from->intSubset;
1312 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001313 xmlXIncludeMergeData data;
1314
1315 data.ctxt = ctxt;
1316 data.doc = doc;
1317
Daniel Veillard4287c572003-02-04 22:48:53 +00001318 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001319 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001320 }
1321 source = from->extSubset;
1322 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001323 xmlXIncludeMergeData data;
1324
1325 data.ctxt = ctxt;
1326 data.doc = doc;
1327
Daniel Veillard4287c572003-02-04 22:48:53 +00001328 /*
1329 * don't duplicate existing stuff when external subsets are the same
1330 */
1331 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1332 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1333 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001334 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001335 }
1336 }
1337 return(0);
1338}
1339
1340/**
Owen Taylor3473f882001-02-23 17:55:21 +00001341 * xmlXIncludeLoadDoc:
1342 * @ctxt: the XInclude context
1343 * @url: the associated URL
1344 * @nr: the xinclude node number
1345 *
1346 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001347 *
1348 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001349 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001350static int
Owen Taylor3473f882001-02-23 17:55:21 +00001351xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1352 xmlDocPtr doc;
1353 xmlURIPtr uri;
1354 xmlChar *URL;
1355 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001356 int i = 0;
1357
1358#ifdef DEBUG_XINCLUDE
1359 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1360#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001361 /*
1362 * Check the URL and remove any fragment identifier
1363 */
1364 uri = xmlParseURI((const char *)url);
1365 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001366 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1367 XML_XINCLUDE_HREF_URI,
1368 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001369 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001370 }
1371 if (uri->fragment != NULL) {
1372 fragment = (xmlChar *) uri->fragment;
1373 uri->fragment = NULL;
1374 }
Daniel Veillardb98d0822003-12-24 11:06:25 +00001375 if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
1376 (ctxt->incTab[nr]->fragment != NULL)) {
1377 if (fragment != NULL) xmlFree(fragment);
1378 fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
1379 }
Owen Taylor3473f882001-02-23 17:55:21 +00001380 URL = xmlSaveUri(uri);
1381 xmlFreeURI(uri);
1382 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001383 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1384 XML_XINCLUDE_HREF_URI,
1385 "invalid value URI %s\n", url);
Owen Taylor3473f882001-02-23 17:55:21 +00001386 if (fragment != NULL)
1387 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001388 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001389 }
1390
1391 /*
1392 * Handling of references to the local document are done
1393 * directly through ctxt->doc.
1394 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001395 if ((URL[0] == 0) || (URL[0] == '#') ||
1396 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001397 doc = NULL;
1398 goto loaded;
1399 }
1400
1401 /*
1402 * Prevent reloading twice the document.
1403 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001404 for (i = 0; i < ctxt->incNr; i++) {
1405 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1406 (ctxt->incTab[i]->doc != NULL)) {
1407 doc = ctxt->incTab[i]->doc;
1408#ifdef DEBUG_XINCLUDE
1409 printf("Already loaded %s\n", URL);
1410#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001411 goto loaded;
1412 }
1413 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001414
Owen Taylor3473f882001-02-23 17:55:21 +00001415 /*
1416 * Load it.
1417 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001418#ifdef DEBUG_XINCLUDE
1419 printf("loading %s\n", URL);
1420#endif
Daniel Veillard98485322003-08-14 15:44:40 +00001421 doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001422 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001423 xmlFree(URL);
1424 if (fragment != NULL)
1425 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001426 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001427 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001428 ctxt->incTab[nr]->doc = doc;
Daniel Veillard98485322003-08-14 15:44:40 +00001429 for (i = nr + 1; i < ctxt->incNr; i++) {
1430 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1431 ctxt->incTab[nr]->count++;
1432#ifdef DEBUG_XINCLUDE
1433 printf("Increasing %s count since reused\n", URL);
1434#endif
1435 break;
1436 }
1437 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001438
1439 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001440 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001441 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001442 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001443
1444 /*
1445 * We don't need the DTD anymore, free up space
1446 if (doc->intSubset != NULL) {
1447 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1448 xmlFreeNode((xmlNodePtr) doc->intSubset);
1449 doc->intSubset = NULL;
1450 }
1451 if (doc->extSubset != NULL) {
1452 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1453 xmlFreeNode((xmlNodePtr) doc->extSubset);
1454 doc->extSubset = NULL;
1455 }
1456 */
1457 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001458
1459loaded:
1460 if (fragment == NULL) {
1461 /*
1462 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001463 */
1464 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001465 {
1466 /* Hopefully a DTD declaration won't be copied from
1467 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001468 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001469 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001470 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001471 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001472 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001473 }
1474#ifdef LIBXML_XPTR_ENABLED
1475 else {
Owen Taylor3473f882001-02-23 17:55:21 +00001476 /*
1477 * Computes the XPointer expression and make a copy used
1478 * as the replacement copy.
1479 */
1480 xmlXPathObjectPtr xptr;
1481 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001482 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001483
1484 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001485 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1486 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001487 } else {
1488 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1489 }
1490 if (xptrctxt == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001491 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1492 XML_XINCLUDE_XPTR_FAILED,
Daniel Veillarda152c4d2003-11-19 16:24:26 +00001493 "could not create XPointer context\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001494 xmlFree(URL);
1495 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001496 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001497 }
1498 xptr = xmlXPtrEval(fragment, xptrctxt);
1499 if (xptr == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001500 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1501 XML_XINCLUDE_XPTR_FAILED,
1502 "XPointer evaluation failed: #%s\n",
1503 fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001504 xmlXPathFreeContext(xptrctxt);
1505 xmlFree(URL);
1506 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001507 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001508 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001509 switch (xptr->type) {
1510 case XPATH_UNDEFINED:
1511 case XPATH_BOOLEAN:
1512 case XPATH_NUMBER:
1513 case XPATH_STRING:
1514 case XPATH_POINT:
1515 case XPATH_USERS:
1516 case XPATH_XSLT_TREE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001517 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1518 XML_XINCLUDE_XPTR_RESULT,
1519 "XPointer is not a range: #%s\n",
1520 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001521 xmlXPathFreeContext(xptrctxt);
1522 xmlFree(URL);
1523 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001524 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001525 case XPATH_NODESET:
Daniel Veillard798ae542003-11-03 17:13:52 +00001526 if ((xptr->nodesetval == NULL) ||
1527 (xptr->nodesetval->nodeNr <= 0)) {
1528 xmlXPathFreeContext(xptrctxt);
1529 xmlFree(URL);
1530 xmlFree(fragment);
1531 return(-1);
1532 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001533 case XPATH_RANGE:
1534 case XPATH_LOCATIONSET:
1535 break;
1536 }
1537 set = xptr->nodesetval;
1538 if (set != NULL) {
1539 for (i = 0;i < set->nodeNr;i++) {
1540 if (set->nodeTab[i] == NULL)
1541 continue;
1542 switch (set->nodeTab[i]->type) {
1543 case XML_TEXT_NODE:
1544 case XML_CDATA_SECTION_NODE:
1545 case XML_ELEMENT_NODE:
1546 case XML_ENTITY_REF_NODE:
1547 case XML_ENTITY_NODE:
1548 case XML_PI_NODE:
1549 case XML_COMMENT_NODE:
1550 case XML_DOCUMENT_NODE:
1551 case XML_HTML_DOCUMENT_NODE:
1552#ifdef LIBXML_DOCB_ENABLED
1553 case XML_DOCB_DOCUMENT_NODE:
1554#endif
1555 continue;
1556 case XML_ATTRIBUTE_NODE:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001557 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1558 XML_XINCLUDE_XPTR_RESULT,
1559 "XPointer selects an attribute: #%s\n",
1560 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001561 set->nodeTab[i] = NULL;
1562 continue;
1563 case XML_NAMESPACE_DECL:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001564 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1565 XML_XINCLUDE_XPTR_RESULT,
1566 "XPointer selects a namespace: #%s\n",
1567 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001568 set->nodeTab[i] = NULL;
1569 continue;
1570 case XML_DOCUMENT_TYPE_NODE:
1571 case XML_DOCUMENT_FRAG_NODE:
1572 case XML_NOTATION_NODE:
1573 case XML_DTD_NODE:
1574 case XML_ELEMENT_DECL:
1575 case XML_ATTRIBUTE_DECL:
1576 case XML_ENTITY_DECL:
1577 case XML_XINCLUDE_START:
1578 case XML_XINCLUDE_END:
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001579 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1580 XML_XINCLUDE_XPTR_RESULT,
1581 "XPointer selects unexpected nodes: #%s\n",
1582 fragment);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001583 set->nodeTab[i] = NULL;
1584 set->nodeTab[i] = NULL;
1585 continue; /* for */
1586 }
1587 }
1588 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001589 if (doc == NULL) {
1590 ctxt->incTab[nr]->xptr = xptr;
1591 ctxt->incTab[nr]->inc = NULL;
1592 } else {
1593 ctxt->incTab[nr]->inc =
1594 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1595 xmlXPathFreeObject(xptr);
1596 }
Owen Taylor3473f882001-02-23 17:55:21 +00001597 xmlXPathFreeContext(xptrctxt);
1598 xmlFree(fragment);
1599 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001600#endif
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001601
1602 /*
1603 * Do the xml:base fixup if needed
1604 */
1605 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1606 xmlNodePtr node;
1607
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001608 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001609 while (node != NULL) {
1610 if (node->type == XML_ELEMENT_NODE)
1611 xmlNodeSetBase(node, URL);
1612 node = node->next;
1613 }
1614 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001615 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1616 (ctxt->incTab[nr]->count <= 1)) {
1617#ifdef DEBUG_XINCLUDE
1618 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1619#endif
1620 xmlFreeDoc(ctxt->incTab[nr]->doc);
1621 ctxt->incTab[nr]->doc = NULL;
1622 }
Owen Taylor3473f882001-02-23 17:55:21 +00001623 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001624 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001625}
1626
1627/**
1628 * xmlXIncludeLoadTxt:
1629 * @ctxt: the XInclude context
1630 * @url: the associated URL
1631 * @nr: the xinclude node number
1632 *
1633 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001634 *
1635 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001636 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001637static int
Owen Taylor3473f882001-02-23 17:55:21 +00001638xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1639 xmlParserInputBufferPtr buf;
1640 xmlNodePtr node;
1641 xmlURIPtr uri;
1642 xmlChar *URL;
1643 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001644 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001645 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001646
Owen Taylor3473f882001-02-23 17:55:21 +00001647 /*
1648 * Check the URL and remove any fragment identifier
1649 */
1650 uri = xmlParseURI((const char *)url);
1651 if (uri == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001652 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1653 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001654 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001655 }
1656 if (uri->fragment != NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001657 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1658 "fragment identifier forbidden for text: %s\n",
1659 (const xmlChar *) uri->fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00001660 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001661 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001662 }
1663 URL = xmlSaveUri(uri);
1664 xmlFreeURI(uri);
1665 if (URL == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001666 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1667 "invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001668 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001669 }
1670
1671 /*
1672 * Handling of references to the local document are done
1673 * directly through ctxt->doc.
1674 */
1675 if (URL[0] == 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001676 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1677 XML_XINCLUDE_TEXT_DOCUMENT,
1678 "text serialization of document not available\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001679 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001680 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001681 }
1682
1683 /*
1684 * Prevent reloading twice the document.
1685 */
1686 for (i = 0; i < ctxt->txtNr; i++) {
1687 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1688 node = xmlCopyNode(ctxt->txtTab[i], 1);
1689 goto loaded;
1690 }
1691 }
1692 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001693 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001694 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001695 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1696 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1697 }
1698 if (encoding != NULL) {
1699 /*
1700 * TODO: we should not have to remap to the xmlCharEncoding
1701 * predefined set, a better interface than
1702 * xmlParserInputBufferCreateFilename should allow any
1703 * encoding supported by iconv
1704 */
1705 enc = xmlParseCharEncoding((const char *) encoding);
1706 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001707 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1708 XML_XINCLUDE_UNKNOWN_ENCODING,
1709 "encoding %s not supported\n", encoding);
Daniel Veillardd076a202002-11-20 13:28:31 +00001710 xmlFree(encoding);
1711 xmlFree(URL);
1712 return(-1);
1713 }
1714 xmlFree(encoding);
1715 }
1716
1717 /*
1718 * Load it.
1719 */
1720 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001721 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001722 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001723 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001724 }
1725 node = xmlNewText(NULL);
1726
1727 /*
1728 * Scan all chars from the resource and add the to the node
1729 */
1730 while (xmlParserInputBufferRead(buf, 128) > 0) {
1731 int len;
1732 const xmlChar *content;
1733
1734 content = xmlBufferContent(buf->buffer);
1735 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001736 for (i = 0;i < len;) {
1737 int cur;
1738 int l;
1739
1740 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1741 if (!IS_CHAR(cur)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001742 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1743 XML_XINCLUDE_INVALID_CHAR,
1744 "%s contains invalid char\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001745 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001746 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001747 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001748 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001749 }
1750 xmlBufferShrink(buf->buffer, len);
1751 }
1752 xmlFreeParserInputBuffer(buf);
1753 xmlXIncludeAddTxt(ctxt, node, URL);
1754
1755loaded:
1756 /*
1757 * Add the element as the replacement copy.
1758 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001759 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001760 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001761 return(0);
1762}
1763
1764/**
1765 * xmlXIncludeLoadFallback:
1766 * @ctxt: the XInclude context
1767 * @fallback: the fallback node
1768 * @nr: the xinclude node number
1769 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001770 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001771 * in the XInclude context
1772 *
1773 * Returns 0 in case of success, -1 in case of failure
1774 */
1775static int
1776xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
William M. Brackaae10522004-01-02 14:59:41 +00001777 xmlXIncludeCtxtPtr newctxt;
1778 int ret = 0;
1779
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001780 if ((fallback == NULL) || (ctxt == NULL))
1781 return(-1);
William M. Brackef245fd2004-02-06 09:33:59 +00001782 if (fallback->children != NULL) {
1783 /*
1784 * It's possible that the fallback also has 'includes'
1785 * (Bug 129969), so we re-process the fallback just in case
1786 */
1787 newctxt = xmlXIncludeNewContext(ctxt->doc);
1788 if (newctxt == NULL)
1789 return (-1);
1790 xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
1791 ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
1792 if ((ret >=0) && (ctxt->nbErrors > 0))
1793 ret = -1;
1794 xmlXIncludeFreeContext(newctxt);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001795
William M. Brackef245fd2004-02-06 09:33:59 +00001796 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
1797 } else {
1798 ctxt->incTab[nr]->inc = NULL;
William M. Brack95af5942004-02-08 04:12:49 +00001799 ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */
William M. Brackef245fd2004-02-06 09:33:59 +00001800 }
William M. Brackaae10522004-01-02 14:59:41 +00001801 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001802}
1803
1804/************************************************************************
1805 * *
1806 * XInclude Processing *
1807 * *
1808 ************************************************************************/
1809
1810/**
1811 * xmlXIncludePreProcessNode:
1812 * @ctxt: an XInclude context
1813 * @node: an XInclude node
1814 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001815 * Implement the XInclude preprocessing, currently just adding the element
1816 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001817 *
1818 * Returns the result list or NULL in case of error
1819 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001820static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001821xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1822 xmlXIncludeAddNode(ctxt, node);
1823 return(0);
1824}
1825
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001826/**
Owen Taylor3473f882001-02-23 17:55:21 +00001827 * xmlXIncludeLoadNode:
1828 * @ctxt: an XInclude context
1829 * @nr: the node number
1830 *
1831 * Find and load the infoset replacement for the given node.
1832 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001833 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001834 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001835static int
Owen Taylor3473f882001-02-23 17:55:21 +00001836xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1837 xmlNodePtr cur;
1838 xmlChar *href;
1839 xmlChar *parse;
1840 xmlChar *base;
1841 xmlChar *URI;
1842 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001843 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001844
1845 if (ctxt == NULL)
1846 return(-1);
1847 if ((nr < 0) || (nr >= ctxt->incNr))
1848 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001849 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001850 if (cur == NULL)
1851 return(-1);
1852
Owen Taylor3473f882001-02-23 17:55:21 +00001853 /*
1854 * read the attributes
1855 */
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001856 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
Owen Taylor3473f882001-02-23 17:55:21 +00001857 if (href == NULL) {
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001858 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
1859 if (href == NULL)
1860 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001861 }
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001862 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
Owen Taylor3473f882001-02-23 17:55:21 +00001863 if (parse != NULL) {
1864 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1865 xml = 1;
1866 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1867 xml = 0;
1868 else {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001869 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1870 XML_XINCLUDE_PARSE_VALUE,
1871 "invalid value %s for 'parse'\n", parse);
Owen Taylor3473f882001-02-23 17:55:21 +00001872 if (href != NULL)
1873 xmlFree(href);
1874 if (parse != NULL)
1875 xmlFree(parse);
1876 return(-1);
1877 }
1878 }
1879
1880 /*
1881 * compute the URI
1882 */
1883 base = xmlNodeGetBase(ctxt->doc, cur);
1884 if (base == NULL) {
1885 URI = xmlBuildURI(href, ctxt->doc->URL);
1886 } else {
1887 URI = xmlBuildURI(href, base);
1888 }
1889 if (URI == NULL) {
1890 xmlChar *escbase;
1891 xmlChar *eschref;
1892 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001893 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001894 */
1895 escbase = xmlURIEscape(base);
1896 eschref = xmlURIEscape(href);
1897 URI = xmlBuildURI(eschref, escbase);
1898 if (escbase != NULL)
1899 xmlFree(escbase);
1900 if (eschref != NULL)
1901 xmlFree(eschref);
1902 }
1903 if (URI == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001904 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1905 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001906 if (parse != NULL)
1907 xmlFree(parse);
1908 if (href != NULL)
1909 xmlFree(href);
1910 if (base != NULL)
1911 xmlFree(base);
1912 return(-1);
1913 }
1914#ifdef DEBUG_XINCLUDE
1915 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1916 xml ? "xml": "text");
1917 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1918#endif
1919
1920 /*
1921 * Cleanup
1922 */
1923 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001924 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001925 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1926 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001927 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1928 }
1929 if (ret < 0) {
1930 xmlNodePtr children;
1931
1932 /*
1933 * Time to try a fallback if availble
1934 */
1935#ifdef DEBUG_XINCLUDE
1936 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1937#endif
1938 children = cur->children;
1939 while (children != NULL) {
1940 if ((children->type == XML_ELEMENT_NODE) &&
1941 (children->ns != NULL) &&
1942 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
Daniel Veillardb5fa0202003-12-08 17:41:29 +00001943 ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
1944 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001945 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
William M. Brack1ff42132003-12-31 14:05:15 +00001946 if (ret == 0)
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001947 break;
1948 }
1949 children = children->next;
1950 }
1951 }
1952 if (ret < 0) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00001953 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1954 XML_XINCLUDE_NO_FALLBACK,
1955 "could not load %s, and no fallback was found\n",
1956 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001957 }
1958
1959 /*
1960 * Cleanup
1961 */
1962 if (URI != NULL)
1963 xmlFree(URI);
1964 if (parse != NULL)
1965 xmlFree(parse);
1966 if (href != NULL)
1967 xmlFree(href);
1968 if (base != NULL)
1969 xmlFree(base);
1970 return(0);
1971}
1972
1973/**
1974 * xmlXIncludeIncludeNode:
1975 * @ctxt: an XInclude context
1976 * @nr: the node number
1977 *
1978 * Inplement the infoset replacement for the given node
1979 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001980 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001981 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001982static int
Owen Taylor3473f882001-02-23 17:55:21 +00001983xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001984 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001985
1986 if (ctxt == NULL)
1987 return(-1);
1988 if ((nr < 0) || (nr >= ctxt->incNr))
1989 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001990 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001991 if (cur == NULL)
1992 return(-1);
1993
1994 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001995 * If we stored an XPointer a late computation may be needed
1996 */
1997 if ((ctxt->incTab[nr]->inc == NULL) &&
1998 (ctxt->incTab[nr]->xptr != NULL)) {
1999 ctxt->incTab[nr]->inc =
2000 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
2001 ctxt->incTab[nr]->xptr);
2002 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
2003 ctxt->incTab[nr]->xptr = NULL;
2004 }
2005 list = ctxt->incTab[nr]->inc;
2006 ctxt->incTab[nr]->inc = NULL;
2007
2008 /*
2009 * Check against the risk of generating a multi-rooted document
2010 */
2011 if ((cur->parent != NULL) &&
2012 (cur->parent->type != XML_ELEMENT_NODE)) {
2013 int nb_elem = 0;
2014
2015 tmp = list;
2016 while (tmp != NULL) {
2017 if (tmp->type == XML_ELEMENT_NODE)
2018 nb_elem++;
2019 tmp = tmp->next;
2020 }
2021 if (nb_elem > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002022 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2023 XML_XINCLUDE_MULTIPLE_ROOT,
2024 "XInclude error: would result in multiple root nodes\n",
2025 NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002026 return(-1);
2027 }
2028 }
2029
2030 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002031 * Change the current node as an XInclude start one, and add an
2032 * entity end one
2033 */
2034 cur->type = XML_XINCLUDE_START;
2035 end = xmlNewNode(cur->ns, cur->name);
2036 if (end == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002037 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED,
2038 "failed to build node\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002039 return(-1);
2040 }
2041 end->type = XML_XINCLUDE_END;
2042 xmlAddNextSibling(cur, end);
2043
2044 /*
2045 * Add the list of nodes
2046 */
Owen Taylor3473f882001-02-23 17:55:21 +00002047 while (list != NULL) {
2048 cur = list;
2049 list = list->next;
2050
2051 xmlAddPrevSibling(end, cur);
2052 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002053
2054
Owen Taylor3473f882001-02-23 17:55:21 +00002055 return(0);
2056}
2057
2058/**
2059 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002060 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002061 * @node: an XInclude node
2062 *
2063 * test if the node is an XInclude node
2064 *
2065 * Returns 1 true, 0 otherwise
2066 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002067static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002068xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002069 if (node == NULL)
2070 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002071 if (node->type != XML_ELEMENT_NODE)
2072 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002073 if (node->ns == NULL)
2074 return(0);
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002075 if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
2076 (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
2077 if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
2078 if (ctxt->legacy == 0) {
2079 xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
2080 "Deprecated XInclude namespace found, use %s",
2081 XINCLUDE_NS);
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002082 ctxt->legacy = 1;
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002083 }
2084 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002085 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2086 xmlNodePtr child = node->children;
2087 int nb_fallback = 0;
2088
2089 while (child != NULL) {
2090 if ((child->type == XML_ELEMENT_NODE) &&
2091 (child->ns != NULL) &&
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002092 ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
2093 (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002094 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002095 xmlXIncludeErr(ctxt, node,
2096 XML_XINCLUDE_INCLUDE_IN_INCLUDE,
2097 "%s has an 'include' child\n",
2098 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002099 return(0);
2100 }
2101 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2102 nb_fallback++;
2103 }
2104 }
2105 child = child->next;
2106 }
2107 if (nb_fallback > 1) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002108 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
2109 "%s has multiple fallback children\n",
2110 XINCLUDE_NODE);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002111 return(0);
2112 }
2113 return(1);
2114 }
2115 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2116 if ((node->parent == NULL) ||
2117 (node->parent->type != XML_ELEMENT_NODE) ||
2118 (node->parent->ns == NULL) ||
Daniel Veillardb5fa0202003-12-08 17:41:29 +00002119 ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
2120 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002121 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00002122 xmlXIncludeErr(ctxt, node,
2123 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
2124 "%s is not the child of an 'include'\n",
2125 XINCLUDE_FALLBACK);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002126 }
2127 }
2128 }
Owen Taylor3473f882001-02-23 17:55:21 +00002129 return(0);
2130}
2131
2132/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002133 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002134 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002135 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002136 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00002137 *
2138 * Implement the XInclude substitution on the XML document @doc
2139 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002140 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002141 * or the number of substitutions done.
2142 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002143static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002144xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00002145 xmlNodePtr cur;
2146 int ret = 0;
2147 int i;
2148
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002149 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002150 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002151 if (ctxt == NULL)
2152 return(-1);
2153
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002154 if (doc->URL != NULL) {
2155 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2156 if (ret < 0)
2157 return(-1);
2158 }
2159
Owen Taylor3473f882001-02-23 17:55:21 +00002160 /*
2161 * First phase: lookup the elements in the document
2162 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002163 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002164 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002165 xmlXIncludePreProcessNode(ctxt, cur);
2166 while (cur != NULL) {
2167 /* TODO: need to work on entities -> stack */
2168 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002169 (cur->children->type != XML_ENTITY_DECL) &&
2170 (cur->children->type != XML_XINCLUDE_START) &&
2171 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002172 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002173 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002174 xmlXIncludePreProcessNode(ctxt, cur);
2175 } else if (cur->next != NULL) {
2176 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002177 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002178 xmlXIncludePreProcessNode(ctxt, cur);
2179 } else {
2180 do {
2181 cur = cur->parent;
2182 if (cur == NULL) break; /* do */
2183 if (cur->next != NULL) {
2184 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002185 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002186 xmlXIncludePreProcessNode(ctxt, cur);
2187 break; /* do */
2188 }
2189 } while (cur != NULL);
2190 }
2191 }
2192
2193 /*
2194 * Second Phase : collect the infosets fragments
2195 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002196 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002197 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002198 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002199 }
2200
2201 /*
2202 * Third phase: extend the original document infoset.
William M. Brack6b1a28d2004-02-06 11:24:44 +00002203 *
2204 * Originally we bypassed the inclusion if there were any errors
2205 * encountered on any of the XIncludes. A bug was raised (bug
2206 * 132588) requesting that we output the XIncludes without error,
2207 * so the check for inc!=NULL || xptr!=NULL was put in. This may
2208 * give some other problems in the future, but for now it seems to
2209 * work ok.
2210 *
Owen Taylor3473f882001-02-23 17:55:21 +00002211 */
William M. Brack6b1a28d2004-02-06 11:24:44 +00002212 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
William M. Brack95af5942004-02-08 04:12:49 +00002213 if ((ctxt->incTab[i]->inc != NULL) ||
2214 (ctxt->incTab[i]->xptr != NULL) ||
2215 (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002216 xmlXIncludeIncludeNode(ctxt, i);
Owen Taylor3473f882001-02-23 17:55:21 +00002217 }
2218
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002219 if (doc->URL != NULL)
2220 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002221 return(ret);
2222}
2223
2224/**
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002225 * xmlXIncludeSetFlags:
2226 * @ctxt: an XInclude processing context
2227 * @flags: a set of xmlParserOption used for parsing XML includes
2228 *
2229 * Set the flags used for further processing of XML resources.
2230 *
2231 * Returns 0 in case of success and -1 in case of error.
2232 */
2233int
2234xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
2235 if (ctxt == NULL)
2236 return(-1);
2237 ctxt->parseFlags = flags;
2238 return(0);
2239}
2240
2241/**
2242 * xmlXIncludeProcessFlags:
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002243 * @doc: an XML document
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002244 * @flags: a set of xmlParserOption used for parsing XML includes
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002245 *
2246 * Implement the XInclude substitution on the XML document @doc
2247 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002248 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002249 * or the number of substitutions done.
2250 */
2251int
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002252xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002253 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002254 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002255 int ret = 0;
2256
2257 if (doc == NULL)
2258 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002259 tree = xmlDocGetRootElement(doc);
2260 if (tree == NULL)
2261 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002262 ctxt = xmlXIncludeNewContext(doc);
2263 if (ctxt == NULL)
2264 return(-1);
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002265 xmlXIncludeSetFlags(ctxt, flags);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002266 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2267 if ((ret >= 0) && (ctxt->nbErrors > 0))
2268 ret = -1;
2269
2270 xmlXIncludeFreeContext(ctxt);
2271 return(ret);
2272}
2273
2274/**
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002275 * xmlXIncludeProcess:
2276 * @doc: an XML document
2277 *
2278 * Implement the XInclude substitution on the XML document @doc
2279 *
2280 * Returns 0 if no substitution were done, -1 if some processing failed
2281 * or the number of substitutions done.
2282 */
2283int
2284xmlXIncludeProcess(xmlDocPtr doc) {
2285 return(xmlXIncludeProcessFlags(doc, 0));
2286}
2287
2288/**
2289 * xmlXIncludeProcessTreeFlags:
2290 * @tree: a node in an XML document
2291 * @flags: a set of xmlParserOption used for parsing XML includes
2292 *
2293 * Implement the XInclude substitution for the given subtree
2294 *
2295 * Returns 0 if no substitution were done, -1 if some processing failed
2296 * or the number of substitutions done.
2297 */
2298int
2299xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
2300 xmlXIncludeCtxtPtr ctxt;
2301 int ret = 0;
2302
2303 if ((tree == NULL) || (tree->doc == NULL))
2304 return(-1);
2305 ctxt = xmlXIncludeNewContext(tree->doc);
2306 if (ctxt == NULL)
2307 return(-1);
2308 xmlXIncludeSetFlags(ctxt, flags);
2309 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
2310 if ((ret >= 0) && (ctxt->nbErrors > 0))
2311 ret = -1;
2312
2313 xmlXIncludeFreeContext(ctxt);
2314 return(ret);
2315}
2316
2317/**
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002318 * xmlXIncludeProcessTree:
2319 * @tree: a node in an XML document
2320 *
2321 * Implement the XInclude substitution for the given subtree
2322 *
2323 * Returns 0 if no substitution were done, -1 if some processing failed
2324 * or the number of substitutions done.
2325 */
2326int
2327xmlXIncludeProcessTree(xmlNodePtr tree) {
Daniel Veillarde74d2e12003-12-09 11:35:37 +00002328 return(xmlXIncludeProcessTreeFlags(tree, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00002329}
2330
Daniel Veillard7899c5c2003-11-03 12:31:38 +00002331/**
2332 * xmlXIncludeProcessNode:
2333 * @ctxt: an existing XInclude context
2334 * @node: a node in an XML document
2335 *
2336 * Implement the XInclude substitution for the given subtree reusing
2337 * the informations and data coming from the given context.
2338 *
2339 * Returns 0 if no substitution were done, -1 if some processing failed
2340 * or the number of substitutions done.
2341 */
2342int
2343xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2344 int ret = 0;
2345
2346 if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
2347 return(-1);
2348 ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
2349 if ((ret >= 0) && (ctxt->nbErrors > 0))
2350 ret = -1;
2351 return(ret);
2352}
2353
Owen Taylor3473f882001-02-23 17:55:21 +00002354#else /* !LIBXML_XINCLUDE_ENABLED */
2355#endif