blob: d0d125f88622424d8725f9148c1279689c7d0854 [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
12/*
13 * TODO: compute XPointers nodesets
Daniel Veillardd16df9f2001-05-23 13:44:21 +000014 * TODO: add an node intermediate API and handle recursion at this level
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21#include <libxml/xmlmemory.h>
22#include <libxml/tree.h>
23#include <libxml/parser.h>
24#include <libxml/uri.h>
25#include <libxml/xpointer.h>
26#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000027#include <libxml/xmlerror.h>
Daniel Veillardd076a202002-11-20 13:28:31 +000028#include <libxml/encoding.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000029#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000030
31#ifdef LIBXML_XINCLUDE_ENABLED
32#include <libxml/xinclude.h>
33
Daniel Veillardbbd22452001-05-23 12:02:27 +000034#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
Owen Taylor3473f882001-02-23 17:55:21 +000035#define XINCLUDE_NODE (const xmlChar *) "include"
Daniel Veillard58e44c92002-08-02 22:19:49 +000036#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
Owen Taylor3473f882001-02-23 17:55:21 +000037#define XINCLUDE_HREF (const xmlChar *) "href"
38#define XINCLUDE_PARSE (const xmlChar *) "parse"
39#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
40#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
Daniel Veillardd076a202002-11-20 13:28:31 +000041#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
Owen Taylor3473f882001-02-23 17:55:21 +000042
43/* #define DEBUG_XINCLUDE */
Daniel Veillard017b1082001-06-21 11:20:21 +000044#ifdef DEBUG_XINCLUDE
45#ifdef LIBXML_DEBUG_ENABLED
46#include <libxml/debugXML.h>
47#endif
48#endif
Owen Taylor3473f882001-02-23 17:55:21 +000049
50/************************************************************************
51 * *
52 * XInclude contexts handling *
53 * *
54 ************************************************************************/
55
56/*
57 * An XInclude context
58 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000059typedef xmlChar *xmlURL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +000060
61typedef struct _xmlXIncludeRef xmlXIncludeRef;
62typedef xmlXIncludeRef *xmlXIncludeRefPtr;
63struct _xmlXIncludeRef {
64 xmlChar *URI; /* the rully resolved resource URL */
65 xmlChar *fragment; /* the fragment in the URI */
66 xmlDocPtr doc; /* the parsed document */
67 xmlNodePtr ref; /* the node making the reference in the source */
68 xmlNodePtr inc; /* the included copy */
69 int xml; /* xml or txt */
70 int count; /* how many refs use that specific doc */
71};
72
Owen Taylor3473f882001-02-23 17:55:21 +000073typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
74typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
75struct _xmlXIncludeCtxt {
76 xmlDocPtr doc; /* the source document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000077 int incBase; /* the first include for this document */
Owen Taylor3473f882001-02-23 17:55:21 +000078 int incNr; /* number of includes */
79 int incMax; /* size of includes tab */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000080 xmlXIncludeRefPtr *incTab; /* array of included references */
81
Owen Taylor3473f882001-02-23 17:55:21 +000082 int txtNr; /* number of unparsed documents */
83 int txtMax; /* size of unparsed documents tab */
84 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000085 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Daniel Veillardd581b7e2003-02-11 18:03:05 +000086
87 int nbErrors; /* the number of errors detected */
Owen Taylor3473f882001-02-23 17:55:21 +000088};
89
Daniel Veillardd16df9f2001-05-23 13:44:21 +000090static int
91xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
Owen Taylor3473f882001-02-23 17:55:21 +000092
93/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +000094 * xmlXIncludeFreeRef:
95 * @ref: the XInclude reference
96 *
97 * Free an XInclude reference
98 */
99static void
100xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
101 if (ref == NULL)
102 return;
103#ifdef DEBUG_XINCLUDE
104 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
105#endif
106 if (ref->doc != NULL) {
107#ifdef DEBUG_XINCLUDE
108 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
109#endif
110 xmlFreeDoc(ref->doc);
111 }
112 if (ref->URI != NULL)
113 xmlFree(ref->URI);
114 if (ref->fragment != NULL)
115 xmlFree(ref->fragment);
116 xmlFree(ref);
117}
118
119/**
120 * xmlXIncludeNewRef:
121 * @ctxt: the XInclude context
122 * @URI: the resource URI
123 *
124 * Creates a new reference within an XInclude context
125 *
126 * Returns the new set
127 */
128static xmlXIncludeRefPtr
129xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
130 xmlNodePtr ref) {
131 xmlXIncludeRefPtr ret;
132
133#ifdef DEBUG_XINCLUDE
134 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
135#endif
136 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
137 if (ret == NULL)
138 return(NULL);
139 memset(ret, 0, sizeof(xmlXIncludeRef));
140 if (URI == NULL)
141 ret->URI = NULL;
142 else
143 ret->URI = xmlStrdup(URI);
144 ret->fragment = NULL;
145 ret->ref = ref;
146 ret->doc = 0;
147 ret->count = 0;
148 ret->xml = 0;
149 ret->inc = NULL;
150 if (ctxt->incMax == 0) {
151 ctxt->incMax = 4;
152 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
153 sizeof(ctxt->incTab[0]));
154 if (ctxt->incTab == NULL) {
155 xmlGenericError(xmlGenericErrorContext,
156 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000157 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000158 xmlXIncludeFreeRef(ret);
159 return(NULL);
160 }
161 }
162 if (ctxt->incNr >= ctxt->incMax) {
163 ctxt->incMax *= 2;
164 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
165 ctxt->incMax * sizeof(ctxt->incTab[0]));
166 if (ctxt->incTab == NULL) {
167 xmlGenericError(xmlGenericErrorContext,
168 "realloc failed !\n");
169 xmlXIncludeFreeRef(ret);
170 return(NULL);
171 }
172 }
173 ctxt->incTab[ctxt->incNr++] = ret;
174 return(ret);
175}
176
177/**
Owen Taylor3473f882001-02-23 17:55:21 +0000178 * xmlXIncludeNewContext:
179 * @doc: an XML Document
180 *
181 * Creates a new XInclude context
182 *
183 * Returns the new set
184 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000185static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000186xmlXIncludeNewContext(xmlDocPtr doc) {
187 xmlXIncludeCtxtPtr ret;
188
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000189#ifdef DEBUG_XINCLUDE
190 xmlGenericError(xmlGenericErrorContext, "New context\n");
191#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000192 if (doc == NULL)
193 return(NULL);
194 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
195 if (ret == NULL)
196 return(NULL);
197 memset(ret, 0, sizeof(xmlXIncludeCtxt));
198 ret->doc = doc;
199 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000200 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000201 ret->incMax = 0;
202 ret->incTab = NULL;
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000203 ret->nbErrors = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000204 return(ret);
205}
206
207/**
208 * xmlXIncludeFreeContext:
209 * @ctxt: the XInclude context
210 *
211 * Free an XInclude context
212 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000213static void
Owen Taylor3473f882001-02-23 17:55:21 +0000214xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
215 int i;
216
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000217#ifdef DEBUG_XINCLUDE
218 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
219#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000220 if (ctxt == NULL)
221 return;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000222 for (i = 0;i < ctxt->incNr;i++) {
223 if (ctxt->incTab[i] != NULL)
224 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000225 }
226 for (i = 0;i < ctxt->txtNr;i++) {
227 if (ctxt->txturlTab[i] != NULL)
228 xmlFree(ctxt->txturlTab[i]);
229 }
230 if (ctxt->incTab != NULL)
231 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000232 if (ctxt->txtTab != NULL)
233 xmlFree(ctxt->txtTab);
234 if (ctxt->txturlTab != NULL)
235 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000236 xmlFree(ctxt);
237}
238
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000239/**
240 * xmlXIncludeAddNode:
241 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000242 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000243 *
244 * Add a new node to process to an XInclude context
245 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000246static int
247xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
248 xmlXIncludeRefPtr ref;
249 xmlURIPtr uri;
250 xmlChar *URL;
251 xmlChar *fragment = NULL;
252 xmlChar *href;
253 xmlChar *parse;
254 xmlChar *base;
255 xmlChar *URI;
256 int xml = 1; /* default Issue 64 */
257
258
259 if (ctxt == NULL)
260 return(-1);
261 if (cur == NULL)
262 return(-1);
263
264#ifdef DEBUG_XINCLUDE
265 xmlGenericError(xmlGenericErrorContext, "Add node\n");
266#endif
267 /*
268 * read the attributes
269 */
270 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
271 if (href == NULL) {
272 href = xmlGetProp(cur, XINCLUDE_HREF);
273 if (href == NULL) {
274 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000275 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000276 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000277 }
278 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000279 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
280 if (parse == NULL) {
281 parse = xmlGetProp(cur, XINCLUDE_PARSE);
282 }
283 if (parse != NULL) {
284 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
285 xml = 1;
286 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
287 xml = 0;
288 else {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000289 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000290 "XInclude: invalid value %s for %s\n",
291 parse, XINCLUDE_PARSE);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000292 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000293 if (href != NULL)
294 xmlFree(href);
295 if (parse != NULL)
296 xmlFree(parse);
297 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000298 }
299 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000300
301 /*
302 * compute the URI
303 */
304 base = xmlNodeGetBase(ctxt->doc, cur);
305 if (base == NULL) {
306 URI = xmlBuildURI(href, ctxt->doc->URL);
307 } else {
308 URI = xmlBuildURI(href, base);
309 }
310 if (URI == NULL) {
311 xmlChar *escbase;
312 xmlChar *eschref;
313 /*
314 * Some escaping may be needed
315 */
316 escbase = xmlURIEscape(base);
317 eschref = xmlURIEscape(href);
318 URI = xmlBuildURI(eschref, escbase);
319 if (escbase != NULL)
320 xmlFree(escbase);
321 if (eschref != NULL)
322 xmlFree(eschref);
323 }
324 if (parse != NULL)
325 xmlFree(parse);
326 if (href != NULL)
327 xmlFree(href);
328 if (base != NULL)
329 xmlFree(base);
330 if (URI == NULL) {
331 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000332 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000333 return(-1);
334 }
335
336 /*
337 * Check the URL and remove any fragment identifier
338 */
339 uri = xmlParseURI((const char *)URI);
340 if (uri == NULL) {
341 xmlGenericError(xmlGenericErrorContext,
342 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000343 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000344 return(-1);
345 }
346 if (uri->fragment != NULL) {
347 fragment = (xmlChar *) uri->fragment;
348 uri->fragment = NULL;
349 }
350 URL = xmlSaveUri(uri);
351 xmlFreeURI(uri);
352 xmlFree(URI);
353 if (URL == NULL) {
354 xmlGenericError(xmlGenericErrorContext,
355 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000356 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000357 if (fragment != NULL)
358 xmlFree(fragment);
359 return(-1);
360 }
361
362 ref = xmlXIncludeNewRef(ctxt, URL, cur);
363 if (ref == NULL) {
364 return(-1);
365 }
366 ref->fragment = fragment;
367 ref->doc = NULL;
368 ref->xml = xml;
369 ref->count = 1;
370 xmlFree(URL);
371 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000372}
373
374/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000375 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000376 * @ctxt: the XInclude context
377 * @doc: the new document
378 * @url: the associated URL
379 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000380 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000381 */
382static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000383xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000384 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000385 xmlXIncludeCtxtPtr newctxt;
386 int i;
387
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000388#ifdef DEBUG_XINCLUDE
389 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
390#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000391 /*
392 * Handle recursion here.
393 */
394
395 newctxt = xmlXIncludeNewContext(doc);
396 if (newctxt != NULL) {
397 /*
398 * Copy the existing document set
399 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000400 newctxt->incMax = ctxt->incMax;
401 newctxt->incNr = ctxt->incNr;
402 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
403 sizeof(newctxt->incTab[0]));
404 if (newctxt->incTab == NULL) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000405 xmlGenericError(xmlGenericErrorContext,
406 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000407 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000408 xmlFree(newctxt);
409 return;
410 }
411
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000412 /*
413 * Inherit the documents already in use by others includes
414 */
415 newctxt->incBase = ctxt->incNr;
416 for (i = 0;i < ctxt->incNr;i++) {
417 newctxt->incTab[i] = ctxt->incTab[i];
418 newctxt->incTab[i]->count++; /* prevent the recursion from
419 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000420 }
421 xmlXIncludeDoProcess(newctxt, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000422 for (i = 0;i < ctxt->incNr;i++) {
423 newctxt->incTab[i]->count--;
424 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000425 }
426 xmlXIncludeFreeContext(newctxt);
427 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000428#ifdef DEBUG_XINCLUDE
429 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
430#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000431}
432
433/**
434 * xmlXIncludeAddTxt:
435 * @ctxt: the XInclude context
436 * @txt: the new text node
437 * @url: the associated URL
438 *
439 * Add a new txtument to the list
440 */
441static void
442xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000443#ifdef DEBUG_XINCLUDE
444 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
445#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000446 if (ctxt->txtMax == 0) {
447 ctxt->txtMax = 4;
448 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
449 sizeof(ctxt->txtTab[0]));
450 if (ctxt->txtTab == NULL) {
451 xmlGenericError(xmlGenericErrorContext,
452 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000453 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000454 return;
455 }
456 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
457 sizeof(ctxt->txturlTab[0]));
458 if (ctxt->txturlTab == NULL) {
459 xmlGenericError(xmlGenericErrorContext,
460 "malloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000461 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000462 return;
463 }
464 }
465 if (ctxt->txtNr >= ctxt->txtMax) {
466 ctxt->txtMax *= 2;
467 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
468 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
469 if (ctxt->txtTab == NULL) {
470 xmlGenericError(xmlGenericErrorContext,
471 "realloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000472 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000473 return;
474 }
475 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000476 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000477 if (ctxt->txturlTab == NULL) {
478 xmlGenericError(xmlGenericErrorContext,
479 "realloc failed !\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000480 ctxt->nbErrors++;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000481 return;
482 }
483 }
484 ctxt->txtTab[ctxt->txtNr] = txt;
485 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
486 ctxt->txtNr++;
487}
488
Owen Taylor3473f882001-02-23 17:55:21 +0000489/************************************************************************
490 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000491 * Node copy with specific semantic *
492 * *
493 ************************************************************************/
494
495/**
496 * xmlXIncludeCopyNode:
497 * @ctxt: the XInclude context
498 * @target: the document target
499 * @source: the document source
500 * @elem: the element
501 *
502 * Make a copy of the node while preserving the XInclude semantic
503 * of the Infoset copy
504 */
505static xmlNodePtr
506xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
507 xmlDocPtr source, xmlNodePtr elem) {
508 xmlNodePtr result = NULL;
509
510 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
511 (elem == NULL))
512 return(NULL);
513 if (elem->type == XML_DTD_NODE)
514 return(NULL);
515 result = xmlDocCopyNode(elem, target, 1);
516 return(result);
517}
518
519/**
520 * xmlXIncludeCopyNodeList:
521 * @ctxt: the XInclude context
522 * @target: the document target
523 * @source: the document source
524 * @elem: the element list
525 *
526 * Make a copy of the node list while preserving the XInclude semantic
527 * of the Infoset copy
528 */
529static xmlNodePtr
530xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
531 xmlDocPtr source, xmlNodePtr elem) {
532 xmlNodePtr cur, res, result = NULL, last = NULL;
533
534 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
535 (elem == NULL))
536 return(NULL);
537 cur = elem;
538 while (cur != NULL) {
539 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
540 if (res != NULL) {
541 if (result == NULL) {
542 result = last = res;
543 } else {
544 last->next = res;
545 res->prev = last;
546 last = res;
547 }
548 }
549 cur = cur->next;
550 }
551 return(result);
552}
553
554/**
555 * xmlXInclueGetNthChild:
556 * @cur: the node
557 * @no: the child number
558 *
559 * Returns the @no'th element child of @cur or NULL
560 */
561static xmlNodePtr
562xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
563 int i;
564 if (cur == NULL)
565 return(cur);
566 cur = cur->children;
567 for (i = 0;i <= no;cur = cur->next) {
568 if (cur == NULL)
569 return(cur);
570 if ((cur->type == XML_ELEMENT_NODE) ||
571 (cur->type == XML_DOCUMENT_NODE) ||
572 (cur->type == XML_HTML_DOCUMENT_NODE)) {
573 i++;
574 if (i == no)
575 break;
576 }
577 }
578 return(cur);
579}
580
581xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
582
583/**
584 * xmlXIncludeCopyRange:
585 * @ctxt: the XInclude context
586 * @target: the document target
587 * @source: the document source
588 * @obj: the XPointer result from the evaluation.
589 *
590 * Build a node list tree copy of the XPointer result.
591 *
592 * Returns an xmlNodePtr list or NULL.
593 * the caller has to free the node tree.
594 */
595static xmlNodePtr
596xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
597 xmlDocPtr source, xmlXPathObjectPtr range) {
598 /* pointers to generated nodes */
599 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
600 /* pointers to traversal nodes */
601 xmlNodePtr start, cur, end;
602 int index1, index2;
603
604 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
605 (range == NULL))
606 return(NULL);
607 if (range->type != XPATH_RANGE)
608 return(NULL);
609 start = (xmlNodePtr) range->user;
610
611 if (start == NULL)
612 return(NULL);
613 end = range->user2;
614 if (end == NULL)
615 return(xmlDocCopyNode(start, target, 1));
616
617 cur = start;
618 index1 = range->index;
619 index2 = range->index2;
620 while (cur != NULL) {
621 if (cur == end) {
622 if (cur->type == XML_TEXT_NODE) {
623 const xmlChar *content = cur->content;
624 int len;
625
626 if (content == NULL) {
627 tmp = xmlNewTextLen(NULL, 0);
628 } else {
629 len = index2;
630 if ((cur == start) && (index1 > 1)) {
631 content += (index1 - 1);
632 len -= (index1 - 1);
633 index1 = 0;
634 } else {
635 len = index2;
636 }
637 tmp = xmlNewTextLen(content, len);
638 }
639 /* single sub text node selection */
640 if (list == NULL)
641 return(tmp);
642 /* prune and return full set */
643 if (last != NULL)
644 xmlAddNextSibling(last, tmp);
645 else
646 xmlAddChild(parent, tmp);
647 return(list);
648 } else {
649 tmp = xmlDocCopyNode(cur, target, 0);
650 if (list == NULL)
651 list = tmp;
652 else {
653 if (last != NULL)
654 xmlAddNextSibling(last, tmp);
655 else
656 xmlAddChild(parent, tmp);
657 }
658 last = NULL;
659 parent = tmp;
660
661 if (index2 > 1) {
662 end = xmlXIncludeGetNthChild(cur, index2 - 1);
663 index2 = 0;
664 }
665 if ((cur == start) && (index1 > 1)) {
666 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
667 index1 = 0;
668 } else {
669 cur = cur->children;
670 }
671 /*
672 * Now gather the remaining nodes from cur to end
673 */
674 continue; /* while */
675 }
676 } else if ((cur == start) &&
677 (list == NULL) /* looks superfluous but ... */ ) {
678 if ((cur->type == XML_TEXT_NODE) ||
679 (cur->type == XML_CDATA_SECTION_NODE)) {
680 const xmlChar *content = cur->content;
681
682 if (content == NULL) {
683 tmp = xmlNewTextLen(NULL, 0);
684 } else {
685 if (index1 > 1) {
686 content += (index1 - 1);
687 }
688 tmp = xmlNewText(content);
689 }
690 last = list = tmp;
691 } else {
692 if ((cur == start) && (index1 > 1)) {
693 tmp = xmlDocCopyNode(cur, target, 0);
694 list = tmp;
695 parent = tmp;
696 last = NULL;
697 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
698 index1 = 0;
699 /*
700 * Now gather the remaining nodes from cur to end
701 */
702 continue; /* while */
703 }
704 tmp = xmlDocCopyNode(cur, target, 1);
705 list = tmp;
706 parent = NULL;
707 last = tmp;
708 }
709 } else {
710 tmp = NULL;
711 switch (cur->type) {
712 case XML_DTD_NODE:
713 case XML_ELEMENT_DECL:
714 case XML_ATTRIBUTE_DECL:
715 case XML_ENTITY_NODE:
716 /* Do not copy DTD informations */
717 break;
718 case XML_ENTITY_DECL:
719 /* handle crossing entities -> stack needed */
720 break;
721 case XML_XINCLUDE_START:
722 case XML_XINCLUDE_END:
723 /* don't consider it part of the tree content */
724 break;
725 case XML_ATTRIBUTE_NODE:
726 /* Humm, should not happen ! */
727 break;
728 default:
729 tmp = xmlDocCopyNode(cur, target, 1);
730 break;
731 }
732 if (tmp != NULL) {
733 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
734 return(NULL);
735 }
736 if (last != NULL)
737 xmlAddNextSibling(last, tmp);
738 else {
739 xmlAddChild(parent, tmp);
740 last = tmp;
741 }
742 }
743 }
744 /*
745 * Skip to next node in document order
746 */
747 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
748 return(NULL);
749 }
750 cur = xmlXPtrAdvanceNode(cur);
751 }
752 return(list);
753}
754
755/**
756 * xmlXIncludeBuildNodeList:
757 * @ctxt: the XInclude context
758 * @target: the document target
759 * @source: the document source
760 * @obj: the XPointer result from the evaluation.
761 *
762 * Build a node list tree copy of the XPointer result.
763 * This will drop Attributes and Namespace declarations.
764 *
765 * Returns an xmlNodePtr list or NULL.
766 * the caller has to free the node tree.
767 */
768static xmlNodePtr
769xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
770 xmlDocPtr source, xmlXPathObjectPtr obj) {
771 xmlNodePtr list = NULL, last = NULL;
772 int i;
773
774 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
775 (obj == NULL))
776 return(NULL);
777 switch (obj->type) {
778 case XPATH_NODESET: {
779 xmlNodeSetPtr set = obj->nodesetval;
780 if (set == NULL)
781 return(NULL);
782 for (i = 0;i < set->nodeNr;i++) {
783 if (set->nodeTab[i] == NULL)
784 continue;
785 switch (set->nodeTab[i]->type) {
786 case XML_TEXT_NODE:
787 case XML_CDATA_SECTION_NODE:
788 case XML_ELEMENT_NODE:
789 case XML_ENTITY_REF_NODE:
790 case XML_ENTITY_NODE:
791 case XML_PI_NODE:
792 case XML_COMMENT_NODE:
793 case XML_DOCUMENT_NODE:
794 case XML_HTML_DOCUMENT_NODE:
795#ifdef LIBXML_DOCB_ENABLED
796 case XML_DOCB_DOCUMENT_NODE:
797#endif
798 case XML_XINCLUDE_START:
799 case XML_XINCLUDE_END:
800 break;
801 case XML_ATTRIBUTE_NODE:
802 case XML_NAMESPACE_DECL:
803 case XML_DOCUMENT_TYPE_NODE:
804 case XML_DOCUMENT_FRAG_NODE:
805 case XML_NOTATION_NODE:
806 case XML_DTD_NODE:
807 case XML_ELEMENT_DECL:
808 case XML_ATTRIBUTE_DECL:
809 case XML_ENTITY_DECL:
810 continue; /* for */
811 }
812 if (last == NULL)
813 list = last = xmlXIncludeCopyNode(ctxt, target, source,
814 set->nodeTab[i]);
815 else {
816 xmlAddNextSibling(last,
817 xmlXIncludeCopyNode(ctxt, target, source,
818 set->nodeTab[i]));
819 if (last->next != NULL)
820 last = last->next;
821 }
822 }
823 break;
824 }
825 case XPATH_LOCATIONSET: {
826 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
827 if (set == NULL)
828 return(NULL);
829 for (i = 0;i < set->locNr;i++) {
830 if (last == NULL)
831 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
832 set->locTab[i]);
833 else
834 xmlAddNextSibling(last,
835 xmlXIncludeCopyXPointer(ctxt, target, source,
836 set->locTab[i]));
837 if (last != NULL) {
838 while (last->next != NULL)
839 last = last->next;
840 }
841 }
842 break;
843 }
844 case XPATH_RANGE:
845 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
846 case XPATH_POINT:
847 /* points are ignored in XInclude */
848 break;
849 default:
850 break;
851 }
852 return(list);
853}
854/************************************************************************
855 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000856 * XInclude I/O handling *
857 * *
858 ************************************************************************/
859
860/**
Daniel Veillard4287c572003-02-04 22:48:53 +0000861 * xmlXIncludeMergeOneEntity:
862 * @ent: the entity
863 * @doc: the including doc
864 * @nr: the entity name
865 *
866 * Inplements the merge of one entity
867 */
868static void
869xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlDocPtr doc,
870 xmlChar *name ATTRIBUTE_UNUSED) {
871 xmlEntityPtr ret;
872
873 if ((ent == NULL) || (doc == NULL))
874 return;
875 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
876 ent->SystemID, ent->content);
877 if (ret != NULL) {
878 if (ent->URI != NULL)
879 ret->URI = xmlStrdup(ent->URI);
880 }
881}
882
883/**
884 * xmlXIncludeMergeEntities:
885 * @ctxt: an XInclude context
886 * @doc: the including doc
887 * @from: the included doc
888 *
889 * Inplements the entity merge
890 *
891 * Returns 0 if merge succeeded, -1 if some processing failed
892 */
893static int
894xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
895 xmlDocPtr from) {
896 xmlNodePtr cur;
897 xmlDtdPtr target, source;
898
899 if (ctxt == NULL)
900 return(-1);
901
902 if ((from == NULL) || (from->intSubset == NULL))
903 return(0);
904
905 target = doc->intSubset;
906 if (target == NULL) {
907 cur = xmlDocGetRootElement(doc);
908 if (cur == NULL)
909 return(-1);
910 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
911 if (target == NULL)
912 return(-1);
913 }
914
915 source = from->intSubset;
916 if ((source != NULL) && (source->entities != NULL)) {
917 xmlHashScan((xmlHashTablePtr) source->entities,
918 (xmlHashScanner) xmlXIncludeMergeEntity, doc);
919 }
920 source = from->extSubset;
921 if ((source != NULL) && (source->entities != NULL)) {
922 /*
923 * don't duplicate existing stuff when external subsets are the same
924 */
925 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
926 (!xmlStrEqual(target->SystemID, source->SystemID))) {
927 xmlHashScan((xmlHashTablePtr) source->entities,
928 (xmlHashScanner) xmlXIncludeMergeEntity, doc);
929 }
930 }
931 return(0);
932}
933
934/**
Owen Taylor3473f882001-02-23 17:55:21 +0000935 * xmlXIncludeLoadDoc:
936 * @ctxt: the XInclude context
937 * @url: the associated URL
938 * @nr: the xinclude node number
939 *
940 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000941 *
942 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000943 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000944static int
Owen Taylor3473f882001-02-23 17:55:21 +0000945xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
946 xmlDocPtr doc;
947 xmlURIPtr uri;
948 xmlChar *URL;
949 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000950 int i = 0;
951
952#ifdef DEBUG_XINCLUDE
953 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
954#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000955 /*
956 * Check the URL and remove any fragment identifier
957 */
958 uri = xmlParseURI((const char *)url);
959 if (uri == NULL) {
960 xmlGenericError(xmlGenericErrorContext,
961 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000962 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000963 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000964 }
965 if (uri->fragment != NULL) {
966 fragment = (xmlChar *) uri->fragment;
967 uri->fragment = NULL;
968 }
969 URL = xmlSaveUri(uri);
970 xmlFreeURI(uri);
971 if (URL == NULL) {
972 xmlGenericError(xmlGenericErrorContext,
973 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +0000974 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +0000975 if (fragment != NULL)
976 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000977 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000978 }
979
980 /*
981 * Handling of references to the local document are done
982 * directly through ctxt->doc.
983 */
984 if ((URL[0] == 0) || (URL[0] == '#')) {
985 doc = NULL;
986 goto loaded;
987 }
988
989 /*
990 * Prevent reloading twice the document.
991 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000992 for (i = 0; i < ctxt->incNr; i++) {
993 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
994 (ctxt->incTab[i]->doc != NULL)) {
995 doc = ctxt->incTab[i]->doc;
996#ifdef DEBUG_XINCLUDE
997 printf("Already loaded %s\n", URL);
998#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000999 goto loaded;
1000 }
1001 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001002
Owen Taylor3473f882001-02-23 17:55:21 +00001003 /*
1004 * Load it.
1005 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001006#ifdef DEBUG_XINCLUDE
1007 printf("loading %s\n", URL);
1008#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001009 doc = xmlParseFile((const char *)URL);
1010 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001011 xmlFree(URL);
1012 if (fragment != NULL)
1013 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001014 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001015 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001016 ctxt->incTab[nr]->doc = doc;
1017
1018 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001019 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001020 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001021 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001022
1023 /*
1024 * We don't need the DTD anymore, free up space
1025 if (doc->intSubset != NULL) {
1026 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1027 xmlFreeNode((xmlNodePtr) doc->intSubset);
1028 doc->intSubset = NULL;
1029 }
1030 if (doc->extSubset != NULL) {
1031 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1032 xmlFreeNode((xmlNodePtr) doc->extSubset);
1033 doc->extSubset = NULL;
1034 }
1035 */
1036 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001037
1038loaded:
1039 if (fragment == NULL) {
1040 /*
1041 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001042 */
1043 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001044 {
1045 /* Hopefully a DTD declaration won't be copied from
1046 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001047 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001048 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001049 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001050 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001051 }
Owen Taylor3473f882001-02-23 17:55:21 +00001052 } else {
1053 /*
1054 * Computes the XPointer expression and make a copy used
1055 * as the replacement copy.
1056 */
1057 xmlXPathObjectPtr xptr;
1058 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001059 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001060
1061 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001062 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1063 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001064 } else {
1065 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1066 }
1067 if (xptrctxt == NULL) {
1068 xmlGenericError(xmlGenericErrorContext,
1069 "XInclude: could create XPointer context\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001070 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001071 xmlFree(URL);
1072 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001073 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001074 }
1075 xptr = xmlXPtrEval(fragment, xptrctxt);
1076 if (xptr == NULL) {
1077 xmlGenericError(xmlGenericErrorContext,
1078 "XInclude: XPointer evaluation failed: #%s\n",
1079 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001080 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001081 xmlXPathFreeContext(xptrctxt);
1082 xmlFree(URL);
1083 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001084 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001085 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001086 switch (xptr->type) {
1087 case XPATH_UNDEFINED:
1088 case XPATH_BOOLEAN:
1089 case XPATH_NUMBER:
1090 case XPATH_STRING:
1091 case XPATH_POINT:
1092 case XPATH_USERS:
1093 case XPATH_XSLT_TREE:
1094 xmlGenericError(xmlGenericErrorContext,
1095 "XInclude: XPointer is not a range: #%s\n",
1096 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001097 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001098 xmlXPathFreeContext(xptrctxt);
1099 xmlFree(URL);
1100 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001101 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001102 case XPATH_NODESET:
1103 case XPATH_RANGE:
1104 case XPATH_LOCATIONSET:
1105 break;
1106 }
1107 set = xptr->nodesetval;
1108 if (set != NULL) {
1109 for (i = 0;i < set->nodeNr;i++) {
1110 if (set->nodeTab[i] == NULL)
1111 continue;
1112 switch (set->nodeTab[i]->type) {
1113 case XML_TEXT_NODE:
1114 case XML_CDATA_SECTION_NODE:
1115 case XML_ELEMENT_NODE:
1116 case XML_ENTITY_REF_NODE:
1117 case XML_ENTITY_NODE:
1118 case XML_PI_NODE:
1119 case XML_COMMENT_NODE:
1120 case XML_DOCUMENT_NODE:
1121 case XML_HTML_DOCUMENT_NODE:
1122#ifdef LIBXML_DOCB_ENABLED
1123 case XML_DOCB_DOCUMENT_NODE:
1124#endif
1125 continue;
1126 case XML_ATTRIBUTE_NODE:
1127 xmlGenericError(xmlGenericErrorContext,
1128 "XInclude: XPointer selects an attribute: #%s\n",
1129 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001130 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001131 set->nodeTab[i] = NULL;
1132 continue;
1133 case XML_NAMESPACE_DECL:
1134 xmlGenericError(xmlGenericErrorContext,
1135 "XInclude: XPointer selects a namespace: #%s\n",
1136 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001137 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001138 set->nodeTab[i] = NULL;
1139 continue;
1140 case XML_DOCUMENT_TYPE_NODE:
1141 case XML_DOCUMENT_FRAG_NODE:
1142 case XML_NOTATION_NODE:
1143 case XML_DTD_NODE:
1144 case XML_ELEMENT_DECL:
1145 case XML_ATTRIBUTE_DECL:
1146 case XML_ENTITY_DECL:
1147 case XML_XINCLUDE_START:
1148 case XML_XINCLUDE_END:
1149 xmlGenericError(xmlGenericErrorContext,
1150 "XInclude: XPointer selects unexpected nodes: #%s\n",
1151 fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001152 ctxt->nbErrors++;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001153 set->nodeTab[i] = NULL;
1154 set->nodeTab[i] = NULL;
1155 continue; /* for */
1156 }
1157 }
1158 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001159 ctxt->incTab[nr]->inc =
1160 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
Owen Taylor3473f882001-02-23 17:55:21 +00001161 xmlXPathFreeObject(xptr);
1162 xmlXPathFreeContext(xptrctxt);
1163 xmlFree(fragment);
1164 }
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001165
1166 /*
1167 * Do the xml:base fixup if needed
1168 */
1169 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1170 xmlNodePtr node;
1171
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001172 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001173 while (node != NULL) {
1174 if (node->type == XML_ELEMENT_NODE)
1175 xmlNodeSetBase(node, URL);
1176 node = node->next;
1177 }
1178 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001179 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1180 (ctxt->incTab[nr]->count <= 1)) {
1181#ifdef DEBUG_XINCLUDE
1182 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1183#endif
1184 xmlFreeDoc(ctxt->incTab[nr]->doc);
1185 ctxt->incTab[nr]->doc = NULL;
1186 }
Owen Taylor3473f882001-02-23 17:55:21 +00001187 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001188 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001189}
1190
1191/**
1192 * xmlXIncludeLoadTxt:
1193 * @ctxt: the XInclude context
1194 * @url: the associated URL
1195 * @nr: the xinclude node number
1196 *
1197 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001198 *
1199 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001200 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001201static int
Owen Taylor3473f882001-02-23 17:55:21 +00001202xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1203 xmlParserInputBufferPtr buf;
1204 xmlNodePtr node;
1205 xmlURIPtr uri;
1206 xmlChar *URL;
1207 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001208 xmlChar *encoding = NULL;
1209 xmlCharEncoding enc = 0;
1210
Owen Taylor3473f882001-02-23 17:55:21 +00001211 /*
1212 * Check the URL and remove any fragment identifier
1213 */
1214 uri = xmlParseURI((const char *)url);
1215 if (uri == NULL) {
1216 xmlGenericError(xmlGenericErrorContext,
1217 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001218 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001219 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001220 }
1221 if (uri->fragment != NULL) {
1222 xmlGenericError(xmlGenericErrorContext,
1223 "XInclude: fragment identifier forbidden for text: %s\n",
1224 uri->fragment);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001225 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001226 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001227 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001228 }
1229 URL = xmlSaveUri(uri);
1230 xmlFreeURI(uri);
1231 if (URL == NULL) {
1232 xmlGenericError(xmlGenericErrorContext,
1233 "XInclude: invalid value URI %s\n", url);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001234 ctxt->nbErrors++;
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001235 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001236 }
1237
1238 /*
1239 * Handling of references to the local document are done
1240 * directly through ctxt->doc.
1241 */
1242 if (URL[0] == 0) {
1243 xmlGenericError(xmlGenericErrorContext,
1244 "XInclude: text serialization of document not available\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001245 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001246 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001247 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001248 }
1249
1250 /*
1251 * Prevent reloading twice the document.
1252 */
1253 for (i = 0; i < ctxt->txtNr; i++) {
1254 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1255 node = xmlCopyNode(ctxt->txtTab[i], 1);
1256 goto loaded;
1257 }
1258 }
1259 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001260 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001261 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001262 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1263 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1264 }
1265 if (encoding != NULL) {
1266 /*
1267 * TODO: we should not have to remap to the xmlCharEncoding
1268 * predefined set, a better interface than
1269 * xmlParserInputBufferCreateFilename should allow any
1270 * encoding supported by iconv
1271 */
1272 enc = xmlParseCharEncoding((const char *) encoding);
1273 if (enc == XML_CHAR_ENCODING_ERROR) {
1274 xmlGenericError(xmlGenericErrorContext,
1275 "XInclude: encoding %s not supported\n", encoding);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001276 ctxt->nbErrors++;
Daniel Veillardd076a202002-11-20 13:28:31 +00001277 xmlFree(encoding);
1278 xmlFree(URL);
1279 return(-1);
1280 }
1281 xmlFree(encoding);
1282 }
1283
1284 /*
1285 * Load it.
1286 */
1287 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001288 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001289 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001290 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001291 }
1292 node = xmlNewText(NULL);
1293
1294 /*
1295 * Scan all chars from the resource and add the to the node
1296 */
1297 while (xmlParserInputBufferRead(buf, 128) > 0) {
1298 int len;
1299 const xmlChar *content;
1300
1301 content = xmlBufferContent(buf->buffer);
1302 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001303 for (i = 0;i < len;) {
1304 int cur;
1305 int l;
1306
1307 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1308 if (!IS_CHAR(cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001309 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd076a202002-11-20 13:28:31 +00001310 "XInclude: %s contains invalid char %d\n", URL, cur);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001311 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001312 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001313 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001314 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001315 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001316 }
1317 xmlBufferShrink(buf->buffer, len);
1318 }
1319 xmlFreeParserInputBuffer(buf);
1320 xmlXIncludeAddTxt(ctxt, node, URL);
1321
1322loaded:
1323 /*
1324 * Add the element as the replacement copy.
1325 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001326 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001327 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001328 return(0);
1329}
1330
1331/**
1332 * xmlXIncludeLoadFallback:
1333 * @ctxt: the XInclude context
1334 * @fallback: the fallback node
1335 * @nr: the xinclude node number
1336 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001337 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001338 * in the XInclude context
1339 *
1340 * Returns 0 in case of success, -1 in case of failure
1341 */
1342static int
1343xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1344 if ((fallback == NULL) || (ctxt == NULL))
1345 return(-1);
1346
Daniel Veillard06503452002-12-13 10:42:08 +00001347 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001348 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001349}
1350
1351/************************************************************************
1352 * *
1353 * XInclude Processing *
1354 * *
1355 ************************************************************************/
1356
1357/**
1358 * xmlXIncludePreProcessNode:
1359 * @ctxt: an XInclude context
1360 * @node: an XInclude node
1361 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001362 * Implement the XInclude preprocessing, currently just adding the element
1363 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001364 *
1365 * Returns the result list or NULL in case of error
1366 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001367static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001368xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1369 xmlXIncludeAddNode(ctxt, node);
1370 return(0);
1371}
1372
Daniel Veillard118aed72002-09-24 14:13:13 +00001373#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00001374/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001375 * xmlXIncludePreloadNode:
1376 * @ctxt: an XInclude context
1377 * @nr: the node number
1378 *
1379 * Do some precomputations and preload shared documents
1380 *
1381 * Returns 0 if substitution succeeded, -1 if some processing failed
1382 */
1383static int
1384xmlXIncludePreloadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1385 xmlNodePtr cur;
1386 xmlChar *href;
1387 xmlChar *parse;
1388 xmlChar *base;
1389 xmlChar *URI;
1390 int xml = 1; /* default Issue 64 */
1391 xmlURIPtr uri;
1392 xmlChar *URL;
1393 xmlChar *fragment = NULL;
1394 int i;
1395
1396
1397 if (ctxt == NULL)
1398 return(-1);
1399 if ((nr < 0) || (nr >= ctxt->incNr))
1400 return(-1);
1401 cur = ctxt->incTab[nr]->ref;
1402 if (cur == NULL)
1403 return(-1);
1404
1405 /*
1406 * read the attributes
1407 */
1408 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1409 if (href == NULL) {
1410 href = xmlGetProp(cur, XINCLUDE_HREF);
1411 if (href == NULL) {
1412 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1413 return(-1);
1414 }
1415 }
1416 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1417 if (parse == NULL) {
1418 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1419 }
1420 if (parse != NULL) {
1421 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1422 xml = 1;
1423 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1424 xml = 0;
1425 else {
1426 xmlGenericError(xmlGenericErrorContext,
1427 "XInclude: invalid value %s for %s\n",
1428 parse, XINCLUDE_PARSE);
1429 if (href != NULL)
1430 xmlFree(href);
1431 if (parse != NULL)
1432 xmlFree(parse);
1433 return(-1);
1434 }
1435 }
1436
1437 /*
1438 * compute the URI
1439 */
1440 base = xmlNodeGetBase(ctxt->doc, cur);
1441 if (base == NULL) {
1442 URI = xmlBuildURI(href, ctxt->doc->URL);
1443 } else {
1444 URI = xmlBuildURI(href, base);
1445 }
1446 if (URI == NULL) {
1447 xmlChar *escbase;
1448 xmlChar *eschref;
1449 /*
1450 * Some escaping may be needed
1451 */
1452 escbase = xmlURIEscape(base);
1453 eschref = xmlURIEscape(href);
1454 URI = xmlBuildURI(eschref, escbase);
1455 if (escbase != NULL)
1456 xmlFree(escbase);
1457 if (eschref != NULL)
1458 xmlFree(eschref);
1459 }
1460 if (parse != NULL)
1461 xmlFree(parse);
1462 if (href != NULL)
1463 xmlFree(href);
1464 if (base != NULL)
1465 xmlFree(base);
1466 if (URI == NULL) {
1467 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001468 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001469 return(-1);
1470 }
1471
1472 /*
1473 * Check the URL and remove any fragment identifier
1474 */
1475 uri = xmlParseURI((const char *)URI);
1476 if (uri == NULL) {
1477 xmlGenericError(xmlGenericErrorContext,
1478 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001479 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001480 xmlFree(URI);
1481 return(-1);
1482 }
1483 if (uri->fragment != NULL) {
1484 fragment = (xmlChar *) uri->fragment;
1485 uri->fragment = NULL;
1486 }
1487 URL = xmlSaveUri(uri);
1488 xmlFreeURI(uri);
1489 if (URL == NULL) {
1490 xmlGenericError(xmlGenericErrorContext,
1491 "XInclude: invalid value URI %s\n", URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001492 ctxt->nbErrors++;
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001493 if (fragment != NULL)
1494 xmlFree(fragment);
1495 xmlFree(URI);
1496 return(-1);
1497 }
1498 xmlFree(URI);
1499 if (fragment != NULL)
1500 xmlFree(fragment);
1501
1502 for (i = 0; i < nr; i++) {
1503 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1504#ifdef DEBUG_XINCLUDE
1505 printf("Incrementing count for %d : %s\n", i, ctxt->incTab[i]->URI);
1506#endif
1507 ctxt->incTab[i]->count++;
1508 break;
1509 }
1510 }
1511 xmlFree(URL);
1512 return(0);
1513}
Daniel Veillard118aed72002-09-24 14:13:13 +00001514#endif
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001515
1516/**
Owen Taylor3473f882001-02-23 17:55:21 +00001517 * xmlXIncludeLoadNode:
1518 * @ctxt: an XInclude context
1519 * @nr: the node number
1520 *
1521 * Find and load the infoset replacement for the given node.
1522 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001523 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001524 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001525static int
Owen Taylor3473f882001-02-23 17:55:21 +00001526xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1527 xmlNodePtr cur;
1528 xmlChar *href;
1529 xmlChar *parse;
1530 xmlChar *base;
1531 xmlChar *URI;
1532 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001533 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001534
1535 if (ctxt == NULL)
1536 return(-1);
1537 if ((nr < 0) || (nr >= ctxt->incNr))
1538 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001539 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001540 if (cur == NULL)
1541 return(-1);
1542
Owen Taylor3473f882001-02-23 17:55:21 +00001543 /*
1544 * read the attributes
1545 */
1546 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1547 if (href == NULL) {
1548 href = xmlGetProp(cur, XINCLUDE_HREF);
1549 if (href == NULL) {
1550 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001551 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001552 return(-1);
1553 }
1554 }
1555 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1556 if (parse == NULL) {
1557 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1558 }
1559 if (parse != NULL) {
1560 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1561 xml = 1;
1562 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1563 xml = 0;
1564 else {
1565 xmlGenericError(xmlGenericErrorContext,
1566 "XInclude: invalid value %s for %s\n",
1567 parse, XINCLUDE_PARSE);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001568 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001569 if (href != NULL)
1570 xmlFree(href);
1571 if (parse != NULL)
1572 xmlFree(parse);
1573 return(-1);
1574 }
1575 }
1576
1577 /*
1578 * compute the URI
1579 */
1580 base = xmlNodeGetBase(ctxt->doc, cur);
1581 if (base == NULL) {
1582 URI = xmlBuildURI(href, ctxt->doc->URL);
1583 } else {
1584 URI = xmlBuildURI(href, base);
1585 }
1586 if (URI == NULL) {
1587 xmlChar *escbase;
1588 xmlChar *eschref;
1589 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001590 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001591 */
1592 escbase = xmlURIEscape(base);
1593 eschref = xmlURIEscape(href);
1594 URI = xmlBuildURI(eschref, escbase);
1595 if (escbase != NULL)
1596 xmlFree(escbase);
1597 if (eschref != NULL)
1598 xmlFree(eschref);
1599 }
1600 if (URI == NULL) {
1601 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001602 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001603 if (parse != NULL)
1604 xmlFree(parse);
1605 if (href != NULL)
1606 xmlFree(href);
1607 if (base != NULL)
1608 xmlFree(base);
1609 return(-1);
1610 }
1611#ifdef DEBUG_XINCLUDE
1612 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1613 xml ? "xml": "text");
1614 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1615#endif
1616
1617 /*
1618 * Cleanup
1619 */
1620 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001621 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001622 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1623 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001624 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1625 }
1626 if (ret < 0) {
1627 xmlNodePtr children;
1628
1629 /*
1630 * Time to try a fallback if availble
1631 */
1632#ifdef DEBUG_XINCLUDE
1633 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1634#endif
1635 children = cur->children;
1636 while (children != NULL) {
1637 if ((children->type == XML_ELEMENT_NODE) &&
1638 (children->ns != NULL) &&
1639 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1640 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1641 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1642 if (ret == 0)
1643 break;
1644 }
1645 children = children->next;
1646 }
1647 }
1648 if (ret < 0) {
1649 xmlGenericError(xmlGenericErrorContext,
1650 "XInclude: could not load %s, and no fallback was found\n",
1651 URI);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001652 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001653 }
1654
1655 /*
1656 * Cleanup
1657 */
1658 if (URI != NULL)
1659 xmlFree(URI);
1660 if (parse != NULL)
1661 xmlFree(parse);
1662 if (href != NULL)
1663 xmlFree(href);
1664 if (base != NULL)
1665 xmlFree(base);
1666 return(0);
1667}
1668
1669/**
1670 * xmlXIncludeIncludeNode:
1671 * @ctxt: an XInclude context
1672 * @nr: the node number
1673 *
1674 * Inplement the infoset replacement for the given node
1675 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001676 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001677 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001678static int
Owen Taylor3473f882001-02-23 17:55:21 +00001679xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1680 xmlNodePtr cur, end, list;
1681
1682 if (ctxt == NULL)
1683 return(-1);
1684 if ((nr < 0) || (nr >= ctxt->incNr))
1685 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001686 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001687 if (cur == NULL)
1688 return(-1);
1689
1690 /*
1691 * Change the current node as an XInclude start one, and add an
1692 * entity end one
1693 */
1694 cur->type = XML_XINCLUDE_START;
1695 end = xmlNewNode(cur->ns, cur->name);
1696 if (end == NULL) {
1697 xmlGenericError(xmlGenericErrorContext,
1698 "XInclude: failed to build node\n");
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001699 ctxt->nbErrors++;
Owen Taylor3473f882001-02-23 17:55:21 +00001700 return(-1);
1701 }
1702 end->type = XML_XINCLUDE_END;
1703 xmlAddNextSibling(cur, end);
1704
1705 /*
1706 * Add the list of nodes
1707 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001708 list = ctxt->incTab[nr]->inc;
1709 ctxt->incTab[nr]->inc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001710 while (list != NULL) {
1711 cur = list;
1712 list = list->next;
1713
1714 xmlAddPrevSibling(end, cur);
1715 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001716
1717
Owen Taylor3473f882001-02-23 17:55:21 +00001718 return(0);
1719}
1720
1721/**
1722 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +00001723 * @node: an XInclude node
1724 *
1725 * test if the node is an XInclude node
1726 *
1727 * Returns 1 true, 0 otherwise
1728 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001729static int
1730xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001731 if (node == NULL)
1732 return(0);
1733 if (node->ns == NULL)
1734 return(0);
1735 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
1736 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
1737 return(0);
1738}
1739
1740/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001741 * xmlXIncludeDoProcess:
1742 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +00001743 * @doc: an XML document
1744 *
1745 * Implement the XInclude substitution on the XML document @doc
1746 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001747 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001748 * or the number of substitutions done.
1749 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001750static int
1751xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001752 xmlNodePtr cur;
1753 int ret = 0;
1754 int i;
1755
1756 if (doc == NULL)
1757 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001758 if (ctxt == NULL)
1759 return(-1);
1760
1761 /*
1762 * First phase: lookup the elements in the document
1763 */
1764 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001765 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001766 xmlXIncludePreProcessNode(ctxt, cur);
1767 while (cur != NULL) {
1768 /* TODO: need to work on entities -> stack */
1769 if ((cur->children != NULL) &&
1770 (cur->children->type != XML_ENTITY_DECL)) {
1771 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001772 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001773 xmlXIncludePreProcessNode(ctxt, cur);
1774 } else if (cur->next != NULL) {
1775 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001776 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001777 xmlXIncludePreProcessNode(ctxt, cur);
1778 } else {
1779 do {
1780 cur = cur->parent;
1781 if (cur == NULL) break; /* do */
1782 if (cur->next != NULL) {
1783 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001784 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001785 xmlXIncludePreProcessNode(ctxt, cur);
1786 break; /* do */
1787 }
1788 } while (cur != NULL);
1789 }
1790 }
1791
1792 /*
1793 * Second Phase : collect the infosets fragments
1794 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001795 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001796 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00001797 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00001798 }
1799
1800 /*
1801 * Third phase: extend the original document infoset.
1802 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001803 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001804 xmlXIncludeIncludeNode(ctxt, i);
1805 }
1806
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001807 return(ret);
1808}
1809
1810/**
1811 * xmlXIncludeProcess:
1812 * @doc: an XML document
1813 *
1814 * Implement the XInclude substitution on the XML document @doc
1815 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001816 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001817 * or the number of substitutions done.
1818 */
1819int
1820xmlXIncludeProcess(xmlDocPtr doc) {
1821 xmlXIncludeCtxtPtr ctxt;
1822 int ret = 0;
1823
1824 if (doc == NULL)
1825 return(-1);
1826 ctxt = xmlXIncludeNewContext(doc);
1827 if (ctxt == NULL)
1828 return(-1);
1829 ret = xmlXIncludeDoProcess(ctxt, doc);
Daniel Veillardd581b7e2003-02-11 18:03:05 +00001830 if ((ret >= 0) && (ctxt->nbErrors > 0))
1831 ret = -1;
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001832
Owen Taylor3473f882001-02-23 17:55:21 +00001833 xmlXIncludeFreeContext(ctxt);
1834 return(ret);
1835}
1836
1837#else /* !LIBXML_XINCLUDE_ENABLED */
1838#endif