blob: a9a1e3c61912853fadf673b9963972942ff33b10 [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 */
Owen Taylor3473f882001-02-23 17:55:21 +000086};
87
Daniel Veillardd16df9f2001-05-23 13:44:21 +000088static int
89xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
Owen Taylor3473f882001-02-23 17:55:21 +000090
91/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +000092 * xmlXIncludeFreeRef:
93 * @ref: the XInclude reference
94 *
95 * Free an XInclude reference
96 */
97static void
98xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
99 if (ref == NULL)
100 return;
101#ifdef DEBUG_XINCLUDE
102 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
103#endif
104 if (ref->doc != NULL) {
105#ifdef DEBUG_XINCLUDE
106 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
107#endif
108 xmlFreeDoc(ref->doc);
109 }
110 if (ref->URI != NULL)
111 xmlFree(ref->URI);
112 if (ref->fragment != NULL)
113 xmlFree(ref->fragment);
114 xmlFree(ref);
115}
116
117/**
118 * xmlXIncludeNewRef:
119 * @ctxt: the XInclude context
120 * @URI: the resource URI
121 *
122 * Creates a new reference within an XInclude context
123 *
124 * Returns the new set
125 */
126static xmlXIncludeRefPtr
127xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
128 xmlNodePtr ref) {
129 xmlXIncludeRefPtr ret;
130
131#ifdef DEBUG_XINCLUDE
132 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
133#endif
134 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
135 if (ret == NULL)
136 return(NULL);
137 memset(ret, 0, sizeof(xmlXIncludeRef));
138 if (URI == NULL)
139 ret->URI = NULL;
140 else
141 ret->URI = xmlStrdup(URI);
142 ret->fragment = NULL;
143 ret->ref = ref;
144 ret->doc = 0;
145 ret->count = 0;
146 ret->xml = 0;
147 ret->inc = NULL;
148 if (ctxt->incMax == 0) {
149 ctxt->incMax = 4;
150 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
151 sizeof(ctxt->incTab[0]));
152 if (ctxt->incTab == NULL) {
153 xmlGenericError(xmlGenericErrorContext,
154 "malloc failed !\n");
155 xmlXIncludeFreeRef(ret);
156 return(NULL);
157 }
158 }
159 if (ctxt->incNr >= ctxt->incMax) {
160 ctxt->incMax *= 2;
161 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
162 ctxt->incMax * sizeof(ctxt->incTab[0]));
163 if (ctxt->incTab == NULL) {
164 xmlGenericError(xmlGenericErrorContext,
165 "realloc failed !\n");
166 xmlXIncludeFreeRef(ret);
167 return(NULL);
168 }
169 }
170 ctxt->incTab[ctxt->incNr++] = ret;
171 return(ret);
172}
173
174/**
Owen Taylor3473f882001-02-23 17:55:21 +0000175 * xmlXIncludeNewContext:
176 * @doc: an XML Document
177 *
178 * Creates a new XInclude context
179 *
180 * Returns the new set
181 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000182static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000183xmlXIncludeNewContext(xmlDocPtr doc) {
184 xmlXIncludeCtxtPtr ret;
185
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000186#ifdef DEBUG_XINCLUDE
187 xmlGenericError(xmlGenericErrorContext, "New context\n");
188#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000189 if (doc == NULL)
190 return(NULL);
191 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
192 if (ret == NULL)
193 return(NULL);
194 memset(ret, 0, sizeof(xmlXIncludeCtxt));
195 ret->doc = doc;
196 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000197 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000198 ret->incMax = 0;
199 ret->incTab = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000200 return(ret);
201}
202
203/**
204 * xmlXIncludeFreeContext:
205 * @ctxt: the XInclude context
206 *
207 * Free an XInclude context
208 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000209static void
Owen Taylor3473f882001-02-23 17:55:21 +0000210xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
211 int i;
212
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000213#ifdef DEBUG_XINCLUDE
214 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
215#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000216 if (ctxt == NULL)
217 return;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000218 for (i = 0;i < ctxt->incNr;i++) {
219 if (ctxt->incTab[i] != NULL)
220 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000221 }
222 for (i = 0;i < ctxt->txtNr;i++) {
223 if (ctxt->txturlTab[i] != NULL)
224 xmlFree(ctxt->txturlTab[i]);
225 }
226 if (ctxt->incTab != NULL)
227 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000228 if (ctxt->txtTab != NULL)
229 xmlFree(ctxt->txtTab);
230 if (ctxt->txturlTab != NULL)
231 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000232 xmlFree(ctxt);
233}
234
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000235/**
236 * xmlXIncludeAddNode:
237 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000238 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000239 *
240 * Add a new node to process to an XInclude context
241 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000242static int
243xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
244 xmlXIncludeRefPtr ref;
245 xmlURIPtr uri;
246 xmlChar *URL;
247 xmlChar *fragment = NULL;
248 xmlChar *href;
249 xmlChar *parse;
250 xmlChar *base;
251 xmlChar *URI;
252 int xml = 1; /* default Issue 64 */
253
254
255 if (ctxt == NULL)
256 return(-1);
257 if (cur == NULL)
258 return(-1);
259
260#ifdef DEBUG_XINCLUDE
261 xmlGenericError(xmlGenericErrorContext, "Add node\n");
262#endif
263 /*
264 * read the attributes
265 */
266 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
267 if (href == NULL) {
268 href = xmlGetProp(cur, XINCLUDE_HREF);
269 if (href == NULL) {
270 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
271 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000272 }
273 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000274 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
275 if (parse == NULL) {
276 parse = xmlGetProp(cur, XINCLUDE_PARSE);
277 }
278 if (parse != NULL) {
279 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
280 xml = 1;
281 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
282 xml = 0;
283 else {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000284 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000285 "XInclude: invalid value %s for %s\n",
286 parse, XINCLUDE_PARSE);
287 if (href != NULL)
288 xmlFree(href);
289 if (parse != NULL)
290 xmlFree(parse);
291 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000292 }
293 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000294
295 /*
296 * compute the URI
297 */
298 base = xmlNodeGetBase(ctxt->doc, cur);
299 if (base == NULL) {
300 URI = xmlBuildURI(href, ctxt->doc->URL);
301 } else {
302 URI = xmlBuildURI(href, base);
303 }
304 if (URI == NULL) {
305 xmlChar *escbase;
306 xmlChar *eschref;
307 /*
308 * Some escaping may be needed
309 */
310 escbase = xmlURIEscape(base);
311 eschref = xmlURIEscape(href);
312 URI = xmlBuildURI(eschref, escbase);
313 if (escbase != NULL)
314 xmlFree(escbase);
315 if (eschref != NULL)
316 xmlFree(eschref);
317 }
318 if (parse != NULL)
319 xmlFree(parse);
320 if (href != NULL)
321 xmlFree(href);
322 if (base != NULL)
323 xmlFree(base);
324 if (URI == NULL) {
325 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
326 return(-1);
327 }
328
329 /*
330 * Check the URL and remove any fragment identifier
331 */
332 uri = xmlParseURI((const char *)URI);
333 if (uri == NULL) {
334 xmlGenericError(xmlGenericErrorContext,
335 "XInclude: invalid value URI %s\n", URI);
336 return(-1);
337 }
338 if (uri->fragment != NULL) {
339 fragment = (xmlChar *) uri->fragment;
340 uri->fragment = NULL;
341 }
342 URL = xmlSaveUri(uri);
343 xmlFreeURI(uri);
344 xmlFree(URI);
345 if (URL == NULL) {
346 xmlGenericError(xmlGenericErrorContext,
347 "XInclude: invalid value URI %s\n", URI);
348 if (fragment != NULL)
349 xmlFree(fragment);
350 return(-1);
351 }
352
353 ref = xmlXIncludeNewRef(ctxt, URL, cur);
354 if (ref == NULL) {
355 return(-1);
356 }
357 ref->fragment = fragment;
358 ref->doc = NULL;
359 ref->xml = xml;
360 ref->count = 1;
361 xmlFree(URL);
362 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000363}
364
365/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000366 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000367 * @ctxt: the XInclude context
368 * @doc: the new document
369 * @url: the associated URL
370 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000371 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000372 */
373static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000374xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000375 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000376 xmlXIncludeCtxtPtr newctxt;
377 int i;
378
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000379#ifdef DEBUG_XINCLUDE
380 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
381#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000382 /*
383 * Handle recursion here.
384 */
385
386 newctxt = xmlXIncludeNewContext(doc);
387 if (newctxt != NULL) {
388 /*
389 * Copy the existing document set
390 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000391 newctxt->incMax = ctxt->incMax;
392 newctxt->incNr = ctxt->incNr;
393 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
394 sizeof(newctxt->incTab[0]));
395 if (newctxt->incTab == NULL) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000396 xmlGenericError(xmlGenericErrorContext,
397 "malloc failed !\n");
398 xmlFree(newctxt);
399 return;
400 }
401
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000402 /*
403 * Inherit the documents already in use by others includes
404 */
405 newctxt->incBase = ctxt->incNr;
406 for (i = 0;i < ctxt->incNr;i++) {
407 newctxt->incTab[i] = ctxt->incTab[i];
408 newctxt->incTab[i]->count++; /* prevent the recursion from
409 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000410 }
411 xmlXIncludeDoProcess(newctxt, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000412 for (i = 0;i < ctxt->incNr;i++) {
413 newctxt->incTab[i]->count--;
414 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000415 }
416 xmlXIncludeFreeContext(newctxt);
417 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000418#ifdef DEBUG_XINCLUDE
419 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
420#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000421}
422
423/**
424 * xmlXIncludeAddTxt:
425 * @ctxt: the XInclude context
426 * @txt: the new text node
427 * @url: the associated URL
428 *
429 * Add a new txtument to the list
430 */
431static void
432xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000433#ifdef DEBUG_XINCLUDE
434 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
435#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000436 if (ctxt->txtMax == 0) {
437 ctxt->txtMax = 4;
438 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
439 sizeof(ctxt->txtTab[0]));
440 if (ctxt->txtTab == NULL) {
441 xmlGenericError(xmlGenericErrorContext,
442 "malloc failed !\n");
443 return;
444 }
445 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
446 sizeof(ctxt->txturlTab[0]));
447 if (ctxt->txturlTab == NULL) {
448 xmlGenericError(xmlGenericErrorContext,
449 "malloc failed !\n");
450 return;
451 }
452 }
453 if (ctxt->txtNr >= ctxt->txtMax) {
454 ctxt->txtMax *= 2;
455 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
456 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
457 if (ctxt->txtTab == NULL) {
458 xmlGenericError(xmlGenericErrorContext,
459 "realloc failed !\n");
460 return;
461 }
462 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000463 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000464 if (ctxt->txturlTab == NULL) {
465 xmlGenericError(xmlGenericErrorContext,
466 "realloc failed !\n");
467 return;
468 }
469 }
470 ctxt->txtTab[ctxt->txtNr] = txt;
471 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
472 ctxt->txtNr++;
473}
474
Owen Taylor3473f882001-02-23 17:55:21 +0000475/************************************************************************
476 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000477 * Node copy with specific semantic *
478 * *
479 ************************************************************************/
480
481/**
482 * xmlXIncludeCopyNode:
483 * @ctxt: the XInclude context
484 * @target: the document target
485 * @source: the document source
486 * @elem: the element
487 *
488 * Make a copy of the node while preserving the XInclude semantic
489 * of the Infoset copy
490 */
491static xmlNodePtr
492xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
493 xmlDocPtr source, xmlNodePtr elem) {
494 xmlNodePtr result = NULL;
495
496 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
497 (elem == NULL))
498 return(NULL);
499 if (elem->type == XML_DTD_NODE)
500 return(NULL);
501 result = xmlDocCopyNode(elem, target, 1);
502 return(result);
503}
504
505/**
506 * xmlXIncludeCopyNodeList:
507 * @ctxt: the XInclude context
508 * @target: the document target
509 * @source: the document source
510 * @elem: the element list
511 *
512 * Make a copy of the node list while preserving the XInclude semantic
513 * of the Infoset copy
514 */
515static xmlNodePtr
516xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
517 xmlDocPtr source, xmlNodePtr elem) {
518 xmlNodePtr cur, res, result = NULL, last = NULL;
519
520 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
521 (elem == NULL))
522 return(NULL);
523 cur = elem;
524 while (cur != NULL) {
525 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
526 if (res != NULL) {
527 if (result == NULL) {
528 result = last = res;
529 } else {
530 last->next = res;
531 res->prev = last;
532 last = res;
533 }
534 }
535 cur = cur->next;
536 }
537 return(result);
538}
539
540/**
541 * xmlXInclueGetNthChild:
542 * @cur: the node
543 * @no: the child number
544 *
545 * Returns the @no'th element child of @cur or NULL
546 */
547static xmlNodePtr
548xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
549 int i;
550 if (cur == NULL)
551 return(cur);
552 cur = cur->children;
553 for (i = 0;i <= no;cur = cur->next) {
554 if (cur == NULL)
555 return(cur);
556 if ((cur->type == XML_ELEMENT_NODE) ||
557 (cur->type == XML_DOCUMENT_NODE) ||
558 (cur->type == XML_HTML_DOCUMENT_NODE)) {
559 i++;
560 if (i == no)
561 break;
562 }
563 }
564 return(cur);
565}
566
567xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
568
569/**
570 * xmlXIncludeCopyRange:
571 * @ctxt: the XInclude context
572 * @target: the document target
573 * @source: the document source
574 * @obj: the XPointer result from the evaluation.
575 *
576 * Build a node list tree copy of the XPointer result.
577 *
578 * Returns an xmlNodePtr list or NULL.
579 * the caller has to free the node tree.
580 */
581static xmlNodePtr
582xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
583 xmlDocPtr source, xmlXPathObjectPtr range) {
584 /* pointers to generated nodes */
585 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
586 /* pointers to traversal nodes */
587 xmlNodePtr start, cur, end;
588 int index1, index2;
589
590 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
591 (range == NULL))
592 return(NULL);
593 if (range->type != XPATH_RANGE)
594 return(NULL);
595 start = (xmlNodePtr) range->user;
596
597 if (start == NULL)
598 return(NULL);
599 end = range->user2;
600 if (end == NULL)
601 return(xmlDocCopyNode(start, target, 1));
602
603 cur = start;
604 index1 = range->index;
605 index2 = range->index2;
606 while (cur != NULL) {
607 if (cur == end) {
608 if (cur->type == XML_TEXT_NODE) {
609 const xmlChar *content = cur->content;
610 int len;
611
612 if (content == NULL) {
613 tmp = xmlNewTextLen(NULL, 0);
614 } else {
615 len = index2;
616 if ((cur == start) && (index1 > 1)) {
617 content += (index1 - 1);
618 len -= (index1 - 1);
619 index1 = 0;
620 } else {
621 len = index2;
622 }
623 tmp = xmlNewTextLen(content, len);
624 }
625 /* single sub text node selection */
626 if (list == NULL)
627 return(tmp);
628 /* prune and return full set */
629 if (last != NULL)
630 xmlAddNextSibling(last, tmp);
631 else
632 xmlAddChild(parent, tmp);
633 return(list);
634 } else {
635 tmp = xmlDocCopyNode(cur, target, 0);
636 if (list == NULL)
637 list = tmp;
638 else {
639 if (last != NULL)
640 xmlAddNextSibling(last, tmp);
641 else
642 xmlAddChild(parent, tmp);
643 }
644 last = NULL;
645 parent = tmp;
646
647 if (index2 > 1) {
648 end = xmlXIncludeGetNthChild(cur, index2 - 1);
649 index2 = 0;
650 }
651 if ((cur == start) && (index1 > 1)) {
652 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
653 index1 = 0;
654 } else {
655 cur = cur->children;
656 }
657 /*
658 * Now gather the remaining nodes from cur to end
659 */
660 continue; /* while */
661 }
662 } else if ((cur == start) &&
663 (list == NULL) /* looks superfluous but ... */ ) {
664 if ((cur->type == XML_TEXT_NODE) ||
665 (cur->type == XML_CDATA_SECTION_NODE)) {
666 const xmlChar *content = cur->content;
667
668 if (content == NULL) {
669 tmp = xmlNewTextLen(NULL, 0);
670 } else {
671 if (index1 > 1) {
672 content += (index1 - 1);
673 }
674 tmp = xmlNewText(content);
675 }
676 last = list = tmp;
677 } else {
678 if ((cur == start) && (index1 > 1)) {
679 tmp = xmlDocCopyNode(cur, target, 0);
680 list = tmp;
681 parent = tmp;
682 last = NULL;
683 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
684 index1 = 0;
685 /*
686 * Now gather the remaining nodes from cur to end
687 */
688 continue; /* while */
689 }
690 tmp = xmlDocCopyNode(cur, target, 1);
691 list = tmp;
692 parent = NULL;
693 last = tmp;
694 }
695 } else {
696 tmp = NULL;
697 switch (cur->type) {
698 case XML_DTD_NODE:
699 case XML_ELEMENT_DECL:
700 case XML_ATTRIBUTE_DECL:
701 case XML_ENTITY_NODE:
702 /* Do not copy DTD informations */
703 break;
704 case XML_ENTITY_DECL:
705 /* handle crossing entities -> stack needed */
706 break;
707 case XML_XINCLUDE_START:
708 case XML_XINCLUDE_END:
709 /* don't consider it part of the tree content */
710 break;
711 case XML_ATTRIBUTE_NODE:
712 /* Humm, should not happen ! */
713 break;
714 default:
715 tmp = xmlDocCopyNode(cur, target, 1);
716 break;
717 }
718 if (tmp != NULL) {
719 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
720 return(NULL);
721 }
722 if (last != NULL)
723 xmlAddNextSibling(last, tmp);
724 else {
725 xmlAddChild(parent, tmp);
726 last = tmp;
727 }
728 }
729 }
730 /*
731 * Skip to next node in document order
732 */
733 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
734 return(NULL);
735 }
736 cur = xmlXPtrAdvanceNode(cur);
737 }
738 return(list);
739}
740
741/**
742 * xmlXIncludeBuildNodeList:
743 * @ctxt: the XInclude context
744 * @target: the document target
745 * @source: the document source
746 * @obj: the XPointer result from the evaluation.
747 *
748 * Build a node list tree copy of the XPointer result.
749 * This will drop Attributes and Namespace declarations.
750 *
751 * Returns an xmlNodePtr list or NULL.
752 * the caller has to free the node tree.
753 */
754static xmlNodePtr
755xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
756 xmlDocPtr source, xmlXPathObjectPtr obj) {
757 xmlNodePtr list = NULL, last = NULL;
758 int i;
759
760 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
761 (obj == NULL))
762 return(NULL);
763 switch (obj->type) {
764 case XPATH_NODESET: {
765 xmlNodeSetPtr set = obj->nodesetval;
766 if (set == NULL)
767 return(NULL);
768 for (i = 0;i < set->nodeNr;i++) {
769 if (set->nodeTab[i] == NULL)
770 continue;
771 switch (set->nodeTab[i]->type) {
772 case XML_TEXT_NODE:
773 case XML_CDATA_SECTION_NODE:
774 case XML_ELEMENT_NODE:
775 case XML_ENTITY_REF_NODE:
776 case XML_ENTITY_NODE:
777 case XML_PI_NODE:
778 case XML_COMMENT_NODE:
779 case XML_DOCUMENT_NODE:
780 case XML_HTML_DOCUMENT_NODE:
781#ifdef LIBXML_DOCB_ENABLED
782 case XML_DOCB_DOCUMENT_NODE:
783#endif
784 case XML_XINCLUDE_START:
785 case XML_XINCLUDE_END:
786 break;
787 case XML_ATTRIBUTE_NODE:
788 case XML_NAMESPACE_DECL:
789 case XML_DOCUMENT_TYPE_NODE:
790 case XML_DOCUMENT_FRAG_NODE:
791 case XML_NOTATION_NODE:
792 case XML_DTD_NODE:
793 case XML_ELEMENT_DECL:
794 case XML_ATTRIBUTE_DECL:
795 case XML_ENTITY_DECL:
796 continue; /* for */
797 }
798 if (last == NULL)
799 list = last = xmlXIncludeCopyNode(ctxt, target, source,
800 set->nodeTab[i]);
801 else {
802 xmlAddNextSibling(last,
803 xmlXIncludeCopyNode(ctxt, target, source,
804 set->nodeTab[i]));
805 if (last->next != NULL)
806 last = last->next;
807 }
808 }
809 break;
810 }
811 case XPATH_LOCATIONSET: {
812 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
813 if (set == NULL)
814 return(NULL);
815 for (i = 0;i < set->locNr;i++) {
816 if (last == NULL)
817 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
818 set->locTab[i]);
819 else
820 xmlAddNextSibling(last,
821 xmlXIncludeCopyXPointer(ctxt, target, source,
822 set->locTab[i]));
823 if (last != NULL) {
824 while (last->next != NULL)
825 last = last->next;
826 }
827 }
828 break;
829 }
830 case XPATH_RANGE:
831 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
832 case XPATH_POINT:
833 /* points are ignored in XInclude */
834 break;
835 default:
836 break;
837 }
838 return(list);
839}
840/************************************************************************
841 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000842 * XInclude I/O handling *
843 * *
844 ************************************************************************/
845
846/**
Daniel Veillard4287c572003-02-04 22:48:53 +0000847 * xmlXIncludeMergeOneEntity:
848 * @ent: the entity
849 * @doc: the including doc
850 * @nr: the entity name
851 *
852 * Inplements the merge of one entity
853 */
854static void
855xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlDocPtr doc,
856 xmlChar *name ATTRIBUTE_UNUSED) {
857 xmlEntityPtr ret;
858
859 if ((ent == NULL) || (doc == NULL))
860 return;
861 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
862 ent->SystemID, ent->content);
863 if (ret != NULL) {
864 if (ent->URI != NULL)
865 ret->URI = xmlStrdup(ent->URI);
866 }
867}
868
869/**
870 * xmlXIncludeMergeEntities:
871 * @ctxt: an XInclude context
872 * @doc: the including doc
873 * @from: the included doc
874 *
875 * Inplements the entity merge
876 *
877 * Returns 0 if merge succeeded, -1 if some processing failed
878 */
879static int
880xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
881 xmlDocPtr from) {
882 xmlNodePtr cur;
883 xmlDtdPtr target, source;
884
885 if (ctxt == NULL)
886 return(-1);
887
888 if ((from == NULL) || (from->intSubset == NULL))
889 return(0);
890
891 target = doc->intSubset;
892 if (target == NULL) {
893 cur = xmlDocGetRootElement(doc);
894 if (cur == NULL)
895 return(-1);
896 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
897 if (target == NULL)
898 return(-1);
899 }
900
901 source = from->intSubset;
902 if ((source != NULL) && (source->entities != NULL)) {
903 xmlHashScan((xmlHashTablePtr) source->entities,
904 (xmlHashScanner) xmlXIncludeMergeEntity, doc);
905 }
906 source = from->extSubset;
907 if ((source != NULL) && (source->entities != NULL)) {
908 /*
909 * don't duplicate existing stuff when external subsets are the same
910 */
911 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
912 (!xmlStrEqual(target->SystemID, source->SystemID))) {
913 xmlHashScan((xmlHashTablePtr) source->entities,
914 (xmlHashScanner) xmlXIncludeMergeEntity, doc);
915 }
916 }
917 return(0);
918}
919
920/**
Owen Taylor3473f882001-02-23 17:55:21 +0000921 * xmlXIncludeLoadDoc:
922 * @ctxt: the XInclude context
923 * @url: the associated URL
924 * @nr: the xinclude node number
925 *
926 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000927 *
928 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000929 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000930static int
Owen Taylor3473f882001-02-23 17:55:21 +0000931xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
932 xmlDocPtr doc;
933 xmlURIPtr uri;
934 xmlChar *URL;
935 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000936 int i = 0;
937
938#ifdef DEBUG_XINCLUDE
939 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
940#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000941 /*
942 * Check the URL and remove any fragment identifier
943 */
944 uri = xmlParseURI((const char *)url);
945 if (uri == NULL) {
946 xmlGenericError(xmlGenericErrorContext,
947 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000948 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000949 }
950 if (uri->fragment != NULL) {
951 fragment = (xmlChar *) uri->fragment;
952 uri->fragment = NULL;
953 }
954 URL = xmlSaveUri(uri);
955 xmlFreeURI(uri);
956 if (URL == NULL) {
957 xmlGenericError(xmlGenericErrorContext,
958 "XInclude: invalid value URI %s\n", url);
959 if (fragment != NULL)
960 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000961 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000962 }
963
964 /*
965 * Handling of references to the local document are done
966 * directly through ctxt->doc.
967 */
968 if ((URL[0] == 0) || (URL[0] == '#')) {
969 doc = NULL;
970 goto loaded;
971 }
972
973 /*
974 * Prevent reloading twice the document.
975 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000976 for (i = 0; i < ctxt->incNr; i++) {
977 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
978 (ctxt->incTab[i]->doc != NULL)) {
979 doc = ctxt->incTab[i]->doc;
980#ifdef DEBUG_XINCLUDE
981 printf("Already loaded %s\n", URL);
982#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000983 goto loaded;
984 }
985 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000986
Owen Taylor3473f882001-02-23 17:55:21 +0000987 /*
988 * Load it.
989 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000990#ifdef DEBUG_XINCLUDE
991 printf("loading %s\n", URL);
992#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000993 doc = xmlParseFile((const char *)URL);
994 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000995 xmlFree(URL);
996 if (fragment != NULL)
997 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000998 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001000 ctxt->incTab[nr]->doc = doc;
1001
1002 /*
Daniel Veillard4287c572003-02-04 22:48:53 +00001003 * Make sure we have all entities fixed up
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001004 */
Daniel Veillard4287c572003-02-04 22:48:53 +00001005 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001006
1007 /*
1008 * We don't need the DTD anymore, free up space
1009 if (doc->intSubset != NULL) {
1010 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1011 xmlFreeNode((xmlNodePtr) doc->intSubset);
1012 doc->intSubset = NULL;
1013 }
1014 if (doc->extSubset != NULL) {
1015 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1016 xmlFreeNode((xmlNodePtr) doc->extSubset);
1017 doc->extSubset = NULL;
1018 }
1019 */
1020 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001021
1022loaded:
1023 if (fragment == NULL) {
1024 /*
1025 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +00001026 */
1027 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +00001028 {
1029 /* Hopefully a DTD declaration won't be copied from
1030 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001031 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001032 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001033 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001034 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +00001035 }
Owen Taylor3473f882001-02-23 17:55:21 +00001036 } else {
1037 /*
1038 * Computes the XPointer expression and make a copy used
1039 * as the replacement copy.
1040 */
1041 xmlXPathObjectPtr xptr;
1042 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +00001043 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +00001044
1045 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001046 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1047 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001048 } else {
1049 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1050 }
1051 if (xptrctxt == NULL) {
1052 xmlGenericError(xmlGenericErrorContext,
1053 "XInclude: could create XPointer context\n");
1054 xmlFree(URL);
1055 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001056 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001057 }
1058 xptr = xmlXPtrEval(fragment, xptrctxt);
1059 if (xptr == NULL) {
1060 xmlGenericError(xmlGenericErrorContext,
1061 "XInclude: XPointer evaluation failed: #%s\n",
1062 fragment);
1063 xmlXPathFreeContext(xptrctxt);
1064 xmlFree(URL);
1065 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001066 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001067 }
Daniel Veillard39196eb2001-06-19 18:09:42 +00001068 switch (xptr->type) {
1069 case XPATH_UNDEFINED:
1070 case XPATH_BOOLEAN:
1071 case XPATH_NUMBER:
1072 case XPATH_STRING:
1073 case XPATH_POINT:
1074 case XPATH_USERS:
1075 case XPATH_XSLT_TREE:
1076 xmlGenericError(xmlGenericErrorContext,
1077 "XInclude: XPointer is not a range: #%s\n",
1078 fragment);
1079 xmlXPathFreeContext(xptrctxt);
1080 xmlFree(URL);
1081 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001082 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001083 case XPATH_NODESET:
1084 case XPATH_RANGE:
1085 case XPATH_LOCATIONSET:
1086 break;
1087 }
1088 set = xptr->nodesetval;
1089 if (set != NULL) {
1090 for (i = 0;i < set->nodeNr;i++) {
1091 if (set->nodeTab[i] == NULL)
1092 continue;
1093 switch (set->nodeTab[i]->type) {
1094 case XML_TEXT_NODE:
1095 case XML_CDATA_SECTION_NODE:
1096 case XML_ELEMENT_NODE:
1097 case XML_ENTITY_REF_NODE:
1098 case XML_ENTITY_NODE:
1099 case XML_PI_NODE:
1100 case XML_COMMENT_NODE:
1101 case XML_DOCUMENT_NODE:
1102 case XML_HTML_DOCUMENT_NODE:
1103#ifdef LIBXML_DOCB_ENABLED
1104 case XML_DOCB_DOCUMENT_NODE:
1105#endif
1106 continue;
1107 case XML_ATTRIBUTE_NODE:
1108 xmlGenericError(xmlGenericErrorContext,
1109 "XInclude: XPointer selects an attribute: #%s\n",
1110 fragment);
1111 set->nodeTab[i] = NULL;
1112 continue;
1113 case XML_NAMESPACE_DECL:
1114 xmlGenericError(xmlGenericErrorContext,
1115 "XInclude: XPointer selects a namespace: #%s\n",
1116 fragment);
1117 set->nodeTab[i] = NULL;
1118 continue;
1119 case XML_DOCUMENT_TYPE_NODE:
1120 case XML_DOCUMENT_FRAG_NODE:
1121 case XML_NOTATION_NODE:
1122 case XML_DTD_NODE:
1123 case XML_ELEMENT_DECL:
1124 case XML_ATTRIBUTE_DECL:
1125 case XML_ENTITY_DECL:
1126 case XML_XINCLUDE_START:
1127 case XML_XINCLUDE_END:
1128 xmlGenericError(xmlGenericErrorContext,
1129 "XInclude: XPointer selects unexpected nodes: #%s\n",
1130 fragment);
1131 set->nodeTab[i] = NULL;
1132 set->nodeTab[i] = NULL;
1133 continue; /* for */
1134 }
1135 }
1136 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001137 ctxt->incTab[nr]->inc =
1138 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
Owen Taylor3473f882001-02-23 17:55:21 +00001139 xmlXPathFreeObject(xptr);
1140 xmlXPathFreeContext(xptrctxt);
1141 xmlFree(fragment);
1142 }
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001143
1144 /*
1145 * Do the xml:base fixup if needed
1146 */
1147 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1148 xmlNodePtr node;
1149
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001150 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001151 while (node != NULL) {
1152 if (node->type == XML_ELEMENT_NODE)
1153 xmlNodeSetBase(node, URL);
1154 node = node->next;
1155 }
1156 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001157 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1158 (ctxt->incTab[nr]->count <= 1)) {
1159#ifdef DEBUG_XINCLUDE
1160 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1161#endif
1162 xmlFreeDoc(ctxt->incTab[nr]->doc);
1163 ctxt->incTab[nr]->doc = NULL;
1164 }
Owen Taylor3473f882001-02-23 17:55:21 +00001165 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001166 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001167}
1168
1169/**
1170 * xmlXIncludeLoadTxt:
1171 * @ctxt: the XInclude context
1172 * @url: the associated URL
1173 * @nr: the xinclude node number
1174 *
1175 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001176 *
1177 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001178 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001179static int
Owen Taylor3473f882001-02-23 17:55:21 +00001180xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1181 xmlParserInputBufferPtr buf;
1182 xmlNodePtr node;
1183 xmlURIPtr uri;
1184 xmlChar *URL;
1185 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001186 xmlChar *encoding = NULL;
1187 xmlCharEncoding enc = 0;
1188
Owen Taylor3473f882001-02-23 17:55:21 +00001189 /*
1190 * Check the URL and remove any fragment identifier
1191 */
1192 uri = xmlParseURI((const char *)url);
1193 if (uri == NULL) {
1194 xmlGenericError(xmlGenericErrorContext,
1195 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001196 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001197 }
1198 if (uri->fragment != NULL) {
1199 xmlGenericError(xmlGenericErrorContext,
1200 "XInclude: fragment identifier forbidden for text: %s\n",
1201 uri->fragment);
1202 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001203 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001204 }
1205 URL = xmlSaveUri(uri);
1206 xmlFreeURI(uri);
1207 if (URL == NULL) {
1208 xmlGenericError(xmlGenericErrorContext,
1209 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001210 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001211 }
1212
1213 /*
1214 * Handling of references to the local document are done
1215 * directly through ctxt->doc.
1216 */
1217 if (URL[0] == 0) {
1218 xmlGenericError(xmlGenericErrorContext,
1219 "XInclude: text serialization of document not available\n");
1220 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001221 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001222 }
1223
1224 /*
1225 * Prevent reloading twice the document.
1226 */
1227 for (i = 0; i < ctxt->txtNr; i++) {
1228 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1229 node = xmlCopyNode(ctxt->txtTab[i], 1);
1230 goto loaded;
1231 }
1232 }
1233 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001234 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001235 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001236 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1237 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1238 }
1239 if (encoding != NULL) {
1240 /*
1241 * TODO: we should not have to remap to the xmlCharEncoding
1242 * predefined set, a better interface than
1243 * xmlParserInputBufferCreateFilename should allow any
1244 * encoding supported by iconv
1245 */
1246 enc = xmlParseCharEncoding((const char *) encoding);
1247 if (enc == XML_CHAR_ENCODING_ERROR) {
1248 xmlGenericError(xmlGenericErrorContext,
1249 "XInclude: encoding %s not supported\n", encoding);
1250 xmlFree(encoding);
1251 xmlFree(URL);
1252 return(-1);
1253 }
1254 xmlFree(encoding);
1255 }
1256
1257 /*
1258 * Load it.
1259 */
1260 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001261 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001262 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001263 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001264 }
1265 node = xmlNewText(NULL);
1266
1267 /*
1268 * Scan all chars from the resource and add the to the node
1269 */
1270 while (xmlParserInputBufferRead(buf, 128) > 0) {
1271 int len;
1272 const xmlChar *content;
1273
1274 content = xmlBufferContent(buf->buffer);
1275 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001276 for (i = 0;i < len;) {
1277 int cur;
1278 int l;
1279
1280 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1281 if (!IS_CHAR(cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001282 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd076a202002-11-20 13:28:31 +00001283 "XInclude: %s contains invalid char %d\n", URL, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001284 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001285 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001286 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001287 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001288 }
1289 xmlBufferShrink(buf->buffer, len);
1290 }
1291 xmlFreeParserInputBuffer(buf);
1292 xmlXIncludeAddTxt(ctxt, node, URL);
1293
1294loaded:
1295 /*
1296 * Add the element as the replacement copy.
1297 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001298 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001299 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001300 return(0);
1301}
1302
1303/**
1304 * xmlXIncludeLoadFallback:
1305 * @ctxt: the XInclude context
1306 * @fallback: the fallback node
1307 * @nr: the xinclude node number
1308 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001309 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001310 * in the XInclude context
1311 *
1312 * Returns 0 in case of success, -1 in case of failure
1313 */
1314static int
1315xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1316 if ((fallback == NULL) || (ctxt == NULL))
1317 return(-1);
1318
Daniel Veillard06503452002-12-13 10:42:08 +00001319 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001320 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001321}
1322
1323/************************************************************************
1324 * *
1325 * XInclude Processing *
1326 * *
1327 ************************************************************************/
1328
1329/**
1330 * xmlXIncludePreProcessNode:
1331 * @ctxt: an XInclude context
1332 * @node: an XInclude node
1333 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001334 * Implement the XInclude preprocessing, currently just adding the element
1335 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001336 *
1337 * Returns the result list or NULL in case of error
1338 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001339static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001340xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1341 xmlXIncludeAddNode(ctxt, node);
1342 return(0);
1343}
1344
Daniel Veillard118aed72002-09-24 14:13:13 +00001345#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00001346/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001347 * xmlXIncludePreloadNode:
1348 * @ctxt: an XInclude context
1349 * @nr: the node number
1350 *
1351 * Do some precomputations and preload shared documents
1352 *
1353 * Returns 0 if substitution succeeded, -1 if some processing failed
1354 */
1355static int
1356xmlXIncludePreloadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1357 xmlNodePtr cur;
1358 xmlChar *href;
1359 xmlChar *parse;
1360 xmlChar *base;
1361 xmlChar *URI;
1362 int xml = 1; /* default Issue 64 */
1363 xmlURIPtr uri;
1364 xmlChar *URL;
1365 xmlChar *fragment = NULL;
1366 int i;
1367
1368
1369 if (ctxt == NULL)
1370 return(-1);
1371 if ((nr < 0) || (nr >= ctxt->incNr))
1372 return(-1);
1373 cur = ctxt->incTab[nr]->ref;
1374 if (cur == NULL)
1375 return(-1);
1376
1377 /*
1378 * read the attributes
1379 */
1380 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1381 if (href == NULL) {
1382 href = xmlGetProp(cur, XINCLUDE_HREF);
1383 if (href == NULL) {
1384 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1385 return(-1);
1386 }
1387 }
1388 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1389 if (parse == NULL) {
1390 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1391 }
1392 if (parse != NULL) {
1393 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1394 xml = 1;
1395 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1396 xml = 0;
1397 else {
1398 xmlGenericError(xmlGenericErrorContext,
1399 "XInclude: invalid value %s for %s\n",
1400 parse, XINCLUDE_PARSE);
1401 if (href != NULL)
1402 xmlFree(href);
1403 if (parse != NULL)
1404 xmlFree(parse);
1405 return(-1);
1406 }
1407 }
1408
1409 /*
1410 * compute the URI
1411 */
1412 base = xmlNodeGetBase(ctxt->doc, cur);
1413 if (base == NULL) {
1414 URI = xmlBuildURI(href, ctxt->doc->URL);
1415 } else {
1416 URI = xmlBuildURI(href, base);
1417 }
1418 if (URI == NULL) {
1419 xmlChar *escbase;
1420 xmlChar *eschref;
1421 /*
1422 * Some escaping may be needed
1423 */
1424 escbase = xmlURIEscape(base);
1425 eschref = xmlURIEscape(href);
1426 URI = xmlBuildURI(eschref, escbase);
1427 if (escbase != NULL)
1428 xmlFree(escbase);
1429 if (eschref != NULL)
1430 xmlFree(eschref);
1431 }
1432 if (parse != NULL)
1433 xmlFree(parse);
1434 if (href != NULL)
1435 xmlFree(href);
1436 if (base != NULL)
1437 xmlFree(base);
1438 if (URI == NULL) {
1439 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1440 return(-1);
1441 }
1442
1443 /*
1444 * Check the URL and remove any fragment identifier
1445 */
1446 uri = xmlParseURI((const char *)URI);
1447 if (uri == NULL) {
1448 xmlGenericError(xmlGenericErrorContext,
1449 "XInclude: invalid value URI %s\n", URI);
1450 xmlFree(URI);
1451 return(-1);
1452 }
1453 if (uri->fragment != NULL) {
1454 fragment = (xmlChar *) uri->fragment;
1455 uri->fragment = NULL;
1456 }
1457 URL = xmlSaveUri(uri);
1458 xmlFreeURI(uri);
1459 if (URL == NULL) {
1460 xmlGenericError(xmlGenericErrorContext,
1461 "XInclude: invalid value URI %s\n", URI);
1462 if (fragment != NULL)
1463 xmlFree(fragment);
1464 xmlFree(URI);
1465 return(-1);
1466 }
1467 xmlFree(URI);
1468 if (fragment != NULL)
1469 xmlFree(fragment);
1470
1471 for (i = 0; i < nr; i++) {
1472 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1473#ifdef DEBUG_XINCLUDE
1474 printf("Incrementing count for %d : %s\n", i, ctxt->incTab[i]->URI);
1475#endif
1476 ctxt->incTab[i]->count++;
1477 break;
1478 }
1479 }
1480 xmlFree(URL);
1481 return(0);
1482}
Daniel Veillard118aed72002-09-24 14:13:13 +00001483#endif
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001484
1485/**
Owen Taylor3473f882001-02-23 17:55:21 +00001486 * xmlXIncludeLoadNode:
1487 * @ctxt: an XInclude context
1488 * @nr: the node number
1489 *
1490 * Find and load the infoset replacement for the given node.
1491 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001492 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001493 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001494static int
Owen Taylor3473f882001-02-23 17:55:21 +00001495xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1496 xmlNodePtr cur;
1497 xmlChar *href;
1498 xmlChar *parse;
1499 xmlChar *base;
1500 xmlChar *URI;
1501 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001502 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001503
1504 if (ctxt == NULL)
1505 return(-1);
1506 if ((nr < 0) || (nr >= ctxt->incNr))
1507 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001508 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001509 if (cur == NULL)
1510 return(-1);
1511
Owen Taylor3473f882001-02-23 17:55:21 +00001512 /*
1513 * read the attributes
1514 */
1515 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1516 if (href == NULL) {
1517 href = xmlGetProp(cur, XINCLUDE_HREF);
1518 if (href == NULL) {
1519 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1520 return(-1);
1521 }
1522 }
1523 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1524 if (parse == NULL) {
1525 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1526 }
1527 if (parse != NULL) {
1528 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1529 xml = 1;
1530 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1531 xml = 0;
1532 else {
1533 xmlGenericError(xmlGenericErrorContext,
1534 "XInclude: invalid value %s for %s\n",
1535 parse, XINCLUDE_PARSE);
1536 if (href != NULL)
1537 xmlFree(href);
1538 if (parse != NULL)
1539 xmlFree(parse);
1540 return(-1);
1541 }
1542 }
1543
1544 /*
1545 * compute the URI
1546 */
1547 base = xmlNodeGetBase(ctxt->doc, cur);
1548 if (base == NULL) {
1549 URI = xmlBuildURI(href, ctxt->doc->URL);
1550 } else {
1551 URI = xmlBuildURI(href, base);
1552 }
1553 if (URI == NULL) {
1554 xmlChar *escbase;
1555 xmlChar *eschref;
1556 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001557 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001558 */
1559 escbase = xmlURIEscape(base);
1560 eschref = xmlURIEscape(href);
1561 URI = xmlBuildURI(eschref, escbase);
1562 if (escbase != NULL)
1563 xmlFree(escbase);
1564 if (eschref != NULL)
1565 xmlFree(eschref);
1566 }
1567 if (URI == NULL) {
1568 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1569 if (parse != NULL)
1570 xmlFree(parse);
1571 if (href != NULL)
1572 xmlFree(href);
1573 if (base != NULL)
1574 xmlFree(base);
1575 return(-1);
1576 }
1577#ifdef DEBUG_XINCLUDE
1578 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1579 xml ? "xml": "text");
1580 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1581#endif
1582
1583 /*
1584 * Cleanup
1585 */
1586 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001587 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001588 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1589 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001590 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1591 }
1592 if (ret < 0) {
1593 xmlNodePtr children;
1594
1595 /*
1596 * Time to try a fallback if availble
1597 */
1598#ifdef DEBUG_XINCLUDE
1599 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1600#endif
1601 children = cur->children;
1602 while (children != NULL) {
1603 if ((children->type == XML_ELEMENT_NODE) &&
1604 (children->ns != NULL) &&
1605 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1606 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1607 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1608 if (ret == 0)
1609 break;
1610 }
1611 children = children->next;
1612 }
1613 }
1614 if (ret < 0) {
1615 xmlGenericError(xmlGenericErrorContext,
1616 "XInclude: could not load %s, and no fallback was found\n",
1617 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001618 }
1619
1620 /*
1621 * Cleanup
1622 */
1623 if (URI != NULL)
1624 xmlFree(URI);
1625 if (parse != NULL)
1626 xmlFree(parse);
1627 if (href != NULL)
1628 xmlFree(href);
1629 if (base != NULL)
1630 xmlFree(base);
1631 return(0);
1632}
1633
1634/**
1635 * xmlXIncludeIncludeNode:
1636 * @ctxt: an XInclude context
1637 * @nr: the node number
1638 *
1639 * Inplement the infoset replacement for the given node
1640 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001641 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001642 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001643static int
Owen Taylor3473f882001-02-23 17:55:21 +00001644xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1645 xmlNodePtr cur, end, list;
1646
1647 if (ctxt == NULL)
1648 return(-1);
1649 if ((nr < 0) || (nr >= ctxt->incNr))
1650 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001651 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001652 if (cur == NULL)
1653 return(-1);
1654
1655 /*
1656 * Change the current node as an XInclude start one, and add an
1657 * entity end one
1658 */
1659 cur->type = XML_XINCLUDE_START;
1660 end = xmlNewNode(cur->ns, cur->name);
1661 if (end == NULL) {
1662 xmlGenericError(xmlGenericErrorContext,
1663 "XInclude: failed to build node\n");
1664 return(-1);
1665 }
1666 end->type = XML_XINCLUDE_END;
1667 xmlAddNextSibling(cur, end);
1668
1669 /*
1670 * Add the list of nodes
1671 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001672 list = ctxt->incTab[nr]->inc;
1673 ctxt->incTab[nr]->inc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001674 while (list != NULL) {
1675 cur = list;
1676 list = list->next;
1677
1678 xmlAddPrevSibling(end, cur);
1679 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001680
1681
Owen Taylor3473f882001-02-23 17:55:21 +00001682 return(0);
1683}
1684
1685/**
1686 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +00001687 * @node: an XInclude node
1688 *
1689 * test if the node is an XInclude node
1690 *
1691 * Returns 1 true, 0 otherwise
1692 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001693static int
1694xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001695 if (node == NULL)
1696 return(0);
1697 if (node->ns == NULL)
1698 return(0);
1699 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
1700 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
1701 return(0);
1702}
1703
1704/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001705 * xmlXIncludeDoProcess:
1706 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +00001707 * @doc: an XML document
1708 *
1709 * Implement the XInclude substitution on the XML document @doc
1710 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001711 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001712 * or the number of substitutions done.
1713 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001714static int
1715xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001716 xmlNodePtr cur;
1717 int ret = 0;
1718 int i;
1719
1720 if (doc == NULL)
1721 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001722 if (ctxt == NULL)
1723 return(-1);
1724
1725 /*
1726 * First phase: lookup the elements in the document
1727 */
1728 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001729 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001730 xmlXIncludePreProcessNode(ctxt, cur);
1731 while (cur != NULL) {
1732 /* TODO: need to work on entities -> stack */
1733 if ((cur->children != NULL) &&
1734 (cur->children->type != XML_ENTITY_DECL)) {
1735 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001736 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001737 xmlXIncludePreProcessNode(ctxt, cur);
1738 } else if (cur->next != NULL) {
1739 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001740 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001741 xmlXIncludePreProcessNode(ctxt, cur);
1742 } else {
1743 do {
1744 cur = cur->parent;
1745 if (cur == NULL) break; /* do */
1746 if (cur->next != NULL) {
1747 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001748 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001749 xmlXIncludePreProcessNode(ctxt, cur);
1750 break; /* do */
1751 }
1752 } while (cur != NULL);
1753 }
1754 }
1755
1756 /*
1757 * Second Phase : collect the infosets fragments
1758 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001759 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001760 xmlXIncludeLoadNode(ctxt, i);
Daniel Veillard97fd5672003-02-07 13:01:54 +00001761 ret++;
Owen Taylor3473f882001-02-23 17:55:21 +00001762 }
1763
1764 /*
1765 * Third phase: extend the original document infoset.
1766 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001767 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001768 xmlXIncludeIncludeNode(ctxt, i);
1769 }
1770
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001771 return(ret);
1772}
1773
1774/**
1775 * xmlXIncludeProcess:
1776 * @doc: an XML document
1777 *
1778 * Implement the XInclude substitution on the XML document @doc
1779 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001780 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001781 * or the number of substitutions done.
1782 */
1783int
1784xmlXIncludeProcess(xmlDocPtr doc) {
1785 xmlXIncludeCtxtPtr ctxt;
1786 int ret = 0;
1787
1788 if (doc == NULL)
1789 return(-1);
1790 ctxt = xmlXIncludeNewContext(doc);
1791 if (ctxt == NULL)
1792 return(-1);
1793 ret = xmlXIncludeDoProcess(ctxt, doc);
1794
Owen Taylor3473f882001-02-23 17:55:21 +00001795 xmlXIncludeFreeContext(ctxt);
1796 return(ret);
1797}
1798
1799#else /* !LIBXML_XINCLUDE_ENABLED */
1800#endif