blob: 9f1a45b1723415c4ffc4bb96072161249f14919a [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xinclude.c : Code to implement XInclude processing
3 *
Daniel Veillardbbd22452001-05-23 12:02:27 +00004 * World Wide Web Consortium W3C Last Call Working Draft 16 May 2001
5 * http://www.w3.org/TR/2001/WD-xinclude-20010516/
Owen Taylor3473f882001-02-23 17:55:21 +00006 *
7 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 */
11
Daniel Veillard34ce8be2002-03-18 19:37:11 +000012#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000013#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000014
Owen Taylor3473f882001-02-23 17:55:21 +000015#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/tree.h>
18#include <libxml/parser.h>
19#include <libxml/uri.h>
20#include <libxml/xpointer.h>
21#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <libxml/xmlerror.h>
Daniel Veillardd076a202002-11-20 13:28:31 +000023#include <libxml/encoding.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000024#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000025
26#ifdef LIBXML_XINCLUDE_ENABLED
27#include <libxml/xinclude.h>
28
Daniel Veillardbbd22452001-05-23 12:02:27 +000029#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
Owen Taylor3473f882001-02-23 17:55:21 +000030#define XINCLUDE_NODE (const xmlChar *) "include"
Daniel Veillard58e44c92002-08-02 22:19:49 +000031#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
Owen Taylor3473f882001-02-23 17:55:21 +000032#define XINCLUDE_HREF (const xmlChar *) "href"
33#define XINCLUDE_PARSE (const xmlChar *) "parse"
34#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
35#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
Daniel Veillardd076a202002-11-20 13:28:31 +000036#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
Owen Taylor3473f882001-02-23 17:55:21 +000037
Daniel Veillardf4b4f982003-02-13 11:02:08 +000038#define XINCLUDE_MAX_DEPTH 40
39
Daniel Veillard98485322003-08-14 15:44:40 +000040/* #define DEBUG_XINCLUDE */
Daniel Veillard017b1082001-06-21 11:20:21 +000041#ifdef DEBUG_XINCLUDE
42#ifdef LIBXML_DEBUG_ENABLED
43#include <libxml/debugXML.h>
44#endif
45#endif
Owen Taylor3473f882001-02-23 17:55:21 +000046
47/************************************************************************
48 * *
49 * XInclude contexts handling *
50 * *
51 ************************************************************************/
52
53/*
54 * An XInclude context
55 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000056typedef xmlChar *xmlURL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +000057
58typedef struct _xmlXIncludeRef xmlXIncludeRef;
59typedef xmlXIncludeRef *xmlXIncludeRefPtr;
60struct _xmlXIncludeRef {
61 xmlChar *URI; /* the rully resolved resource URL */
62 xmlChar *fragment; /* the fragment in the URI */
63 xmlDocPtr doc; /* the parsed document */
64 xmlNodePtr ref; /* the node making the reference in the source */
65 xmlNodePtr inc; /* the included copy */
66 int xml; /* xml or txt */
67 int count; /* how many refs use that specific doc */
Daniel Veillardf4b4f982003-02-13 11:02:08 +000068 xmlXPathObjectPtr xptr; /* the xpointer if needed */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000069};
70
Owen Taylor3473f882001-02-23 17:55:21 +000071typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
72typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
73struct _xmlXIncludeCtxt {
74 xmlDocPtr doc; /* the source document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000075 int incBase; /* the first include for this document */
Owen Taylor3473f882001-02-23 17:55:21 +000076 int incNr; /* number of includes */
77 int incMax; /* size of includes tab */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000078 xmlXIncludeRefPtr *incTab; /* array of included references */
79
Owen Taylor3473f882001-02-23 17:55:21 +000080 int txtNr; /* number of unparsed documents */
81 int txtMax; /* size of unparsed documents tab */
82 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000083 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Daniel Veillardd581b7e2003-02-11 18:03:05 +000084
Daniel Veillardf4b4f982003-02-13 11:02:08 +000085 xmlChar * url; /* the current URL processed */
86 int urlNr; /* number of url stacked */
87 int urlMax; /* size of url stack */
88 xmlChar * *urlTab; /* url stack */
89
Daniel Veillardd581b7e2003-02-11 18:03:05 +000090 int nbErrors; /* the number of errors detected */
Owen Taylor3473f882001-02-23 17:55:21 +000091};
92
Daniel Veillardd16df9f2001-05-23 13:44:21 +000093static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +000094xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
Owen Taylor3473f882001-02-23 17:55:21 +000095
Daniel Veillard98485322003-08-14 15:44:40 +000096
97/**
98 * xmlXIncludeErrorContext:
99 * @ctxt: the XInclude context
100 * @node: the node
101 *
102 * Dump informations about the kocation of the error in the instance
103 */
104static void
105xmlXIncludeErrorContext(xmlXIncludeCtxtPtr ctxt ATTRIBUTE_UNUSED,
106 xmlNodePtr node)
107{
108 int line = 0;
109 const xmlChar *file = NULL;
110 const xmlChar *name = NULL;
111 const char *type = "error";
112
113 if (node == NULL) {
114 return;
115 }
116 if (node != NULL) {
117 if ((node->type == XML_DOCUMENT_NODE) ||
118 (node->type == XML_HTML_DOCUMENT_NODE)) {
119 xmlDocPtr doc = (xmlDocPtr) node;
120
121 file = doc->URL;
122 } else {
123 /*
124 * Try to find contextual informations to report
125 */
126 if (node->type == XML_ELEMENT_NODE) {
127 line = (long) node->content;
128 } else if ((node->prev != NULL) &&
129 (node->prev->type == XML_ELEMENT_NODE)) {
130 line = (long) node->prev->content;
131 } else if ((node->parent != NULL) &&
132 (node->parent->type == XML_ELEMENT_NODE)) {
133 line = (long) node->parent->content;
134 }
135 if ((node->doc != NULL) && (node->doc->URL != NULL))
136 file = node->doc->URL;
137 if (node->name != NULL)
138 name = node->name;
139 }
140 }
141
142 type = "XInclude :";
143
144 if ((file != NULL) && (line != 0) && (name != NULL))
145 xmlGenericError(xmlGenericErrorContext,
146 "%s: file %s line %d element %s\n", type, file,
147 line, name);
148 else if ((file != NULL) && (name != NULL))
149 xmlGenericError(xmlGenericErrorContext, "%s: file %s element %s\n",
150 type, file, name);
151 else if ((file != NULL) && (line != 0))
152 xmlGenericError(xmlGenericErrorContext, "%s: file %s line %d\n",
153 type, file, line);
154 else if (file != NULL)
155 xmlGenericError(xmlGenericErrorContext, "%s: file %s\n", type,
156 file);
157 else if (name != NULL)
158 xmlGenericError(xmlGenericErrorContext, "%s: element %s\n", type,
159 name);
160 else
161 xmlGenericError(xmlGenericErrorContext, "%s\n", type);
162}
163
Owen Taylor3473f882001-02-23 17:55:21 +0000164/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000165 * xmlXIncludeFreeRef:
166 * @ref: the XInclude reference
167 *
168 * Free an XInclude reference
169 */
170static void
171xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
172 if (ref == NULL)
173 return;
174#ifdef DEBUG_XINCLUDE
175 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
176#endif
177 if (ref->doc != NULL) {
178#ifdef DEBUG_XINCLUDE
179 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
180#endif
181 xmlFreeDoc(ref->doc);
182 }
183 if (ref->URI != NULL)
184 xmlFree(ref->URI);
185 if (ref->fragment != NULL)
186 xmlFree(ref->fragment);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000187 if (ref->xptr != NULL)
188 xmlXPathFreeObject(ref->xptr);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000189 xmlFree(ref);
190}
191
192/**
193 * xmlXIncludeNewRef:
194 * @ctxt: the XInclude context
195 * @URI: the resource URI
196 *
197 * Creates a new reference within an XInclude context
198 *
199 * Returns the new set
200 */
201static xmlXIncludeRefPtr
202xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
203 xmlNodePtr ref) {
204 xmlXIncludeRefPtr ret;
205
206#ifdef DEBUG_XINCLUDE
207 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
208#endif
209 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
210 if (ret == NULL)
211 return(NULL);
212 memset(ret, 0, sizeof(xmlXIncludeRef));
213 if (URI == NULL)
214 ret->URI = NULL;
215 else
216 ret->URI = xmlStrdup(URI);
217 ret->fragment = NULL;
218 ret->ref = ref;
219 ret->doc = 0;
220 ret->count = 0;
221 ret->xml = 0;
222 ret->inc = NULL;
223 if (ctxt->incMax == 0) {
224 ctxt->incMax = 4;
225 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
226 sizeof(ctxt->incTab[0]));
227 if (ctxt->incTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000228 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000229 xmlGenericError(xmlGenericErrorContext,
230 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000231 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000232 xmlXIncludeFreeRef(ret);
233 return(NULL);
234 }
235 }
236 if (ctxt->incNr >= ctxt->incMax) {
237 ctxt->incMax *= 2;
238 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
239 ctxt->incMax * sizeof(ctxt->incTab[0]));
240 if (ctxt->incTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000241 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000242 xmlGenericError(xmlGenericErrorContext,
243 "realloc failed !\n");
244 xmlXIncludeFreeRef(ret);
245 return(NULL);
246 }
247 }
248 ctxt->incTab[ctxt->incNr++] = ret;
249 return(ret);
250}
251
252/**
Owen Taylor3473f882001-02-23 17:55:21 +0000253 * xmlXIncludeNewContext:
254 * @doc: an XML Document
255 *
256 * Creates a new XInclude context
257 *
258 * Returns the new set
259 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000260static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000261xmlXIncludeNewContext(xmlDocPtr doc) {
262 xmlXIncludeCtxtPtr ret;
263
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000264#ifdef DEBUG_XINCLUDE
265 xmlGenericError(xmlGenericErrorContext, "New context\n");
266#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000267 if (doc == NULL)
268 return(NULL);
269 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
270 if (ret == NULL)
271 return(NULL);
272 memset(ret, 0, sizeof(xmlXIncludeCtxt));
273 ret->doc = doc;
274 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000275 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000276 ret->incMax = 0;
277 ret->incTab = NULL;
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000278 ret->nbErrors = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000279 return(ret);
280}
281
282/**
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000283 * xmlXIncludeURLPush:
284 * @ctxt: the parser context
285 * @value: the url
286 *
287 * Pushes a new url on top of the url stack
288 *
289 * Returns -1 in case of error, the index in the stack otherwise
290 */
291static int
292xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
293 const xmlChar *value)
294{
295 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
Daniel Veillard98485322003-08-14 15:44:40 +0000296 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000297 xmlGenericError(xmlGenericErrorContext,
298 "XInclude: detected a recursion in %s\n",
299 value);
300 ctxt->nbErrors++;
301 return(-1);
302 }
303 if (ctxt->urlTab == NULL) {
304 ctxt->urlMax = 4;
305 ctxt->urlNr = 0;
306 ctxt->urlTab = (xmlChar * *) xmlMalloc(
307 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
308 if (ctxt->urlTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000309 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000310 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
311 return (-1);
312 }
313 }
314 if (ctxt->urlNr >= ctxt->urlMax) {
315 ctxt->urlMax *= 2;
316 ctxt->urlTab =
317 (xmlChar * *) xmlRealloc(ctxt->urlTab,
318 ctxt->urlMax *
319 sizeof(ctxt->urlTab[0]));
320 if (ctxt->urlTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000321 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000322 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
323 return (-1);
324 }
325 }
326 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
327 return (ctxt->urlNr++);
328}
329
330/**
331 * xmlXIncludeURLPop:
332 * @ctxt: the parser context
333 *
334 * Pops the top url from the url stack
335 */
336static void
337xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
338{
339 xmlChar * ret;
340
341 if (ctxt->urlNr <= 0)
342 return;
343 ctxt->urlNr--;
344 if (ctxt->urlNr > 0)
345 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
346 else
347 ctxt->url = NULL;
348 ret = ctxt->urlTab[ctxt->urlNr];
349 ctxt->urlTab[ctxt->urlNr] = 0;
350 if (ret != NULL)
351 xmlFree(ret);
352}
353
354/**
Owen Taylor3473f882001-02-23 17:55:21 +0000355 * xmlXIncludeFreeContext:
356 * @ctxt: the XInclude context
357 *
358 * Free an XInclude context
359 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000360static void
Owen Taylor3473f882001-02-23 17:55:21 +0000361xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
362 int i;
363
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000364#ifdef DEBUG_XINCLUDE
365 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
366#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000367 if (ctxt == NULL)
368 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000369 while (ctxt->urlNr > 0)
370 xmlXIncludeURLPop(ctxt);
371 if (ctxt->urlTab != NULL)
372 xmlFree(ctxt->urlTab);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000373 for (i = 0;i < ctxt->incNr;i++) {
374 if (ctxt->incTab[i] != NULL)
375 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000376 }
377 for (i = 0;i < ctxt->txtNr;i++) {
378 if (ctxt->txturlTab[i] != NULL)
379 xmlFree(ctxt->txturlTab[i]);
380 }
381 if (ctxt->incTab != NULL)
382 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000383 if (ctxt->txtTab != NULL)
384 xmlFree(ctxt->txtTab);
385 if (ctxt->txturlTab != NULL)
386 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000387 xmlFree(ctxt);
388}
389
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000390/**
Daniel Veillard98485322003-08-14 15:44:40 +0000391 * xmlXIncludeParseFile:
392 * @ctxt: the XInclude context
393 * @URL: the URL or file path
394 *
395 * parse an document for XInclude
396 */
397static xmlDocPtr
398xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt ATTRIBUTE_UNUSED, const char *URL) {
399 xmlDocPtr ret;
400 xmlParserCtxtPtr pctxt;
401 char *directory = NULL;
402
403 xmlInitParser();
404
405 pctxt = xmlCreateFileParserCtxt(URL);
406 if (pctxt == NULL) {
407 return(NULL);
408 }
409
410 if ((pctxt->directory == NULL) && (directory == NULL))
411 directory = xmlParserGetDirectory(URL);
412 if ((pctxt->directory == NULL) && (directory != NULL))
413 pctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
414
415 pctxt->loadsubset = XML_DETECT_IDS;
416
417 xmlParseDocument(pctxt);
418
419 if (pctxt->wellFormed)
420 ret = pctxt->myDoc;
421 else {
422 ret = NULL;
423 xmlFreeDoc(pctxt->myDoc);
424 pctxt->myDoc = NULL;
425 }
426 xmlFreeParserCtxt(pctxt);
427
428 return(ret);
429}
430
431/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000432 * xmlXIncludeAddNode:
433 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000434 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000435 *
436 * Add a new node to process to an XInclude context
437 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000438static int
439xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
440 xmlXIncludeRefPtr ref;
441 xmlURIPtr uri;
442 xmlChar *URL;
443 xmlChar *fragment = NULL;
444 xmlChar *href;
445 xmlChar *parse;
446 xmlChar *base;
447 xmlChar *URI;
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000448 int xml = 1, i; /* default Issue 64 */
449 int local = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000450
451
452 if (ctxt == NULL)
453 return(-1);
454 if (cur == NULL)
455 return(-1);
456
457#ifdef DEBUG_XINCLUDE
458 xmlGenericError(xmlGenericErrorContext, "Add node\n");
459#endif
460 /*
461 * read the attributes
462 */
463 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
464 if (href == NULL) {
465 href = xmlGetProp(cur, XINCLUDE_HREF);
466 if (href == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000467 xmlXIncludeErrorContext(ctxt, cur);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000468 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000469 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000470 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000471 }
472 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000473 if (href[0] == '#')
474 local = 1;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000475 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
476 if (parse == NULL) {
477 parse = xmlGetProp(cur, XINCLUDE_PARSE);
478 }
479 if (parse != NULL) {
480 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
481 xml = 1;
482 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
483 xml = 0;
484 else {
Daniel Veillard98485322003-08-14 15:44:40 +0000485 xmlXIncludeErrorContext(ctxt, cur);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000486 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000487 "XInclude: invalid value %s for %s\n",
488 parse, XINCLUDE_PARSE);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000489 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000490 if (href != NULL)
491 xmlFree(href);
492 if (parse != NULL)
493 xmlFree(parse);
494 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000495 }
496 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000497
498 /*
499 * compute the URI
500 */
501 base = xmlNodeGetBase(ctxt->doc, cur);
502 if (base == NULL) {
503 URI = xmlBuildURI(href, ctxt->doc->URL);
504 } else {
505 URI = xmlBuildURI(href, base);
506 }
507 if (URI == NULL) {
508 xmlChar *escbase;
509 xmlChar *eschref;
510 /*
511 * Some escaping may be needed
512 */
513 escbase = xmlURIEscape(base);
514 eschref = xmlURIEscape(href);
515 URI = xmlBuildURI(eschref, escbase);
516 if (escbase != NULL)
517 xmlFree(escbase);
518 if (eschref != NULL)
519 xmlFree(eschref);
520 }
521 if (parse != NULL)
522 xmlFree(parse);
523 if (href != NULL)
524 xmlFree(href);
525 if (base != NULL)
526 xmlFree(base);
527 if (URI == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000528 xmlXIncludeErrorContext(ctxt, cur);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000529 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000530 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000531 return(-1);
532 }
533
534 /*
535 * Check the URL and remove any fragment identifier
536 */
537 uri = xmlParseURI((const char *)URI);
538 if (uri == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000539 xmlXIncludeErrorContext(ctxt, cur);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000540 xmlGenericError(xmlGenericErrorContext,
541 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000542 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000543 return(-1);
544 }
545 if (uri->fragment != NULL) {
546 fragment = (xmlChar *) uri->fragment;
547 uri->fragment = NULL;
548 }
549 URL = xmlSaveUri(uri);
550 xmlFreeURI(uri);
551 xmlFree(URI);
552 if (URL == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000553 xmlXIncludeErrorContext(ctxt, cur);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000554 xmlGenericError(xmlGenericErrorContext,
555 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000556 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000557 if (fragment != NULL)
558 xmlFree(fragment);
559 return(-1);
560 }
561
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000562 /*
563 * Check the URL against the stack for recursions
564 */
565 if (!local) {
566 for (i = 0;i < ctxt->urlNr;i++) {
567 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
Daniel Veillard98485322003-08-14 15:44:40 +0000568 xmlXIncludeErrorContext(ctxt, cur);
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000569 xmlGenericError(xmlGenericErrorContext,
570 "XInclude: detected a recursion in %s\n",
571 URL);
572 ctxt->nbErrors++;
573 return(-1);
574 }
575 }
576 }
577
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000578 ref = xmlXIncludeNewRef(ctxt, URL, cur);
579 if (ref == NULL) {
580 return(-1);
581 }
582 ref->fragment = fragment;
583 ref->doc = NULL;
584 ref->xml = xml;
585 ref->count = 1;
586 xmlFree(URL);
587 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000588}
589
590/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000591 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000592 * @ctxt: the XInclude context
593 * @doc: the new document
594 * @url: the associated URL
595 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000596 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000597 */
598static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000599xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000600 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000601 xmlXIncludeCtxtPtr newctxt;
602 int i;
603
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000604 /*
605 * Avoid recursion in already substitued resources
606 for (i = 0;i < ctxt->urlNr;i++) {
607 if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
608 return;
609 }
610 */
611
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000612#ifdef DEBUG_XINCLUDE
613 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
614#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000615 /*
616 * Handle recursion here.
617 */
618
619 newctxt = xmlXIncludeNewContext(doc);
620 if (newctxt != NULL) {
621 /*
622 * Copy the existing document set
623 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000624 newctxt->incMax = ctxt->incMax;
625 newctxt->incNr = ctxt->incNr;
626 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
627 sizeof(newctxt->incTab[0]));
628 if (newctxt->incTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000629 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000630 xmlGenericError(xmlGenericErrorContext,
631 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000632 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000633 xmlFree(newctxt);
634 return;
635 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000636 /*
637 * copy the urlTab
638 */
639 newctxt->urlMax = ctxt->urlMax;
640 newctxt->urlNr = ctxt->urlNr;
641 newctxt->urlTab = ctxt->urlTab;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000642
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000643 /*
644 * Inherit the documents already in use by others includes
645 */
646 newctxt->incBase = ctxt->incNr;
647 for (i = 0;i < ctxt->incNr;i++) {
648 newctxt->incTab[i] = ctxt->incTab[i];
649 newctxt->incTab[i]->count++; /* prevent the recursion from
650 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000651 }
Daniel Veillard8edf1c52003-07-22 20:52:14 +0000652 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000653 for (i = 0;i < ctxt->incNr;i++) {
654 newctxt->incTab[i]->count--;
655 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000656 }
Daniel Veillardd9b72832003-03-27 14:24:00 +0000657
658 /* urlTab may have been reallocated */
659 ctxt->urlTab = newctxt->urlTab;
660 ctxt->urlMax = newctxt->urlMax;
661
Daniel Veillardf4b4f982003-02-13 11:02:08 +0000662 newctxt->urlMax = 0;
663 newctxt->urlNr = 0;
664 newctxt->urlTab = NULL;
665
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000666 xmlXIncludeFreeContext(newctxt);
667 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000668#ifdef DEBUG_XINCLUDE
669 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
670#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000671}
672
673/**
674 * xmlXIncludeAddTxt:
675 * @ctxt: the XInclude context
676 * @txt: the new text node
677 * @url: the associated URL
678 *
679 * Add a new txtument to the list
680 */
681static void
682xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000683#ifdef DEBUG_XINCLUDE
684 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
685#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000686 if (ctxt->txtMax == 0) {
687 ctxt->txtMax = 4;
688 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
689 sizeof(ctxt->txtTab[0]));
690 if (ctxt->txtTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000691 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000692 xmlGenericError(xmlGenericErrorContext,
693 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000694 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000695 return;
696 }
697 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
698 sizeof(ctxt->txturlTab[0]));
699 if (ctxt->txturlTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000700 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000701 xmlGenericError(xmlGenericErrorContext,
702 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000703 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000704 return;
705 }
706 }
707 if (ctxt->txtNr >= ctxt->txtMax) {
708 ctxt->txtMax *= 2;
709 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
710 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
711 if (ctxt->txtTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000712 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000713 xmlGenericError(xmlGenericErrorContext,
714 "realloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000715 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000716 return;
717 }
718 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000719 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000720 if (ctxt->txturlTab == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +0000721 xmlXIncludeErrorContext(ctxt, NULL);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000722 xmlGenericError(xmlGenericErrorContext,
723 "realloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000724 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000725 return;
726 }
727 }
728 ctxt->txtTab[ctxt->txtNr] = txt;
729 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
730 ctxt->txtNr++;
731}
732
Owen Taylor3473f882001-02-23 17:55:21 +0000733/************************************************************************
734 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000735 * Node copy with specific semantic *
736 * *
737 ************************************************************************/
738
739/**
740 * xmlXIncludeCopyNode:
741 * @ctxt: the XInclude context
742 * @target: the document target
743 * @source: the document source
744 * @elem: the element
745 *
746 * Make a copy of the node while preserving the XInclude semantic
747 * of the Infoset copy
748 */
749static xmlNodePtr
750xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
751 xmlDocPtr source, xmlNodePtr elem) {
752 xmlNodePtr result = NULL;
753
754 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
755 (elem == NULL))
756 return(NULL);
757 if (elem->type == XML_DTD_NODE)
758 return(NULL);
759 result = xmlDocCopyNode(elem, target, 1);
760 return(result);
761}
762
763/**
764 * xmlXIncludeCopyNodeList:
765 * @ctxt: the XInclude context
766 * @target: the document target
767 * @source: the document source
768 * @elem: the element list
769 *
770 * Make a copy of the node list while preserving the XInclude semantic
771 * of the Infoset copy
772 */
773static xmlNodePtr
774xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
775 xmlDocPtr source, xmlNodePtr elem) {
776 xmlNodePtr cur, res, result = NULL, last = NULL;
777
778 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
779 (elem == NULL))
780 return(NULL);
781 cur = elem;
782 while (cur != NULL) {
783 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
784 if (res != NULL) {
785 if (result == NULL) {
786 result = last = res;
787 } else {
788 last->next = res;
789 res->prev = last;
790 last = res;
791 }
792 }
793 cur = cur->next;
794 }
795 return(result);
796}
797
798/**
799 * xmlXInclueGetNthChild:
800 * @cur: the node
801 * @no: the child number
802 *
803 * Returns the @no'th element child of @cur or NULL
804 */
805static xmlNodePtr
806xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
807 int i;
808 if (cur == NULL)
809 return(cur);
810 cur = cur->children;
811 for (i = 0;i <= no;cur = cur->next) {
812 if (cur == NULL)
813 return(cur);
814 if ((cur->type == XML_ELEMENT_NODE) ||
815 (cur->type == XML_DOCUMENT_NODE) ||
816 (cur->type == XML_HTML_DOCUMENT_NODE)) {
817 i++;
818 if (i == no)
819 break;
820 }
821 }
822 return(cur);
823}
824
825xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
826
827/**
828 * xmlXIncludeCopyRange:
829 * @ctxt: the XInclude context
830 * @target: the document target
831 * @source: the document source
832 * @obj: the XPointer result from the evaluation.
833 *
834 * Build a node list tree copy of the XPointer result.
835 *
836 * Returns an xmlNodePtr list or NULL.
837 * the caller has to free the node tree.
838 */
839static xmlNodePtr
840xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
841 xmlDocPtr source, xmlXPathObjectPtr range) {
842 /* pointers to generated nodes */
843 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
844 /* pointers to traversal nodes */
845 xmlNodePtr start, cur, end;
846 int index1, index2;
847
848 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
849 (range == NULL))
850 return(NULL);
851 if (range->type != XPATH_RANGE)
852 return(NULL);
853 start = (xmlNodePtr) range->user;
854
855 if (start == NULL)
856 return(NULL);
857 end = range->user2;
858 if (end == NULL)
859 return(xmlDocCopyNode(start, target, 1));
860
861 cur = start;
862 index1 = range->index;
863 index2 = range->index2;
864 while (cur != NULL) {
865 if (cur == end) {
866 if (cur->type == XML_TEXT_NODE) {
867 const xmlChar *content = cur->content;
868 int len;
869
870 if (content == NULL) {
871 tmp = xmlNewTextLen(NULL, 0);
872 } else {
873 len = index2;
874 if ((cur == start) && (index1 > 1)) {
875 content += (index1 - 1);
876 len -= (index1 - 1);
877 index1 = 0;
878 } else {
879 len = index2;
880 }
881 tmp = xmlNewTextLen(content, len);
882 }
883 /* single sub text node selection */
884 if (list == NULL)
885 return(tmp);
886 /* prune and return full set */
887 if (last != NULL)
888 xmlAddNextSibling(last, tmp);
889 else
890 xmlAddChild(parent, tmp);
891 return(list);
892 } else {
893 tmp = xmlDocCopyNode(cur, target, 0);
894 if (list == NULL)
895 list = tmp;
896 else {
897 if (last != NULL)
898 xmlAddNextSibling(last, tmp);
899 else
900 xmlAddChild(parent, tmp);
901 }
902 last = NULL;
903 parent = tmp;
904
905 if (index2 > 1) {
906 end = xmlXIncludeGetNthChild(cur, index2 - 1);
907 index2 = 0;
908 }
909 if ((cur == start) && (index1 > 1)) {
910 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
911 index1 = 0;
912 } else {
913 cur = cur->children;
914 }
915 /*
916 * Now gather the remaining nodes from cur to end
917 */
918 continue; /* while */
919 }
920 } else if ((cur == start) &&
921 (list == NULL) /* looks superfluous but ... */ ) {
922 if ((cur->type == XML_TEXT_NODE) ||
923 (cur->type == XML_CDATA_SECTION_NODE)) {
924 const xmlChar *content = cur->content;
925
926 if (content == NULL) {
927 tmp = xmlNewTextLen(NULL, 0);
928 } else {
929 if (index1 > 1) {
930 content += (index1 - 1);
931 }
932 tmp = xmlNewText(content);
933 }
934 last = list = tmp;
935 } else {
936 if ((cur == start) && (index1 > 1)) {
937 tmp = xmlDocCopyNode(cur, target, 0);
938 list = tmp;
939 parent = tmp;
940 last = NULL;
941 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
942 index1 = 0;
943 /*
944 * Now gather the remaining nodes from cur to end
945 */
946 continue; /* while */
947 }
948 tmp = xmlDocCopyNode(cur, target, 1);
949 list = tmp;
950 parent = NULL;
951 last = tmp;
952 }
953 } else {
954 tmp = NULL;
955 switch (cur->type) {
956 case XML_DTD_NODE:
957 case XML_ELEMENT_DECL:
958 case XML_ATTRIBUTE_DECL:
959 case XML_ENTITY_NODE:
960 /* Do not copy DTD informations */
961 break;
962 case XML_ENTITY_DECL:
963 /* handle crossing entities -> stack needed */
964 break;
965 case XML_XINCLUDE_START:
966 case XML_XINCLUDE_END:
967 /* don't consider it part of the tree content */
968 break;
969 case XML_ATTRIBUTE_NODE:
970 /* Humm, should not happen ! */
971 break;
972 default:
973 tmp = xmlDocCopyNode(cur, target, 1);
974 break;
975 }
976 if (tmp != NULL) {
977 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
978 return(NULL);
979 }
980 if (last != NULL)
981 xmlAddNextSibling(last, tmp);
982 else {
983 xmlAddChild(parent, tmp);
984 last = tmp;
985 }
986 }
987 }
988 /*
989 * Skip to next node in document order
990 */
991 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
992 return(NULL);
993 }
994 cur = xmlXPtrAdvanceNode(cur);
995 }
996 return(list);
997}
998
999/**
1000 * xmlXIncludeBuildNodeList:
1001 * @ctxt: the XInclude context
1002 * @target: the document target
1003 * @source: the document source
1004 * @obj: the XPointer result from the evaluation.
1005 *
1006 * Build a node list tree copy of the XPointer result.
1007 * This will drop Attributes and Namespace declarations.
1008 *
1009 * Returns an xmlNodePtr list or NULL.
1010 * the caller has to free the node tree.
1011 */
1012static xmlNodePtr
1013xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
1014 xmlDocPtr source, xmlXPathObjectPtr obj) {
1015 xmlNodePtr list = NULL, last = NULL;
1016 int i;
1017
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001018 if (source == NULL)
1019 source = ctxt->doc;
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001020 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
1021 (obj == NULL))
1022 return(NULL);
1023 switch (obj->type) {
1024 case XPATH_NODESET: {
1025 xmlNodeSetPtr set = obj->nodesetval;
1026 if (set == NULL)
1027 return(NULL);
1028 for (i = 0;i < set->nodeNr;i++) {
1029 if (set->nodeTab[i] == NULL)
1030 continue;
1031 switch (set->nodeTab[i]->type) {
1032 case XML_TEXT_NODE:
1033 case XML_CDATA_SECTION_NODE:
1034 case XML_ELEMENT_NODE:
1035 case XML_ENTITY_REF_NODE:
1036 case XML_ENTITY_NODE:
1037 case XML_PI_NODE:
1038 case XML_COMMENT_NODE:
1039 case XML_DOCUMENT_NODE:
1040 case XML_HTML_DOCUMENT_NODE:
1041#ifdef LIBXML_DOCB_ENABLED
1042 case XML_DOCB_DOCUMENT_NODE:
1043#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001044 case XML_XINCLUDE_END:
1045 break;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001046 case XML_XINCLUDE_START: {
1047 xmlNodePtr tmp, cur = set->nodeTab[i];
1048
1049 cur = cur->next;
1050 while (cur != NULL) {
1051 switch(cur->type) {
1052 case XML_TEXT_NODE:
1053 case XML_CDATA_SECTION_NODE:
1054 case XML_ELEMENT_NODE:
1055 case XML_ENTITY_REF_NODE:
1056 case XML_ENTITY_NODE:
1057 case XML_PI_NODE:
1058 case XML_COMMENT_NODE:
1059 tmp = xmlXIncludeCopyNode(ctxt, target,
1060 source, cur);
1061 if (last == NULL) {
1062 list = last = tmp;
1063 } else {
1064 xmlAddNextSibling(last, tmp);
1065 last = tmp;
1066 }
1067 cur = cur->next;
1068 continue;
1069 default:
1070 break;
1071 }
1072 break;
1073 }
1074 continue;
1075 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001076 case XML_ATTRIBUTE_NODE:
1077 case XML_NAMESPACE_DECL:
1078 case XML_DOCUMENT_TYPE_NODE:
1079 case XML_DOCUMENT_FRAG_NODE:
1080 case XML_NOTATION_NODE:
1081 case XML_DTD_NODE:
1082 case XML_ELEMENT_DECL:
1083 case XML_ATTRIBUTE_DECL:
1084 case XML_ENTITY_DECL:
1085 continue; /* for */
1086 }
1087 if (last == NULL)
1088 list = last = xmlXIncludeCopyNode(ctxt, target, source,
1089 set->nodeTab[i]);
1090 else {
1091 xmlAddNextSibling(last,
1092 xmlXIncludeCopyNode(ctxt, target, source,
1093 set->nodeTab[i]));
1094 if (last->next != NULL)
1095 last = last->next;
1096 }
1097 }
1098 break;
1099 }
1100 case XPATH_LOCATIONSET: {
1101 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1102 if (set == NULL)
1103 return(NULL);
1104 for (i = 0;i < set->locNr;i++) {
1105 if (last == NULL)
1106 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
1107 set->locTab[i]);
1108 else
1109 xmlAddNextSibling(last,
1110 xmlXIncludeCopyXPointer(ctxt, target, source,
1111 set->locTab[i]));
1112 if (last != NULL) {
1113 while (last->next != NULL)
1114 last = last->next;
1115 }
1116 }
1117 break;
1118 }
1119 case XPATH_RANGE:
1120 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
1121 case XPATH_POINT:
1122 /* points are ignored in XInclude */
1123 break;
1124 default:
1125 break;
1126 }
1127 return(list);
1128}
1129/************************************************************************
1130 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001131 * XInclude I/O handling *
1132 * *
1133 ************************************************************************/
1134
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001135typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1136typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1137struct _xmlXIncludeMergeData {
1138 xmlDocPtr doc;
1139 xmlXIncludeCtxtPtr ctxt;
1140};
1141
Owen Taylor3473f882001-02-23 17:55:21 +00001142/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001143 * xmlXIncludeMergeOneEntity:
1144 * @ent: the entity
1145 * @doc: the including doc
1146 * @nr: the entity name
1147 *
1148 * Inplements the merge of one entity
1149 */
1150static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001151xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001152 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001153 xmlEntityPtr ret, prev;
1154 xmlDocPtr doc;
1155 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001156
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001157 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001158 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001159 ctxt = data->ctxt;
1160 doc = data->doc;
1161 if ((ctxt == NULL) || (doc == NULL))
1162 return;
1163 switch (ent->etype) {
1164 case XML_INTERNAL_PARAMETER_ENTITY:
1165 case XML_EXTERNAL_PARAMETER_ENTITY:
1166 case XML_INTERNAL_PREDEFINED_ENTITY:
1167 return;
1168 case XML_INTERNAL_GENERAL_ENTITY:
1169 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1170 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1171 break;
1172 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001173 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1174 ent->SystemID, ent->content);
1175 if (ret != NULL) {
1176 if (ent->URI != NULL)
1177 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001178 } else {
1179 prev = xmlGetDocEntity(doc, ent->name);
1180 if (prev != NULL) {
1181 if (ent->etype != prev->etype)
1182 goto error;
1183
1184 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1185 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1186 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001187 } else if ((ent->ExternalID != NULL) &&
1188 (prev->ExternalID != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001189 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1190 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001191 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1192 if (!xmlStrEqual(ent->content, prev->content))
1193 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001194 } else {
1195 goto error;
1196 }
1197
1198 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001199 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001200 return;
1201error:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001202 switch (ent->etype) {
1203 case XML_INTERNAL_PARAMETER_ENTITY:
1204 case XML_EXTERNAL_PARAMETER_ENTITY:
1205 case XML_INTERNAL_PREDEFINED_ENTITY:
1206 case XML_INTERNAL_GENERAL_ENTITY:
1207 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1208 return;
1209 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1210 break;
1211 }
Daniel Veillard98485322003-08-14 15:44:40 +00001212 xmlXIncludeErrorContext(ctxt, (xmlNodePtr) ent);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001213 xmlGenericError(xmlGenericErrorContext,
1214 "XInclude: mismatch in redefinition of entity %s\n", ent->name);
1215 ctxt->nbErrors++;
Daniel Veillard4287c572003-02-04 22:48:53 +00001216}
1217
1218/**
1219 * xmlXIncludeMergeEntities:
1220 * @ctxt: an XInclude context
1221 * @doc: the including doc
1222 * @from: the included doc
1223 *
1224 * Inplements the entity merge
1225 *
1226 * Returns 0 if merge succeeded, -1 if some processing failed
1227 */
1228static int
1229xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1230 xmlDocPtr from) {
1231 xmlNodePtr cur;
1232 xmlDtdPtr target, source;
1233
1234 if (ctxt == NULL)
1235 return(-1);
1236
1237 if ((from == NULL) || (from->intSubset == NULL))
1238 return(0);
1239
1240 target = doc->intSubset;
1241 if (target == NULL) {
1242 cur = xmlDocGetRootElement(doc);
1243 if (cur == NULL)
1244 return(-1);
1245 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1246 if (target == NULL)
1247 return(-1);
1248 }
1249
1250 source = from->intSubset;
1251 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001252 xmlXIncludeMergeData data;
1253
1254 data.ctxt = ctxt;
1255 data.doc = doc;
1256
Daniel Veillard4287c572003-02-04 22:48:53 +00001257 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001258 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001259 }
1260 source = from->extSubset;
1261 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001262 xmlXIncludeMergeData data;
1263
1264 data.ctxt = ctxt;
1265 data.doc = doc;
1266
Daniel Veillard4287c572003-02-04 22:48:53 +00001267 /*
1268 * don't duplicate existing stuff when external subsets are the same
1269 */
1270 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1271 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1272 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001273 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001274 }
1275 }
1276 return(0);
1277}
1278
1279/**
Owen Taylor3473f882001-02-23 17:55:21 +00001280 * xmlXIncludeLoadDoc:
1281 * @ctxt: the XInclude context
1282 * @url: the associated URL
1283 * @nr: the xinclude node number
1284 *
1285 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001286 *
1287 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001288 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001289static int
Owen Taylor3473f882001-02-23 17:55:21 +00001290xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1291 xmlDocPtr doc;
1292 xmlURIPtr uri;
1293 xmlChar *URL;
1294 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001295 int i = 0;
1296
1297#ifdef DEBUG_XINCLUDE
1298 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1299#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001300 /*
1301 * Check the URL and remove any fragment identifier
1302 */
1303 uri = xmlParseURI((const char *)url);
1304 if (uri == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001305 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001306 xmlGenericError(xmlGenericErrorContext,
1307 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001308 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001309 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001310 }
1311 if (uri->fragment != NULL) {
1312 fragment = (xmlChar *) uri->fragment;
1313 uri->fragment = NULL;
1314 }
1315 URL = xmlSaveUri(uri);
1316 xmlFreeURI(uri);
1317 if (URL == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001318 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001319 xmlGenericError(xmlGenericErrorContext,
1320 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001321 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001322 if (fragment != NULL)
1323 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001324 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001325 }
1326
1327 /*
1328 * Handling of references to the local document are done
1329 * directly through ctxt->doc.
1330 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001331 if ((URL[0] == 0) || (URL[0] == '#') ||
1332 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001333 doc = NULL;
1334 goto loaded;
1335 }
1336
1337 /*
1338 * Prevent reloading twice the document.
1339 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001340 for (i = 0; i < ctxt->incNr; i++) {
1341 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1342 (ctxt->incTab[i]->doc != NULL)) {
1343 doc = ctxt->incTab[i]->doc;
1344#ifdef DEBUG_XINCLUDE
1345 printf("Already loaded %s\n", URL);
1346#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001347 goto loaded;
1348 }
1349 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001350
Owen Taylor3473f882001-02-23 17:55:21 +00001351 /*
1352 * Load it.
1353 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001354#ifdef DEBUG_XINCLUDE
1355 printf("loading %s\n", URL);
1356#endif
Daniel Veillard98485322003-08-14 15:44:40 +00001357 doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001358 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001359 xmlFree(URL);
1360 if (fragment != NULL)
1361 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001362 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001363 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001364 ctxt->incTab[nr]->doc = doc;
Daniel Veillard98485322003-08-14 15:44:40 +00001365 for (i = nr + 1; i < ctxt->incNr; i++) {
1366 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1367 ctxt->incTab[nr]->count++;
1368#ifdef DEBUG_XINCLUDE
1369 printf("Increasing %s count since reused\n", URL);
1370#endif
1371 break;
1372 }
1373 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001374
1375 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001376 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001377 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001378 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001379
1380 /*
1381 * We don't need the DTD anymore, free up space
1382 if (doc->intSubset != NULL) {
1383 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1384 xmlFreeNode((xmlNodePtr) doc->intSubset);
1385 doc->intSubset = NULL;
1386 }
1387 if (doc->extSubset != NULL) {
1388 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1389 xmlFreeNode((xmlNodePtr) doc->extSubset);
1390 doc->extSubset = NULL;
1391 }
1392 */
1393 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001394
1395loaded:
1396 if (fragment == NULL) {
1397 /*
1398 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001399 */
1400 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001401 {
1402 /* Hopefully a DTD declaration won't be copied from
1403 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001404 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001405 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001406 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001407 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001408 }
Owen Taylor3473f882001-02-23 17:55:21 +00001409 } else {
1410 /*
1411 * Computes the XPointer expression and make a copy used
1412 * as the replacement copy.
1413 */
1414 xmlXPathObjectPtr xptr;
1415 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001416 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001417
1418 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001419 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1420 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001421 } else {
1422 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1423 }
1424 if (xptrctxt == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001425 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001426 xmlGenericError(xmlGenericErrorContext,
1427 "XInclude: could create XPointer context\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001428 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001429 xmlFree(URL);
1430 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001431 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001432 }
1433 xptr = xmlXPtrEval(fragment, xptrctxt);
1434 if (xptr == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001435 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001436 xmlGenericError(xmlGenericErrorContext,
1437 "XInclude: XPointer evaluation failed: #%s\n",
1438 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001439 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001440 xmlXPathFreeContext(xptrctxt);
1441 xmlFree(URL);
1442 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001443 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001444 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001445 switch (xptr->type) {
1446 case XPATH_UNDEFINED:
1447 case XPATH_BOOLEAN:
1448 case XPATH_NUMBER:
1449 case XPATH_STRING:
1450 case XPATH_POINT:
1451 case XPATH_USERS:
1452 case XPATH_XSLT_TREE:
Daniel Veillard98485322003-08-14 15:44:40 +00001453 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001454 xmlGenericError(xmlGenericErrorContext,
1455 "XInclude: XPointer is not a range: #%s\n",
1456 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001457 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001458 xmlXPathFreeContext(xptrctxt);
1459 xmlFree(URL);
1460 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001461 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001462 case XPATH_NODESET:
1463 case XPATH_RANGE:
1464 case XPATH_LOCATIONSET:
1465 break;
1466 }
1467 set = xptr->nodesetval;
1468 if (set != NULL) {
1469 for (i = 0;i < set->nodeNr;i++) {
1470 if (set->nodeTab[i] == NULL)
1471 continue;
1472 switch (set->nodeTab[i]->type) {
1473 case XML_TEXT_NODE:
1474 case XML_CDATA_SECTION_NODE:
1475 case XML_ELEMENT_NODE:
1476 case XML_ENTITY_REF_NODE:
1477 case XML_ENTITY_NODE:
1478 case XML_PI_NODE:
1479 case XML_COMMENT_NODE:
1480 case XML_DOCUMENT_NODE:
1481 case XML_HTML_DOCUMENT_NODE:
1482#ifdef LIBXML_DOCB_ENABLED
1483 case XML_DOCB_DOCUMENT_NODE:
1484#endif
1485 continue;
1486 case XML_ATTRIBUTE_NODE:
Daniel Veillard98485322003-08-14 15:44:40 +00001487 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001488 xmlGenericError(xmlGenericErrorContext,
1489 "XInclude: XPointer selects an attribute: #%s\n",
1490 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001491 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001492 set->nodeTab[i] = NULL;
1493 continue;
1494 case XML_NAMESPACE_DECL:
Daniel Veillard98485322003-08-14 15:44:40 +00001495 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001496 xmlGenericError(xmlGenericErrorContext,
1497 "XInclude: XPointer selects a namespace: #%s\n",
1498 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001499 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001500 set->nodeTab[i] = NULL;
1501 continue;
1502 case XML_DOCUMENT_TYPE_NODE:
1503 case XML_DOCUMENT_FRAG_NODE:
1504 case XML_NOTATION_NODE:
1505 case XML_DTD_NODE:
1506 case XML_ELEMENT_DECL:
1507 case XML_ATTRIBUTE_DECL:
1508 case XML_ENTITY_DECL:
1509 case XML_XINCLUDE_START:
1510 case XML_XINCLUDE_END:
Daniel Veillard98485322003-08-14 15:44:40 +00001511 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001512 xmlGenericError(xmlGenericErrorContext,
1513 "XInclude: XPointer selects unexpected nodes: #%s\n",
1514 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001515 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001516 set->nodeTab[i] = NULL;
1517 set->nodeTab[i] = NULL;
1518 continue; /* for */
1519 }
1520 }
1521 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001522 if (doc == NULL) {
1523 ctxt->incTab[nr]->xptr = xptr;
1524 ctxt->incTab[nr]->inc = NULL;
1525 } else {
1526 ctxt->incTab[nr]->inc =
1527 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1528 xmlXPathFreeObject(xptr);
1529 }
Owen Taylor3473f882001-02-23 17:55:21 +00001530 xmlXPathFreeContext(xptrctxt);
1531 xmlFree(fragment);
1532 }
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001533
1534 /*
1535 * Do the xml:base fixup if needed
1536 */
1537 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1538 xmlNodePtr node;
1539
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001540 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001541 while (node != NULL) {
1542 if (node->type == XML_ELEMENT_NODE)
1543 xmlNodeSetBase(node, URL);
1544 node = node->next;
1545 }
1546 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001547 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1548 (ctxt->incTab[nr]->count <= 1)) {
1549#ifdef DEBUG_XINCLUDE
1550 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1551#endif
1552 xmlFreeDoc(ctxt->incTab[nr]->doc);
1553 ctxt->incTab[nr]->doc = NULL;
1554 }
Owen Taylor3473f882001-02-23 17:55:21 +00001555 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001556 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001557}
1558
1559/**
1560 * xmlXIncludeLoadTxt:
1561 * @ctxt: the XInclude context
1562 * @url: the associated URL
1563 * @nr: the xinclude node number
1564 *
1565 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001566 *
1567 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001568 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001569static int
Owen Taylor3473f882001-02-23 17:55:21 +00001570xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1571 xmlParserInputBufferPtr buf;
1572 xmlNodePtr node;
1573 xmlURIPtr uri;
1574 xmlChar *URL;
1575 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001576 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001577 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001578
Owen Taylor3473f882001-02-23 17:55:21 +00001579 /*
1580 * Check the URL and remove any fragment identifier
1581 */
1582 uri = xmlParseURI((const char *)url);
1583 if (uri == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001584 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001585 xmlGenericError(xmlGenericErrorContext,
1586 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001587 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001588 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001589 }
1590 if (uri->fragment != NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001591 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001592 xmlGenericError(xmlGenericErrorContext,
1593 "XInclude: fragment identifier forbidden for text: %s\n",
1594 uri->fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001595 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001596 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001597 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001598 }
1599 URL = xmlSaveUri(uri);
1600 xmlFreeURI(uri);
1601 if (URL == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001602 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001603 xmlGenericError(xmlGenericErrorContext,
1604 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001605 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001606 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001607 }
1608
1609 /*
1610 * Handling of references to the local document are done
1611 * directly through ctxt->doc.
1612 */
1613 if (URL[0] == 0) {
Daniel Veillard98485322003-08-14 15:44:40 +00001614 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001615 xmlGenericError(xmlGenericErrorContext,
1616 "XInclude: text serialization of document not available\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001617 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001618 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001619 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001620 }
1621
1622 /*
1623 * Prevent reloading twice the document.
1624 */
1625 for (i = 0; i < ctxt->txtNr; i++) {
1626 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1627 node = xmlCopyNode(ctxt->txtTab[i], 1);
1628 goto loaded;
1629 }
1630 }
1631 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001632 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001633 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001634 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1635 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1636 }
1637 if (encoding != NULL) {
1638 /*
1639 * TODO: we should not have to remap to the xmlCharEncoding
1640 * predefined set, a better interface than
1641 * xmlParserInputBufferCreateFilename should allow any
1642 * encoding supported by iconv
1643 */
1644 enc = xmlParseCharEncoding((const char *) encoding);
1645 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillard98485322003-08-14 15:44:40 +00001646 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillardd076a202002-11-20 13:28:31 +00001647 xmlGenericError(xmlGenericErrorContext,
1648 "XInclude: encoding %s not supported\n", encoding);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001649 ctxt->nbErrors++;
Daniel Veillardd076a202002-11-20 13:28:31 +00001650 xmlFree(encoding);
1651 xmlFree(URL);
1652 return(-1);
1653 }
1654 xmlFree(encoding);
1655 }
1656
1657 /*
1658 * Load it.
1659 */
1660 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001661 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001662 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001663 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001664 }
1665 node = xmlNewText(NULL);
1666
1667 /*
1668 * Scan all chars from the resource and add the to the node
1669 */
1670 while (xmlParserInputBufferRead(buf, 128) > 0) {
1671 int len;
1672 const xmlChar *content;
1673
1674 content = xmlBufferContent(buf->buffer);
1675 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001676 for (i = 0;i < len;) {
1677 int cur;
1678 int l;
1679
1680 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1681 if (!IS_CHAR(cur)) {
Daniel Veillard98485322003-08-14 15:44:40 +00001682 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001683 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd076a202002-11-20 13:28:31 +00001684 "XInclude: %s contains invalid char %d\n", URL, cur);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001685 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001686 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001687 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001688 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001689 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001690 }
1691 xmlBufferShrink(buf->buffer, len);
1692 }
1693 xmlFreeParserInputBuffer(buf);
1694 xmlXIncludeAddTxt(ctxt, node, URL);
1695
1696loaded:
1697 /*
1698 * Add the element as the replacement copy.
1699 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001700 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001701 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001702 return(0);
1703}
1704
1705/**
1706 * xmlXIncludeLoadFallback:
1707 * @ctxt: the XInclude context
1708 * @fallback: the fallback node
1709 * @nr: the xinclude node number
1710 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001711 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001712 * in the XInclude context
1713 *
1714 * Returns 0 in case of success, -1 in case of failure
1715 */
1716static int
1717xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1718 if ((fallback == NULL) || (ctxt == NULL))
1719 return(-1);
1720
Daniel Veillard06503452002-12-13 10:42:08 +00001721 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001722 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001723}
1724
1725/************************************************************************
1726 * *
1727 * XInclude Processing *
1728 * *
1729 ************************************************************************/
1730
1731/**
1732 * xmlXIncludePreProcessNode:
1733 * @ctxt: an XInclude context
1734 * @node: an XInclude node
1735 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001736 * Implement the XInclude preprocessing, currently just adding the element
1737 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001738 *
1739 * Returns the result list or NULL in case of error
1740 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001741static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001742xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1743 xmlXIncludeAddNode(ctxt, node);
1744 return(0);
1745}
1746
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001747/**
Owen Taylor3473f882001-02-23 17:55:21 +00001748 * xmlXIncludeLoadNode:
1749 * @ctxt: an XInclude context
1750 * @nr: the node number
1751 *
1752 * Find and load the infoset replacement for the given node.
1753 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001754 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001755 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001756static int
Owen Taylor3473f882001-02-23 17:55:21 +00001757xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1758 xmlNodePtr cur;
1759 xmlChar *href;
1760 xmlChar *parse;
1761 xmlChar *base;
1762 xmlChar *URI;
1763 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001764 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001765
1766 if (ctxt == NULL)
1767 return(-1);
1768 if ((nr < 0) || (nr >= ctxt->incNr))
1769 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001770 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001771 if (cur == NULL)
1772 return(-1);
1773
Owen Taylor3473f882001-02-23 17:55:21 +00001774 /*
1775 * read the attributes
1776 */
1777 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1778 if (href == NULL) {
1779 href = xmlGetProp(cur, XINCLUDE_HREF);
1780 if (href == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001781 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001782 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001783 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001784 return(-1);
1785 }
1786 }
1787 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1788 if (parse == NULL) {
1789 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1790 }
1791 if (parse != NULL) {
1792 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1793 xml = 1;
1794 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1795 xml = 0;
1796 else {
Daniel Veillard98485322003-08-14 15:44:40 +00001797 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001798 xmlGenericError(xmlGenericErrorContext,
1799 "XInclude: invalid value %s for %s\n",
1800 parse, XINCLUDE_PARSE);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001801 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001802 if (href != NULL)
1803 xmlFree(href);
1804 if (parse != NULL)
1805 xmlFree(parse);
1806 return(-1);
1807 }
1808 }
1809
1810 /*
1811 * compute the URI
1812 */
1813 base = xmlNodeGetBase(ctxt->doc, cur);
1814 if (base == NULL) {
1815 URI = xmlBuildURI(href, ctxt->doc->URL);
1816 } else {
1817 URI = xmlBuildURI(href, base);
1818 }
1819 if (URI == NULL) {
1820 xmlChar *escbase;
1821 xmlChar *eschref;
1822 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001823 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001824 */
1825 escbase = xmlURIEscape(base);
1826 eschref = xmlURIEscape(href);
1827 URI = xmlBuildURI(eschref, escbase);
1828 if (escbase != NULL)
1829 xmlFree(escbase);
1830 if (eschref != NULL)
1831 xmlFree(eschref);
1832 }
1833 if (URI == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001834 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001835 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001836 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001837 if (parse != NULL)
1838 xmlFree(parse);
1839 if (href != NULL)
1840 xmlFree(href);
1841 if (base != NULL)
1842 xmlFree(base);
1843 return(-1);
1844 }
1845#ifdef DEBUG_XINCLUDE
1846 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1847 xml ? "xml": "text");
1848 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1849#endif
1850
1851 /*
1852 * Cleanup
1853 */
1854 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001855 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001856 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1857 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001858 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1859 }
1860 if (ret < 0) {
1861 xmlNodePtr children;
1862
1863 /*
1864 * Time to try a fallback if availble
1865 */
1866#ifdef DEBUG_XINCLUDE
1867 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1868#endif
1869 children = cur->children;
1870 while (children != NULL) {
1871 if ((children->type == XML_ELEMENT_NODE) &&
1872 (children->ns != NULL) &&
1873 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1874 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1875 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1876 if (ret == 0)
1877 break;
1878 }
1879 children = children->next;
1880 }
1881 }
1882 if (ret < 0) {
Daniel Veillard98485322003-08-14 15:44:40 +00001883 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001884 xmlGenericError(xmlGenericErrorContext,
1885 "XInclude: could not load %s, and no fallback was found\n",
1886 URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001887 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001888 }
1889
1890 /*
1891 * Cleanup
1892 */
1893 if (URI != NULL)
1894 xmlFree(URI);
1895 if (parse != NULL)
1896 xmlFree(parse);
1897 if (href != NULL)
1898 xmlFree(href);
1899 if (base != NULL)
1900 xmlFree(base);
1901 return(0);
1902}
1903
1904/**
1905 * xmlXIncludeIncludeNode:
1906 * @ctxt: an XInclude context
1907 * @nr: the node number
1908 *
1909 * Inplement the infoset replacement for the given node
1910 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001911 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001912 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001913static int
Owen Taylor3473f882001-02-23 17:55:21 +00001914xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001915 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001916
1917 if (ctxt == NULL)
1918 return(-1);
1919 if ((nr < 0) || (nr >= ctxt->incNr))
1920 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001921 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001922 if (cur == NULL)
1923 return(-1);
1924
1925 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001926 * If we stored an XPointer a late computation may be needed
1927 */
1928 if ((ctxt->incTab[nr]->inc == NULL) &&
1929 (ctxt->incTab[nr]->xptr != NULL)) {
1930 ctxt->incTab[nr]->inc =
1931 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1932 ctxt->incTab[nr]->xptr);
1933 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1934 ctxt->incTab[nr]->xptr = NULL;
1935 }
1936 list = ctxt->incTab[nr]->inc;
1937 ctxt->incTab[nr]->inc = NULL;
1938
1939 /*
1940 * Check against the risk of generating a multi-rooted document
1941 */
1942 if ((cur->parent != NULL) &&
1943 (cur->parent->type != XML_ELEMENT_NODE)) {
1944 int nb_elem = 0;
1945
1946 tmp = list;
1947 while (tmp != NULL) {
1948 if (tmp->type == XML_ELEMENT_NODE)
1949 nb_elem++;
1950 tmp = tmp->next;
1951 }
1952 if (nb_elem > 1) {
Daniel Veillard98485322003-08-14 15:44:40 +00001953 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001954 xmlGenericError(xmlGenericErrorContext,
1955 "XInclude error: would result in multiple root nodes\n");
1956 ctxt->nbErrors++;
1957 return(-1);
1958 }
1959 }
1960
1961 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001962 * Change the current node as an XInclude start one, and add an
1963 * entity end one
1964 */
1965 cur->type = XML_XINCLUDE_START;
1966 end = xmlNewNode(cur->ns, cur->name);
1967 if (end == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001968 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001969 xmlGenericError(xmlGenericErrorContext,
1970 "XInclude: failed to build node\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001971 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001972 return(-1);
1973 }
1974 end->type = XML_XINCLUDE_END;
1975 xmlAddNextSibling(cur, end);
1976
1977 /*
1978 * Add the list of nodes
1979 */
Owen Taylor3473f882001-02-23 17:55:21 +00001980 while (list != NULL) {
1981 cur = list;
1982 list = list->next;
1983
1984 xmlAddPrevSibling(end, cur);
1985 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001986
1987
Owen Taylor3473f882001-02-23 17:55:21 +00001988 return(0);
1989}
1990
1991/**
1992 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001993 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001994 * @node: an XInclude node
1995 *
1996 * test if the node is an XInclude node
1997 *
1998 * Returns 1 true, 0 otherwise
1999 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002000static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002001xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002002 if (node == NULL)
2003 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002004 if (node->type != XML_ELEMENT_NODE)
2005 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002006 if (node->ns == NULL)
2007 return(0);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002008 if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
2009 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2010 xmlNodePtr child = node->children;
2011 int nb_fallback = 0;
2012
2013 while (child != NULL) {
2014 if ((child->type == XML_ELEMENT_NODE) &&
2015 (child->ns != NULL) &&
2016 (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
2017 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillard98485322003-08-14 15:44:40 +00002018 xmlXIncludeErrorContext(ctxt, node);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002019 xmlGenericError(xmlGenericErrorContext,
2020 "XInclude: %s has an %s child\n",
2021 XINCLUDE_NODE, XINCLUDE_NODE);
2022 ctxt->nbErrors++;
2023 return(0);
2024 }
2025 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2026 nb_fallback++;
2027 }
2028 }
2029 child = child->next;
2030 }
2031 if (nb_fallback > 1) {
Daniel Veillard98485322003-08-14 15:44:40 +00002032 xmlXIncludeErrorContext(ctxt, node);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002033 xmlGenericError(xmlGenericErrorContext,
2034 "XInclude: %s has %d %s children\n",
2035 XINCLUDE_NODE, nb_fallback, XINCLUDE_FALLBACK);
2036 ctxt->nbErrors++;
2037 return(0);
2038 }
2039 return(1);
2040 }
2041 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2042 if ((node->parent == NULL) ||
2043 (node->parent->type != XML_ELEMENT_NODE) ||
2044 (node->parent->ns == NULL) ||
2045 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
2046 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillard98485322003-08-14 15:44:40 +00002047 xmlXIncludeErrorContext(ctxt, node);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002048 xmlGenericError(xmlGenericErrorContext,
2049 "XInclude: %s is not the child of an %s\n",
2050 XINCLUDE_FALLBACK, XINCLUDE_NODE);
2051 ctxt->nbErrors++;
2052 }
2053 }
2054 }
Owen Taylor3473f882001-02-23 17:55:21 +00002055 return(0);
2056}
2057
2058/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002059 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002060 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002061 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002062 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00002063 *
2064 * Implement the XInclude substitution on the XML document @doc
2065 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002066 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002067 * or the number of substitutions done.
2068 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002069static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002070xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00002071 xmlNodePtr cur;
2072 int ret = 0;
2073 int i;
2074
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002075 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002076 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002077 if (ctxt == NULL)
2078 return(-1);
2079
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002080 if (doc->URL != NULL) {
2081 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2082 if (ret < 0)
2083 return(-1);
2084 }
2085
Owen Taylor3473f882001-02-23 17:55:21 +00002086 /*
2087 * First phase: lookup the elements in the document
2088 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002089 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002090 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002091 xmlXIncludePreProcessNode(ctxt, cur);
2092 while (cur != NULL) {
2093 /* TODO: need to work on entities -> stack */
2094 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002095 (cur->children->type != XML_ENTITY_DECL) &&
2096 (cur->children->type != XML_XINCLUDE_START) &&
2097 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002098 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002099 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002100 xmlXIncludePreProcessNode(ctxt, cur);
2101 } else if (cur->next != NULL) {
2102 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002103 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002104 xmlXIncludePreProcessNode(ctxt, cur);
2105 } else {
2106 do {
2107 cur = cur->parent;
2108 if (cur == NULL) break; /* do */
2109 if (cur->next != NULL) {
2110 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002111 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002112 xmlXIncludePreProcessNode(ctxt, cur);
2113 break; /* do */
2114 }
2115 } while (cur != NULL);
2116 }
2117 }
2118
2119 /*
2120 * Second Phase : collect the infosets fragments
2121 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002122 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002123 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002124 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002125 }
2126
2127 /*
2128 * Third phase: extend the original document infoset.
2129 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002130 if (ctxt->nbErrors == 0) {
2131 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2132 xmlXIncludeIncludeNode(ctxt, i);
2133 }
Owen Taylor3473f882001-02-23 17:55:21 +00002134 }
2135
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002136 if (doc->URL != NULL)
2137 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002138 return(ret);
2139}
2140
2141/**
2142 * xmlXIncludeProcess:
2143 * @doc: an XML document
2144 *
2145 * Implement the XInclude substitution on the XML document @doc
2146 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002147 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002148 * or the number of substitutions done.
2149 */
2150int
2151xmlXIncludeProcess(xmlDocPtr doc) {
2152 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002153 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002154 int ret = 0;
2155
2156 if (doc == NULL)
2157 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002158 tree = xmlDocGetRootElement(doc);
2159 if (tree == NULL)
2160 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002161 ctxt = xmlXIncludeNewContext(doc);
2162 if (ctxt == NULL)
2163 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002164 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2165 if ((ret >= 0) && (ctxt->nbErrors > 0))
2166 ret = -1;
2167
2168 xmlXIncludeFreeContext(ctxt);
2169 return(ret);
2170}
2171
2172/**
2173 * xmlXIncludeProcessTree:
2174 * @tree: a node in an XML document
2175 *
2176 * Implement the XInclude substitution for the given subtree
2177 *
2178 * Returns 0 if no substitution were done, -1 if some processing failed
2179 * or the number of substitutions done.
2180 */
2181int
2182xmlXIncludeProcessTree(xmlNodePtr tree) {
2183 xmlXIncludeCtxtPtr ctxt;
2184 int ret = 0;
2185
2186 if ((tree == NULL) || (tree->doc == NULL))
2187 return(-1);
2188 ctxt = xmlXIncludeNewContext(tree->doc);
2189 if (ctxt == NULL)
2190 return(-1);
2191 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00002192 if ((ret >= 0) && (ctxt->nbErrors > 0))
2193 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002194
Owen Taylor3473f882001-02-23 17:55:21 +00002195 xmlXIncludeFreeContext(ctxt);
2196 return(ret);
2197}
2198
2199#else /* !LIBXML_XINCLUDE_ENABLED */
2200#endif