blob: ef535420837348a5caf6d3108765b873a1f1c37e [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 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001119#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001120 case XPATH_RANGE:
1121 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001122#endif
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001123 case XPATH_POINT:
1124 /* points are ignored in XInclude */
1125 break;
1126 default:
1127 break;
1128 }
1129 return(list);
1130}
1131/************************************************************************
1132 * *
Owen Taylor3473f882001-02-23 17:55:21 +00001133 * XInclude I/O handling *
1134 * *
1135 ************************************************************************/
1136
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001137typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1138typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1139struct _xmlXIncludeMergeData {
1140 xmlDocPtr doc;
1141 xmlXIncludeCtxtPtr ctxt;
1142};
1143
Owen Taylor3473f882001-02-23 17:55:21 +00001144/**
Daniel Veillard4287c572003-02-04 22:48:53 +00001145 * xmlXIncludeMergeOneEntity:
1146 * @ent: the entity
1147 * @doc: the including doc
1148 * @nr: the entity name
1149 *
1150 * Inplements the merge of one entity
1151 */
1152static void
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001153xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
Daniel Veillard4287c572003-02-04 22:48:53 +00001154 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001155 xmlEntityPtr ret, prev;
1156 xmlDocPtr doc;
1157 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard4287c572003-02-04 22:48:53 +00001158
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001159 if ((ent == NULL) || (data == NULL))
Daniel Veillard4287c572003-02-04 22:48:53 +00001160 return;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001161 ctxt = data->ctxt;
1162 doc = data->doc;
1163 if ((ctxt == NULL) || (doc == NULL))
1164 return;
1165 switch (ent->etype) {
1166 case XML_INTERNAL_PARAMETER_ENTITY:
1167 case XML_EXTERNAL_PARAMETER_ENTITY:
1168 case XML_INTERNAL_PREDEFINED_ENTITY:
1169 return;
1170 case XML_INTERNAL_GENERAL_ENTITY:
1171 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1172 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1173 break;
1174 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001175 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1176 ent->SystemID, ent->content);
1177 if (ret != NULL) {
1178 if (ent->URI != NULL)
1179 ret->URI = xmlStrdup(ent->URI);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001180 } else {
1181 prev = xmlGetDocEntity(doc, ent->name);
1182 if (prev != NULL) {
1183 if (ent->etype != prev->etype)
1184 goto error;
1185
1186 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1187 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1188 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001189 } else if ((ent->ExternalID != NULL) &&
1190 (prev->ExternalID != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001191 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1192 goto error;
Daniel Veillard2406abd2003-02-24 18:16:47 +00001193 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1194 if (!xmlStrEqual(ent->content, prev->content))
1195 goto error;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001196 } else {
1197 goto error;
1198 }
1199
1200 }
Daniel Veillard4287c572003-02-04 22:48:53 +00001201 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001202 return;
1203error:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001204 switch (ent->etype) {
1205 case XML_INTERNAL_PARAMETER_ENTITY:
1206 case XML_EXTERNAL_PARAMETER_ENTITY:
1207 case XML_INTERNAL_PREDEFINED_ENTITY:
1208 case XML_INTERNAL_GENERAL_ENTITY:
1209 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1210 return;
1211 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1212 break;
1213 }
Daniel Veillard98485322003-08-14 15:44:40 +00001214 xmlXIncludeErrorContext(ctxt, (xmlNodePtr) ent);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001215 xmlGenericError(xmlGenericErrorContext,
1216 "XInclude: mismatch in redefinition of entity %s\n", ent->name);
1217 ctxt->nbErrors++;
Daniel Veillard4287c572003-02-04 22:48:53 +00001218}
1219
1220/**
1221 * xmlXIncludeMergeEntities:
1222 * @ctxt: an XInclude context
1223 * @doc: the including doc
1224 * @from: the included doc
1225 *
1226 * Inplements the entity merge
1227 *
1228 * Returns 0 if merge succeeded, -1 if some processing failed
1229 */
1230static int
1231xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1232 xmlDocPtr from) {
1233 xmlNodePtr cur;
1234 xmlDtdPtr target, source;
1235
1236 if (ctxt == NULL)
1237 return(-1);
1238
1239 if ((from == NULL) || (from->intSubset == NULL))
1240 return(0);
1241
1242 target = doc->intSubset;
1243 if (target == NULL) {
1244 cur = xmlDocGetRootElement(doc);
1245 if (cur == NULL)
1246 return(-1);
1247 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1248 if (target == NULL)
1249 return(-1);
1250 }
1251
1252 source = from->intSubset;
1253 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001254 xmlXIncludeMergeData data;
1255
1256 data.ctxt = ctxt;
1257 data.doc = doc;
1258
Daniel Veillard4287c572003-02-04 22:48:53 +00001259 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001260 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001261 }
1262 source = from->extSubset;
1263 if ((source != NULL) && (source->entities != NULL)) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001264 xmlXIncludeMergeData data;
1265
1266 data.ctxt = ctxt;
1267 data.doc = doc;
1268
Daniel Veillard4287c572003-02-04 22:48:53 +00001269 /*
1270 * don't duplicate existing stuff when external subsets are the same
1271 */
1272 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1273 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1274 xmlHashScan((xmlHashTablePtr) source->entities,
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001275 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
Daniel Veillard4287c572003-02-04 22:48:53 +00001276 }
1277 }
1278 return(0);
1279}
1280
1281/**
Owen Taylor3473f882001-02-23 17:55:21 +00001282 * xmlXIncludeLoadDoc:
1283 * @ctxt: the XInclude context
1284 * @url: the associated URL
1285 * @nr: the xinclude node number
1286 *
1287 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001288 *
1289 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001290 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001291static int
Owen Taylor3473f882001-02-23 17:55:21 +00001292xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1293 xmlDocPtr doc;
1294 xmlURIPtr uri;
1295 xmlChar *URL;
1296 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001297 int i = 0;
1298
1299#ifdef DEBUG_XINCLUDE
1300 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1301#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001302 /*
1303 * Check the URL and remove any fragment identifier
1304 */
1305 uri = xmlParseURI((const char *)url);
1306 if (uri == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001307 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001308 xmlGenericError(xmlGenericErrorContext,
1309 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001310 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001311 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001312 }
1313 if (uri->fragment != NULL) {
1314 fragment = (xmlChar *) uri->fragment;
1315 uri->fragment = NULL;
1316 }
1317 URL = xmlSaveUri(uri);
1318 xmlFreeURI(uri);
1319 if (URL == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001320 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001321 xmlGenericError(xmlGenericErrorContext,
1322 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001323 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001324 if (fragment != NULL)
1325 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001326 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001327 }
1328
1329 /*
1330 * Handling of references to the local document are done
1331 * directly through ctxt->doc.
1332 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001333 if ((URL[0] == 0) || (URL[0] == '#') ||
1334 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001335 doc = NULL;
1336 goto loaded;
1337 }
1338
1339 /*
1340 * Prevent reloading twice the document.
1341 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001342 for (i = 0; i < ctxt->incNr; i++) {
1343 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1344 (ctxt->incTab[i]->doc != NULL)) {
1345 doc = ctxt->incTab[i]->doc;
1346#ifdef DEBUG_XINCLUDE
1347 printf("Already loaded %s\n", URL);
1348#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001349 goto loaded;
1350 }
1351 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001352
Owen Taylor3473f882001-02-23 17:55:21 +00001353 /*
1354 * Load it.
1355 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001356#ifdef DEBUG_XINCLUDE
1357 printf("loading %s\n", URL);
1358#endif
Daniel Veillard98485322003-08-14 15:44:40 +00001359 doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001360 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001361 xmlFree(URL);
1362 if (fragment != NULL)
1363 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001364 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001365 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001366 ctxt->incTab[nr]->doc = doc;
Daniel Veillard98485322003-08-14 15:44:40 +00001367 for (i = nr + 1; i < ctxt->incNr; i++) {
1368 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1369 ctxt->incTab[nr]->count++;
1370#ifdef DEBUG_XINCLUDE
1371 printf("Increasing %s count since reused\n", URL);
1372#endif
1373 break;
1374 }
1375 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001376
1377 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001378 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001379 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001380 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001381
1382 /*
1383 * We don't need the DTD anymore, free up space
1384 if (doc->intSubset != NULL) {
1385 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1386 xmlFreeNode((xmlNodePtr) doc->intSubset);
1387 doc->intSubset = NULL;
1388 }
1389 if (doc->extSubset != NULL) {
1390 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1391 xmlFreeNode((xmlNodePtr) doc->extSubset);
1392 doc->extSubset = NULL;
1393 }
1394 */
1395 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001396
1397loaded:
1398 if (fragment == NULL) {
1399 /*
1400 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001401 */
1402 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001403 {
1404 /* Hopefully a DTD declaration won't be copied from
1405 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001406 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001407 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001408 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001409 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001410 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001411 }
1412#ifdef LIBXML_XPTR_ENABLED
1413 else {
Owen Taylor3473f882001-02-23 17:55:21 +00001414 /*
1415 * Computes the XPointer expression and make a copy used
1416 * as the replacement copy.
1417 */
1418 xmlXPathObjectPtr xptr;
1419 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001420 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001421
1422 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001423 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1424 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001425 } else {
1426 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1427 }
1428 if (xptrctxt == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001429 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001430 xmlGenericError(xmlGenericErrorContext,
1431 "XInclude: could create XPointer context\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001432 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001433 xmlFree(URL);
1434 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001435 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001436 }
1437 xptr = xmlXPtrEval(fragment, xptrctxt);
1438 if (xptr == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001439 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001440 xmlGenericError(xmlGenericErrorContext,
1441 "XInclude: XPointer evaluation failed: #%s\n",
1442 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001443 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001444 xmlXPathFreeContext(xptrctxt);
1445 xmlFree(URL);
1446 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001447 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001448 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001449 switch (xptr->type) {
1450 case XPATH_UNDEFINED:
1451 case XPATH_BOOLEAN:
1452 case XPATH_NUMBER:
1453 case XPATH_STRING:
1454 case XPATH_POINT:
1455 case XPATH_USERS:
1456 case XPATH_XSLT_TREE:
Daniel Veillard98485322003-08-14 15:44:40 +00001457 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001458 xmlGenericError(xmlGenericErrorContext,
1459 "XInclude: XPointer is not a range: #%s\n",
1460 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001461 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001462 xmlXPathFreeContext(xptrctxt);
1463 xmlFree(URL);
1464 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001465 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001466 case XPATH_NODESET:
1467 case XPATH_RANGE:
1468 case XPATH_LOCATIONSET:
1469 break;
1470 }
1471 set = xptr->nodesetval;
1472 if (set != NULL) {
1473 for (i = 0;i < set->nodeNr;i++) {
1474 if (set->nodeTab[i] == NULL)
1475 continue;
1476 switch (set->nodeTab[i]->type) {
1477 case XML_TEXT_NODE:
1478 case XML_CDATA_SECTION_NODE:
1479 case XML_ELEMENT_NODE:
1480 case XML_ENTITY_REF_NODE:
1481 case XML_ENTITY_NODE:
1482 case XML_PI_NODE:
1483 case XML_COMMENT_NODE:
1484 case XML_DOCUMENT_NODE:
1485 case XML_HTML_DOCUMENT_NODE:
1486#ifdef LIBXML_DOCB_ENABLED
1487 case XML_DOCB_DOCUMENT_NODE:
1488#endif
1489 continue;
1490 case XML_ATTRIBUTE_NODE:
Daniel Veillard98485322003-08-14 15:44:40 +00001491 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001492 xmlGenericError(xmlGenericErrorContext,
1493 "XInclude: XPointer selects an attribute: #%s\n",
1494 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001495 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001496 set->nodeTab[i] = NULL;
1497 continue;
1498 case XML_NAMESPACE_DECL:
Daniel Veillard98485322003-08-14 15:44:40 +00001499 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001500 xmlGenericError(xmlGenericErrorContext,
1501 "XInclude: XPointer selects a namespace: #%s\n",
1502 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001503 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001504 set->nodeTab[i] = NULL;
1505 continue;
1506 case XML_DOCUMENT_TYPE_NODE:
1507 case XML_DOCUMENT_FRAG_NODE:
1508 case XML_NOTATION_NODE:
1509 case XML_DTD_NODE:
1510 case XML_ELEMENT_DECL:
1511 case XML_ATTRIBUTE_DECL:
1512 case XML_ENTITY_DECL:
1513 case XML_XINCLUDE_START:
1514 case XML_XINCLUDE_END:
Daniel Veillard98485322003-08-14 15:44:40 +00001515 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001516 xmlGenericError(xmlGenericErrorContext,
1517 "XInclude: XPointer selects unexpected nodes: #%s\n",
1518 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001519 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001520 set->nodeTab[i] = NULL;
1521 set->nodeTab[i] = NULL;
1522 continue; /* for */
1523 }
1524 }
1525 }
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001526 if (doc == NULL) {
1527 ctxt->incTab[nr]->xptr = xptr;
1528 ctxt->incTab[nr]->inc = NULL;
1529 } else {
1530 ctxt->incTab[nr]->inc =
1531 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1532 xmlXPathFreeObject(xptr);
1533 }
Owen Taylor3473f882001-02-23 17:55:21 +00001534 xmlXPathFreeContext(xptrctxt);
1535 xmlFree(fragment);
1536 }
Daniel Veillard10acc2f2003-09-01 20:59:40 +00001537#endif
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001538
1539 /*
1540 * Do the xml:base fixup if needed
1541 */
1542 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1543 xmlNodePtr node;
1544
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001545 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001546 while (node != NULL) {
1547 if (node->type == XML_ELEMENT_NODE)
1548 xmlNodeSetBase(node, URL);
1549 node = node->next;
1550 }
1551 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001552 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1553 (ctxt->incTab[nr]->count <= 1)) {
1554#ifdef DEBUG_XINCLUDE
1555 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1556#endif
1557 xmlFreeDoc(ctxt->incTab[nr]->doc);
1558 ctxt->incTab[nr]->doc = NULL;
1559 }
Owen Taylor3473f882001-02-23 17:55:21 +00001560 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001561 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001562}
1563
1564/**
1565 * xmlXIncludeLoadTxt:
1566 * @ctxt: the XInclude context
1567 * @url: the associated URL
1568 * @nr: the xinclude node number
1569 *
1570 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001571 *
1572 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001573 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001574static int
Owen Taylor3473f882001-02-23 17:55:21 +00001575xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1576 xmlParserInputBufferPtr buf;
1577 xmlNodePtr node;
1578 xmlURIPtr uri;
1579 xmlChar *URL;
1580 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001581 xmlChar *encoding = NULL;
William M. Brack78637da2003-07-31 14:47:38 +00001582 xmlCharEncoding enc = (xmlCharEncoding) 0;
Daniel Veillardd076a202002-11-20 13:28:31 +00001583
Owen Taylor3473f882001-02-23 17:55:21 +00001584 /*
1585 * Check the URL and remove any fragment identifier
1586 */
1587 uri = xmlParseURI((const char *)url);
1588 if (uri == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001589 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001590 xmlGenericError(xmlGenericErrorContext,
1591 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001592 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001593 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001594 }
1595 if (uri->fragment != NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001596 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001597 xmlGenericError(xmlGenericErrorContext,
1598 "XInclude: fragment identifier forbidden for text: %s\n",
1599 uri->fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001600 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001601 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001602 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001603 }
1604 URL = xmlSaveUri(uri);
1605 xmlFreeURI(uri);
1606 if (URL == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001607 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001608 xmlGenericError(xmlGenericErrorContext,
1609 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001610 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001611 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001612 }
1613
1614 /*
1615 * Handling of references to the local document are done
1616 * directly through ctxt->doc.
1617 */
1618 if (URL[0] == 0) {
Daniel Veillard98485322003-08-14 15:44:40 +00001619 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001620 xmlGenericError(xmlGenericErrorContext,
1621 "XInclude: text serialization of document not available\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001622 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001623 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001624 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001625 }
1626
1627 /*
1628 * Prevent reloading twice the document.
1629 */
1630 for (i = 0; i < ctxt->txtNr; i++) {
1631 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1632 node = xmlCopyNode(ctxt->txtTab[i], 1);
1633 goto loaded;
1634 }
1635 }
1636 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001637 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001638 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001639 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1640 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1641 }
1642 if (encoding != NULL) {
1643 /*
1644 * TODO: we should not have to remap to the xmlCharEncoding
1645 * predefined set, a better interface than
1646 * xmlParserInputBufferCreateFilename should allow any
1647 * encoding supported by iconv
1648 */
1649 enc = xmlParseCharEncoding((const char *) encoding);
1650 if (enc == XML_CHAR_ENCODING_ERROR) {
Daniel Veillard98485322003-08-14 15:44:40 +00001651 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillardd076a202002-11-20 13:28:31 +00001652 xmlGenericError(xmlGenericErrorContext,
1653 "XInclude: encoding %s not supported\n", encoding);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001654 ctxt->nbErrors++;
Daniel Veillardd076a202002-11-20 13:28:31 +00001655 xmlFree(encoding);
1656 xmlFree(URL);
1657 return(-1);
1658 }
1659 xmlFree(encoding);
1660 }
1661
1662 /*
1663 * Load it.
1664 */
1665 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001666 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001667 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001668 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001669 }
1670 node = xmlNewText(NULL);
1671
1672 /*
1673 * Scan all chars from the resource and add the to the node
1674 */
1675 while (xmlParserInputBufferRead(buf, 128) > 0) {
1676 int len;
1677 const xmlChar *content;
1678
1679 content = xmlBufferContent(buf->buffer);
1680 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001681 for (i = 0;i < len;) {
1682 int cur;
1683 int l;
1684
1685 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1686 if (!IS_CHAR(cur)) {
Daniel Veillard98485322003-08-14 15:44:40 +00001687 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001688 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd076a202002-11-20 13:28:31 +00001689 "XInclude: %s contains invalid char %d\n", URL, cur);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001690 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001691 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001692 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001693 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001694 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001695 }
1696 xmlBufferShrink(buf->buffer, len);
1697 }
1698 xmlFreeParserInputBuffer(buf);
1699 xmlXIncludeAddTxt(ctxt, node, URL);
1700
1701loaded:
1702 /*
1703 * Add the element as the replacement copy.
1704 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001705 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001706 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001707 return(0);
1708}
1709
1710/**
1711 * xmlXIncludeLoadFallback:
1712 * @ctxt: the XInclude context
1713 * @fallback: the fallback node
1714 * @nr: the xinclude node number
1715 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001716 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001717 * in the XInclude context
1718 *
1719 * Returns 0 in case of success, -1 in case of failure
1720 */
1721static int
1722xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1723 if ((fallback == NULL) || (ctxt == NULL))
1724 return(-1);
1725
Daniel Veillard06503452002-12-13 10:42:08 +00001726 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001727 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001728}
1729
1730/************************************************************************
1731 * *
1732 * XInclude Processing *
1733 * *
1734 ************************************************************************/
1735
1736/**
1737 * xmlXIncludePreProcessNode:
1738 * @ctxt: an XInclude context
1739 * @node: an XInclude node
1740 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001741 * Implement the XInclude preprocessing, currently just adding the element
1742 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001743 *
1744 * Returns the result list or NULL in case of error
1745 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001746static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001747xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1748 xmlXIncludeAddNode(ctxt, node);
1749 return(0);
1750}
1751
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001752/**
Owen Taylor3473f882001-02-23 17:55:21 +00001753 * xmlXIncludeLoadNode:
1754 * @ctxt: an XInclude context
1755 * @nr: the node number
1756 *
1757 * Find and load the infoset replacement for the given node.
1758 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001759 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001760 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001761static int
Owen Taylor3473f882001-02-23 17:55:21 +00001762xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1763 xmlNodePtr cur;
1764 xmlChar *href;
1765 xmlChar *parse;
1766 xmlChar *base;
1767 xmlChar *URI;
1768 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001769 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001770
1771 if (ctxt == NULL)
1772 return(-1);
1773 if ((nr < 0) || (nr >= ctxt->incNr))
1774 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001775 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001776 if (cur == NULL)
1777 return(-1);
1778
Owen Taylor3473f882001-02-23 17:55:21 +00001779 /*
1780 * read the attributes
1781 */
1782 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1783 if (href == NULL) {
1784 href = xmlGetProp(cur, XINCLUDE_HREF);
1785 if (href == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001786 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001787 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001788 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001789 return(-1);
1790 }
1791 }
1792 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1793 if (parse == NULL) {
1794 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1795 }
1796 if (parse != NULL) {
1797 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1798 xml = 1;
1799 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1800 xml = 0;
1801 else {
Daniel Veillard98485322003-08-14 15:44:40 +00001802 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001803 xmlGenericError(xmlGenericErrorContext,
1804 "XInclude: invalid value %s for %s\n",
1805 parse, XINCLUDE_PARSE);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001806 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001807 if (href != NULL)
1808 xmlFree(href);
1809 if (parse != NULL)
1810 xmlFree(parse);
1811 return(-1);
1812 }
1813 }
1814
1815 /*
1816 * compute the URI
1817 */
1818 base = xmlNodeGetBase(ctxt->doc, cur);
1819 if (base == NULL) {
1820 URI = xmlBuildURI(href, ctxt->doc->URL);
1821 } else {
1822 URI = xmlBuildURI(href, base);
1823 }
1824 if (URI == NULL) {
1825 xmlChar *escbase;
1826 xmlChar *eschref;
1827 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001828 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001829 */
1830 escbase = xmlURIEscape(base);
1831 eschref = xmlURIEscape(href);
1832 URI = xmlBuildURI(eschref, escbase);
1833 if (escbase != NULL)
1834 xmlFree(escbase);
1835 if (eschref != NULL)
1836 xmlFree(eschref);
1837 }
1838 if (URI == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001839 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001840 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001841 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001842 if (parse != NULL)
1843 xmlFree(parse);
1844 if (href != NULL)
1845 xmlFree(href);
1846 if (base != NULL)
1847 xmlFree(base);
1848 return(-1);
1849 }
1850#ifdef DEBUG_XINCLUDE
1851 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1852 xml ? "xml": "text");
1853 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1854#endif
1855
1856 /*
1857 * Cleanup
1858 */
1859 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001860 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001861 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1862 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001863 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1864 }
1865 if (ret < 0) {
1866 xmlNodePtr children;
1867
1868 /*
1869 * Time to try a fallback if availble
1870 */
1871#ifdef DEBUG_XINCLUDE
1872 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1873#endif
1874 children = cur->children;
1875 while (children != NULL) {
1876 if ((children->type == XML_ELEMENT_NODE) &&
1877 (children->ns != NULL) &&
1878 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1879 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1880 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1881 if (ret == 0)
1882 break;
1883 }
1884 children = children->next;
1885 }
1886 }
1887 if (ret < 0) {
Daniel Veillard98485322003-08-14 15:44:40 +00001888 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001889 xmlGenericError(xmlGenericErrorContext,
1890 "XInclude: could not load %s, and no fallback was found\n",
1891 URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001892 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001893 }
1894
1895 /*
1896 * Cleanup
1897 */
1898 if (URI != NULL)
1899 xmlFree(URI);
1900 if (parse != NULL)
1901 xmlFree(parse);
1902 if (href != NULL)
1903 xmlFree(href);
1904 if (base != NULL)
1905 xmlFree(base);
1906 return(0);
1907}
1908
1909/**
1910 * xmlXIncludeIncludeNode:
1911 * @ctxt: an XInclude context
1912 * @nr: the node number
1913 *
1914 * Inplement the infoset replacement for the given node
1915 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001916 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001917 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001918static int
Owen Taylor3473f882001-02-23 17:55:21 +00001919xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001920 xmlNodePtr cur, end, list, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00001921
1922 if (ctxt == NULL)
1923 return(-1);
1924 if ((nr < 0) || (nr >= ctxt->incNr))
1925 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001926 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001927 if (cur == NULL)
1928 return(-1);
1929
1930 /*
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001931 * If we stored an XPointer a late computation may be needed
1932 */
1933 if ((ctxt->incTab[nr]->inc == NULL) &&
1934 (ctxt->incTab[nr]->xptr != NULL)) {
1935 ctxt->incTab[nr]->inc =
1936 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1937 ctxt->incTab[nr]->xptr);
1938 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1939 ctxt->incTab[nr]->xptr = NULL;
1940 }
1941 list = ctxt->incTab[nr]->inc;
1942 ctxt->incTab[nr]->inc = NULL;
1943
1944 /*
1945 * Check against the risk of generating a multi-rooted document
1946 */
1947 if ((cur->parent != NULL) &&
1948 (cur->parent->type != XML_ELEMENT_NODE)) {
1949 int nb_elem = 0;
1950
1951 tmp = list;
1952 while (tmp != NULL) {
1953 if (tmp->type == XML_ELEMENT_NODE)
1954 nb_elem++;
1955 tmp = tmp->next;
1956 }
1957 if (nb_elem > 1) {
Daniel Veillard98485322003-08-14 15:44:40 +00001958 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001959 xmlGenericError(xmlGenericErrorContext,
1960 "XInclude error: would result in multiple root nodes\n");
1961 ctxt->nbErrors++;
1962 return(-1);
1963 }
1964 }
1965
1966 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001967 * Change the current node as an XInclude start one, and add an
1968 * entity end one
1969 */
1970 cur->type = XML_XINCLUDE_START;
1971 end = xmlNewNode(cur->ns, cur->name);
1972 if (end == NULL) {
Daniel Veillard98485322003-08-14 15:44:40 +00001973 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
Owen Taylor3473f882001-02-23 17:55:21 +00001974 xmlGenericError(xmlGenericErrorContext,
1975 "XInclude: failed to build node\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001976 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001977 return(-1);
1978 }
1979 end->type = XML_XINCLUDE_END;
1980 xmlAddNextSibling(cur, end);
1981
1982 /*
1983 * Add the list of nodes
1984 */
Owen Taylor3473f882001-02-23 17:55:21 +00001985 while (list != NULL) {
1986 cur = list;
1987 list = list->next;
1988
1989 xmlAddPrevSibling(end, cur);
1990 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001991
1992
Owen Taylor3473f882001-02-23 17:55:21 +00001993 return(0);
1994}
1995
1996/**
1997 * xmlXIncludeTestNode:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00001998 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00001999 * @node: an XInclude node
2000 *
2001 * test if the node is an XInclude node
2002 *
2003 * Returns 1 true, 0 otherwise
2004 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002005static int
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002006xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (node == NULL)
2008 return(0);
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002009 if (node->type != XML_ELEMENT_NODE)
2010 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002011 if (node->ns == NULL)
2012 return(0);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002013 if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
2014 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2015 xmlNodePtr child = node->children;
2016 int nb_fallback = 0;
2017
2018 while (child != NULL) {
2019 if ((child->type == XML_ELEMENT_NODE) &&
2020 (child->ns != NULL) &&
2021 (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
2022 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
Daniel Veillard98485322003-08-14 15:44:40 +00002023 xmlXIncludeErrorContext(ctxt, node);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002024 xmlGenericError(xmlGenericErrorContext,
2025 "XInclude: %s has an %s child\n",
2026 XINCLUDE_NODE, XINCLUDE_NODE);
2027 ctxt->nbErrors++;
2028 return(0);
2029 }
2030 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2031 nb_fallback++;
2032 }
2033 }
2034 child = child->next;
2035 }
2036 if (nb_fallback > 1) {
Daniel Veillard98485322003-08-14 15:44:40 +00002037 xmlXIncludeErrorContext(ctxt, node);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002038 xmlGenericError(xmlGenericErrorContext,
2039 "XInclude: %s has %d %s children\n",
2040 XINCLUDE_NODE, nb_fallback, XINCLUDE_FALLBACK);
2041 ctxt->nbErrors++;
2042 return(0);
2043 }
2044 return(1);
2045 }
2046 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2047 if ((node->parent == NULL) ||
2048 (node->parent->type != XML_ELEMENT_NODE) ||
2049 (node->parent->ns == NULL) ||
2050 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
2051 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
Daniel Veillard98485322003-08-14 15:44:40 +00002052 xmlXIncludeErrorContext(ctxt, node);
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002053 xmlGenericError(xmlGenericErrorContext,
2054 "XInclude: %s is not the child of an %s\n",
2055 XINCLUDE_FALLBACK, XINCLUDE_NODE);
2056 ctxt->nbErrors++;
2057 }
2058 }
2059 }
Owen Taylor3473f882001-02-23 17:55:21 +00002060 return(0);
2061}
2062
2063/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002064 * xmlXIncludeDoProcess:
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002065 * @ctxt: the XInclude processing context
Owen Taylor3473f882001-02-23 17:55:21 +00002066 * @doc: an XML document
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002067 * @tree: the top of the tree to process
Owen Taylor3473f882001-02-23 17:55:21 +00002068 *
2069 * Implement the XInclude substitution on the XML document @doc
2070 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002071 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00002072 * or the number of substitutions done.
2073 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002074static int
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002075xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
Owen Taylor3473f882001-02-23 17:55:21 +00002076 xmlNodePtr cur;
2077 int ret = 0;
2078 int i;
2079
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002080 if ((doc == NULL) || (tree == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002081 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002082 if (ctxt == NULL)
2083 return(-1);
2084
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002085 if (doc->URL != NULL) {
2086 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2087 if (ret < 0)
2088 return(-1);
2089 }
2090
Owen Taylor3473f882001-02-23 17:55:21 +00002091 /*
2092 * First phase: lookup the elements in the document
2093 */
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002094 cur = tree;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002095 if (xmlXIncludeTestNode(ctxt, cur) == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00002096 xmlXIncludePreProcessNode(ctxt, cur);
2097 while (cur != NULL) {
2098 /* TODO: need to work on entities -> stack */
2099 if ((cur->children != NULL) &&
Daniel Veillardffe4f5e2003-07-06 17:35:43 +00002100 (cur->children->type != XML_ENTITY_DECL) &&
2101 (cur->children->type != XML_XINCLUDE_START) &&
2102 (cur->children->type != XML_XINCLUDE_END)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002103 cur = cur->children;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002104 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002105 xmlXIncludePreProcessNode(ctxt, cur);
2106 } else if (cur->next != NULL) {
2107 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002108 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002109 xmlXIncludePreProcessNode(ctxt, cur);
2110 } else {
2111 do {
2112 cur = cur->parent;
2113 if (cur == NULL) break; /* do */
2114 if (cur->next != NULL) {
2115 cur = cur->next;
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002116 if (xmlXIncludeTestNode(ctxt, cur))
Owen Taylor3473f882001-02-23 17:55:21 +00002117 xmlXIncludePreProcessNode(ctxt, cur);
2118 break; /* do */
2119 }
2120 } while (cur != NULL);
2121 }
2122 }
2123
2124 /*
2125 * Second Phase : collect the infosets fragments
2126 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00002127 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00002128 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00002129 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00002130 }
2131
2132 /*
2133 * Third phase: extend the original document infoset.
2134 */
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002135 if (ctxt->nbErrors == 0) {
2136 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2137 xmlXIncludeIncludeNode(ctxt, i);
2138 }
Owen Taylor3473f882001-02-23 17:55:21 +00002139 }
2140
Daniel Veillardf4b4f982003-02-13 11:02:08 +00002141 if (doc->URL != NULL)
2142 xmlXIncludeURLPop(ctxt);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002143 return(ret);
2144}
2145
2146/**
2147 * xmlXIncludeProcess:
2148 * @doc: an XML document
2149 *
2150 * Implement the XInclude substitution on the XML document @doc
2151 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002152 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002153 * or the number of substitutions done.
2154 */
2155int
2156xmlXIncludeProcess(xmlDocPtr doc) {
2157 xmlXIncludeCtxtPtr ctxt;
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002158 xmlNodePtr tree;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002159 int ret = 0;
2160
2161 if (doc == NULL)
2162 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002163 tree = xmlDocGetRootElement(doc);
2164 if (tree == NULL)
2165 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002166 ctxt = xmlXIncludeNewContext(doc);
2167 if (ctxt == NULL)
2168 return(-1);
Daniel Veillard8edf1c52003-07-22 20:52:14 +00002169 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2170 if ((ret >= 0) && (ctxt->nbErrors > 0))
2171 ret = -1;
2172
2173 xmlXIncludeFreeContext(ctxt);
2174 return(ret);
2175}
2176
2177/**
2178 * xmlXIncludeProcessTree:
2179 * @tree: a node in an XML document
2180 *
2181 * Implement the XInclude substitution for the given subtree
2182 *
2183 * Returns 0 if no substitution were done, -1 if some processing failed
2184 * or the number of substitutions done.
2185 */
2186int
2187xmlXIncludeProcessTree(xmlNodePtr tree) {
2188 xmlXIncludeCtxtPtr ctxt;
2189 int ret = 0;
2190
2191 if ((tree == NULL) || (tree->doc == NULL))
2192 return(-1);
2193 ctxt = xmlXIncludeNewContext(tree->doc);
2194 if (ctxt == NULL)
2195 return(-1);
2196 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00002197 if ((ret >= 0) && (ctxt->nbErrors > 0))
2198 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00002199
Owen Taylor3473f882001-02-23 17:55:21 +00002200 xmlXIncludeFreeContext(ctxt);
2201 return(ret);
2202}
2203
2204#else /* !LIBXML_XINCLUDE_ENABLED */
2205#endif