blob: 377f856320055d1ea7d935d5a1e7d51e8c86d13e [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/**
847 * xmlXIncludeLoadDoc:
848 * @ctxt: the XInclude context
849 * @url: the associated URL
850 * @nr: the xinclude node number
851 *
852 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000853 *
854 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000855 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000856static int
Owen Taylor3473f882001-02-23 17:55:21 +0000857xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
858 xmlDocPtr doc;
859 xmlURIPtr uri;
860 xmlChar *URL;
861 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000862 int i = 0;
863
864#ifdef DEBUG_XINCLUDE
865 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
866#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000867 /*
868 * Check the URL and remove any fragment identifier
869 */
870 uri = xmlParseURI((const char *)url);
871 if (uri == NULL) {
872 xmlGenericError(xmlGenericErrorContext,
873 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000874 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000875 }
876 if (uri->fragment != NULL) {
877 fragment = (xmlChar *) uri->fragment;
878 uri->fragment = NULL;
879 }
880 URL = xmlSaveUri(uri);
881 xmlFreeURI(uri);
882 if (URL == NULL) {
883 xmlGenericError(xmlGenericErrorContext,
884 "XInclude: invalid value URI %s\n", url);
885 if (fragment != NULL)
886 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000887 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000888 }
889
890 /*
891 * Handling of references to the local document are done
892 * directly through ctxt->doc.
893 */
894 if ((URL[0] == 0) || (URL[0] == '#')) {
895 doc = NULL;
896 goto loaded;
897 }
898
899 /*
900 * Prevent reloading twice the document.
901 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000902 for (i = 0; i < ctxt->incNr; i++) {
903 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
904 (ctxt->incTab[i]->doc != NULL)) {
905 doc = ctxt->incTab[i]->doc;
906#ifdef DEBUG_XINCLUDE
907 printf("Already loaded %s\n", URL);
908#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000909 goto loaded;
910 }
911 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000912
Owen Taylor3473f882001-02-23 17:55:21 +0000913 /*
914 * Load it.
915 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000916#ifdef DEBUG_XINCLUDE
917 printf("loading %s\n", URL);
918#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000919 doc = xmlParseFile((const char *)URL);
920 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000921 xmlFree(URL);
922 if (fragment != NULL)
923 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000924 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000925 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000926 ctxt->incTab[nr]->doc = doc;
927
928 /*
929 * TODO: Make sure we have all entities fixed up
930 */
931
932 /*
933 * We don't need the DTD anymore, free up space
934 if (doc->intSubset != NULL) {
935 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
936 xmlFreeNode((xmlNodePtr) doc->intSubset);
937 doc->intSubset = NULL;
938 }
939 if (doc->extSubset != NULL) {
940 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
941 xmlFreeNode((xmlNodePtr) doc->extSubset);
942 doc->extSubset = NULL;
943 }
944 */
945 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000946
947loaded:
948 if (fragment == NULL) {
949 /*
950 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +0000951 */
952 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +0000953 {
954 /* Hopefully a DTD declaration won't be copied from
955 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000956 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000957 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000958 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000959 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000960 }
Owen Taylor3473f882001-02-23 17:55:21 +0000961 } else {
962 /*
963 * Computes the XPointer expression and make a copy used
964 * as the replacement copy.
965 */
966 xmlXPathObjectPtr xptr;
967 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +0000968 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +0000969
970 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000971 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
972 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000973 } else {
974 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
975 }
976 if (xptrctxt == NULL) {
977 xmlGenericError(xmlGenericErrorContext,
978 "XInclude: could create XPointer context\n");
979 xmlFree(URL);
980 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000981 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000982 }
983 xptr = xmlXPtrEval(fragment, xptrctxt);
984 if (xptr == NULL) {
985 xmlGenericError(xmlGenericErrorContext,
986 "XInclude: XPointer evaluation failed: #%s\n",
987 fragment);
988 xmlXPathFreeContext(xptrctxt);
989 xmlFree(URL);
990 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000991 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000992 }
Daniel Veillard39196eb2001-06-19 18:09:42 +0000993 switch (xptr->type) {
994 case XPATH_UNDEFINED:
995 case XPATH_BOOLEAN:
996 case XPATH_NUMBER:
997 case XPATH_STRING:
998 case XPATH_POINT:
999 case XPATH_USERS:
1000 case XPATH_XSLT_TREE:
1001 xmlGenericError(xmlGenericErrorContext,
1002 "XInclude: XPointer is not a range: #%s\n",
1003 fragment);
1004 xmlXPathFreeContext(xptrctxt);
1005 xmlFree(URL);
1006 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001007 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001008 case XPATH_NODESET:
1009 case XPATH_RANGE:
1010 case XPATH_LOCATIONSET:
1011 break;
1012 }
1013 set = xptr->nodesetval;
1014 if (set != NULL) {
1015 for (i = 0;i < set->nodeNr;i++) {
1016 if (set->nodeTab[i] == NULL)
1017 continue;
1018 switch (set->nodeTab[i]->type) {
1019 case XML_TEXT_NODE:
1020 case XML_CDATA_SECTION_NODE:
1021 case XML_ELEMENT_NODE:
1022 case XML_ENTITY_REF_NODE:
1023 case XML_ENTITY_NODE:
1024 case XML_PI_NODE:
1025 case XML_COMMENT_NODE:
1026 case XML_DOCUMENT_NODE:
1027 case XML_HTML_DOCUMENT_NODE:
1028#ifdef LIBXML_DOCB_ENABLED
1029 case XML_DOCB_DOCUMENT_NODE:
1030#endif
1031 continue;
1032 case XML_ATTRIBUTE_NODE:
1033 xmlGenericError(xmlGenericErrorContext,
1034 "XInclude: XPointer selects an attribute: #%s\n",
1035 fragment);
1036 set->nodeTab[i] = NULL;
1037 continue;
1038 case XML_NAMESPACE_DECL:
1039 xmlGenericError(xmlGenericErrorContext,
1040 "XInclude: XPointer selects a namespace: #%s\n",
1041 fragment);
1042 set->nodeTab[i] = NULL;
1043 continue;
1044 case XML_DOCUMENT_TYPE_NODE:
1045 case XML_DOCUMENT_FRAG_NODE:
1046 case XML_NOTATION_NODE:
1047 case XML_DTD_NODE:
1048 case XML_ELEMENT_DECL:
1049 case XML_ATTRIBUTE_DECL:
1050 case XML_ENTITY_DECL:
1051 case XML_XINCLUDE_START:
1052 case XML_XINCLUDE_END:
1053 xmlGenericError(xmlGenericErrorContext,
1054 "XInclude: XPointer selects unexpected nodes: #%s\n",
1055 fragment);
1056 set->nodeTab[i] = NULL;
1057 set->nodeTab[i] = NULL;
1058 continue; /* for */
1059 }
1060 }
1061 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001062 ctxt->incTab[nr]->inc =
1063 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
Owen Taylor3473f882001-02-23 17:55:21 +00001064 xmlXPathFreeObject(xptr);
1065 xmlXPathFreeContext(xptrctxt);
1066 xmlFree(fragment);
1067 }
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001068
1069 /*
1070 * Do the xml:base fixup if needed
1071 */
1072 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1073 xmlNodePtr node;
1074
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001075 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001076 while (node != NULL) {
1077 if (node->type == XML_ELEMENT_NODE)
1078 xmlNodeSetBase(node, URL);
1079 node = node->next;
1080 }
1081 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001082 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1083 (ctxt->incTab[nr]->count <= 1)) {
1084#ifdef DEBUG_XINCLUDE
1085 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1086#endif
1087 xmlFreeDoc(ctxt->incTab[nr]->doc);
1088 ctxt->incTab[nr]->doc = NULL;
1089 }
Owen Taylor3473f882001-02-23 17:55:21 +00001090 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001091 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001092}
1093
1094/**
1095 * xmlXIncludeLoadTxt:
1096 * @ctxt: the XInclude context
1097 * @url: the associated URL
1098 * @nr: the xinclude node number
1099 *
1100 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001101 *
1102 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001103 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001104static int
Owen Taylor3473f882001-02-23 17:55:21 +00001105xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1106 xmlParserInputBufferPtr buf;
1107 xmlNodePtr node;
1108 xmlURIPtr uri;
1109 xmlChar *URL;
1110 int i;
Daniel Veillardd076a202002-11-20 13:28:31 +00001111 xmlChar *encoding = NULL;
1112 xmlCharEncoding enc = 0;
1113
Owen Taylor3473f882001-02-23 17:55:21 +00001114 /*
1115 * Check the URL and remove any fragment identifier
1116 */
1117 uri = xmlParseURI((const char *)url);
1118 if (uri == NULL) {
1119 xmlGenericError(xmlGenericErrorContext,
1120 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001121 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001122 }
1123 if (uri->fragment != NULL) {
1124 xmlGenericError(xmlGenericErrorContext,
1125 "XInclude: fragment identifier forbidden for text: %s\n",
1126 uri->fragment);
1127 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001128 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001129 }
1130 URL = xmlSaveUri(uri);
1131 xmlFreeURI(uri);
1132 if (URL == NULL) {
1133 xmlGenericError(xmlGenericErrorContext,
1134 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001135 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001136 }
1137
1138 /*
1139 * Handling of references to the local document are done
1140 * directly through ctxt->doc.
1141 */
1142 if (URL[0] == 0) {
1143 xmlGenericError(xmlGenericErrorContext,
1144 "XInclude: text serialization of document not available\n");
1145 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001146 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001147 }
1148
1149 /*
1150 * Prevent reloading twice the document.
1151 */
1152 for (i = 0; i < ctxt->txtNr; i++) {
1153 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1154 node = xmlCopyNode(ctxt->txtTab[i], 1);
1155 goto loaded;
1156 }
1157 }
1158 /*
Daniel Veillardd076a202002-11-20 13:28:31 +00001159 * Try to get the encoding if available
Owen Taylor3473f882001-02-23 17:55:21 +00001160 */
Daniel Veillardd076a202002-11-20 13:28:31 +00001161 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1162 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1163 }
1164 if (encoding != NULL) {
1165 /*
1166 * TODO: we should not have to remap to the xmlCharEncoding
1167 * predefined set, a better interface than
1168 * xmlParserInputBufferCreateFilename should allow any
1169 * encoding supported by iconv
1170 */
1171 enc = xmlParseCharEncoding((const char *) encoding);
1172 if (enc == XML_CHAR_ENCODING_ERROR) {
1173 xmlGenericError(xmlGenericErrorContext,
1174 "XInclude: encoding %s not supported\n", encoding);
1175 xmlFree(encoding);
1176 xmlFree(URL);
1177 return(-1);
1178 }
1179 xmlFree(encoding);
1180 }
1181
1182 /*
1183 * Load it.
1184 */
1185 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
Owen Taylor3473f882001-02-23 17:55:21 +00001186 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001187 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001188 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001189 }
1190 node = xmlNewText(NULL);
1191
1192 /*
1193 * Scan all chars from the resource and add the to the node
1194 */
1195 while (xmlParserInputBufferRead(buf, 128) > 0) {
1196 int len;
1197 const xmlChar *content;
1198
1199 content = xmlBufferContent(buf->buffer);
1200 len = xmlBufferLength(buf->buffer);
Daniel Veillardd076a202002-11-20 13:28:31 +00001201 for (i = 0;i < len;) {
1202 int cur;
1203 int l;
1204
1205 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1206 if (!IS_CHAR(cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001207 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd076a202002-11-20 13:28:31 +00001208 "XInclude: %s contains invalid char %d\n", URL, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001209 } else {
Daniel Veillardd076a202002-11-20 13:28:31 +00001210 xmlNodeAddContentLen(node, &content[i], l);
Owen Taylor3473f882001-02-23 17:55:21 +00001211 }
Daniel Veillardd076a202002-11-20 13:28:31 +00001212 i += l;
Owen Taylor3473f882001-02-23 17:55:21 +00001213 }
1214 xmlBufferShrink(buf->buffer, len);
1215 }
1216 xmlFreeParserInputBuffer(buf);
1217 xmlXIncludeAddTxt(ctxt, node, URL);
1218
1219loaded:
1220 /*
1221 * Add the element as the replacement copy.
1222 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001223 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001224 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001225 return(0);
1226}
1227
1228/**
1229 * xmlXIncludeLoadFallback:
1230 * @ctxt: the XInclude context
1231 * @fallback: the fallback node
1232 * @nr: the xinclude node number
1233 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001234 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001235 * in the XInclude context
1236 *
1237 * Returns 0 in case of success, -1 in case of failure
1238 */
1239static int
1240xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1241 if ((fallback == NULL) || (ctxt == NULL))
1242 return(-1);
1243
Daniel Veillard06503452002-12-13 10:42:08 +00001244 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001245 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001246}
1247
1248/************************************************************************
1249 * *
1250 * XInclude Processing *
1251 * *
1252 ************************************************************************/
1253
1254/**
1255 * xmlXIncludePreProcessNode:
1256 * @ctxt: an XInclude context
1257 * @node: an XInclude node
1258 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001259 * Implement the XInclude preprocessing, currently just adding the element
1260 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001261 *
1262 * Returns the result list or NULL in case of error
1263 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001264static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001265xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1266 xmlXIncludeAddNode(ctxt, node);
1267 return(0);
1268}
1269
Daniel Veillard118aed72002-09-24 14:13:13 +00001270#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00001271/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001272 * xmlXIncludePreloadNode:
1273 * @ctxt: an XInclude context
1274 * @nr: the node number
1275 *
1276 * Do some precomputations and preload shared documents
1277 *
1278 * Returns 0 if substitution succeeded, -1 if some processing failed
1279 */
1280static int
1281xmlXIncludePreloadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1282 xmlNodePtr cur;
1283 xmlChar *href;
1284 xmlChar *parse;
1285 xmlChar *base;
1286 xmlChar *URI;
1287 int xml = 1; /* default Issue 64 */
1288 xmlURIPtr uri;
1289 xmlChar *URL;
1290 xmlChar *fragment = NULL;
1291 int i;
1292
1293
1294 if (ctxt == NULL)
1295 return(-1);
1296 if ((nr < 0) || (nr >= ctxt->incNr))
1297 return(-1);
1298 cur = ctxt->incTab[nr]->ref;
1299 if (cur == NULL)
1300 return(-1);
1301
1302 /*
1303 * read the attributes
1304 */
1305 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1306 if (href == NULL) {
1307 href = xmlGetProp(cur, XINCLUDE_HREF);
1308 if (href == NULL) {
1309 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1310 return(-1);
1311 }
1312 }
1313 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1314 if (parse == NULL) {
1315 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1316 }
1317 if (parse != NULL) {
1318 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1319 xml = 1;
1320 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1321 xml = 0;
1322 else {
1323 xmlGenericError(xmlGenericErrorContext,
1324 "XInclude: invalid value %s for %s\n",
1325 parse, XINCLUDE_PARSE);
1326 if (href != NULL)
1327 xmlFree(href);
1328 if (parse != NULL)
1329 xmlFree(parse);
1330 return(-1);
1331 }
1332 }
1333
1334 /*
1335 * compute the URI
1336 */
1337 base = xmlNodeGetBase(ctxt->doc, cur);
1338 if (base == NULL) {
1339 URI = xmlBuildURI(href, ctxt->doc->URL);
1340 } else {
1341 URI = xmlBuildURI(href, base);
1342 }
1343 if (URI == NULL) {
1344 xmlChar *escbase;
1345 xmlChar *eschref;
1346 /*
1347 * Some escaping may be needed
1348 */
1349 escbase = xmlURIEscape(base);
1350 eschref = xmlURIEscape(href);
1351 URI = xmlBuildURI(eschref, escbase);
1352 if (escbase != NULL)
1353 xmlFree(escbase);
1354 if (eschref != NULL)
1355 xmlFree(eschref);
1356 }
1357 if (parse != NULL)
1358 xmlFree(parse);
1359 if (href != NULL)
1360 xmlFree(href);
1361 if (base != NULL)
1362 xmlFree(base);
1363 if (URI == NULL) {
1364 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1365 return(-1);
1366 }
1367
1368 /*
1369 * Check the URL and remove any fragment identifier
1370 */
1371 uri = xmlParseURI((const char *)URI);
1372 if (uri == NULL) {
1373 xmlGenericError(xmlGenericErrorContext,
1374 "XInclude: invalid value URI %s\n", URI);
1375 xmlFree(URI);
1376 return(-1);
1377 }
1378 if (uri->fragment != NULL) {
1379 fragment = (xmlChar *) uri->fragment;
1380 uri->fragment = NULL;
1381 }
1382 URL = xmlSaveUri(uri);
1383 xmlFreeURI(uri);
1384 if (URL == NULL) {
1385 xmlGenericError(xmlGenericErrorContext,
1386 "XInclude: invalid value URI %s\n", URI);
1387 if (fragment != NULL)
1388 xmlFree(fragment);
1389 xmlFree(URI);
1390 return(-1);
1391 }
1392 xmlFree(URI);
1393 if (fragment != NULL)
1394 xmlFree(fragment);
1395
1396 for (i = 0; i < nr; i++) {
1397 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1398#ifdef DEBUG_XINCLUDE
1399 printf("Incrementing count for %d : %s\n", i, ctxt->incTab[i]->URI);
1400#endif
1401 ctxt->incTab[i]->count++;
1402 break;
1403 }
1404 }
1405 xmlFree(URL);
1406 return(0);
1407}
Daniel Veillard118aed72002-09-24 14:13:13 +00001408#endif
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001409
1410/**
Owen Taylor3473f882001-02-23 17:55:21 +00001411 * xmlXIncludeLoadNode:
1412 * @ctxt: an XInclude context
1413 * @nr: the node number
1414 *
1415 * Find and load the infoset replacement for the given node.
1416 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001417 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001418 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001419static int
Owen Taylor3473f882001-02-23 17:55:21 +00001420xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1421 xmlNodePtr cur;
1422 xmlChar *href;
1423 xmlChar *parse;
1424 xmlChar *base;
1425 xmlChar *URI;
1426 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001427 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001428
1429 if (ctxt == NULL)
1430 return(-1);
1431 if ((nr < 0) || (nr >= ctxt->incNr))
1432 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001433 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001434 if (cur == NULL)
1435 return(-1);
1436
Owen Taylor3473f882001-02-23 17:55:21 +00001437 /*
1438 * read the attributes
1439 */
1440 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1441 if (href == NULL) {
1442 href = xmlGetProp(cur, XINCLUDE_HREF);
1443 if (href == NULL) {
1444 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1445 return(-1);
1446 }
1447 }
1448 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1449 if (parse == NULL) {
1450 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1451 }
1452 if (parse != NULL) {
1453 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1454 xml = 1;
1455 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1456 xml = 0;
1457 else {
1458 xmlGenericError(xmlGenericErrorContext,
1459 "XInclude: invalid value %s for %s\n",
1460 parse, XINCLUDE_PARSE);
1461 if (href != NULL)
1462 xmlFree(href);
1463 if (parse != NULL)
1464 xmlFree(parse);
1465 return(-1);
1466 }
1467 }
1468
1469 /*
1470 * compute the URI
1471 */
1472 base = xmlNodeGetBase(ctxt->doc, cur);
1473 if (base == NULL) {
1474 URI = xmlBuildURI(href, ctxt->doc->URL);
1475 } else {
1476 URI = xmlBuildURI(href, base);
1477 }
1478 if (URI == NULL) {
1479 xmlChar *escbase;
1480 xmlChar *eschref;
1481 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001482 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001483 */
1484 escbase = xmlURIEscape(base);
1485 eschref = xmlURIEscape(href);
1486 URI = xmlBuildURI(eschref, escbase);
1487 if (escbase != NULL)
1488 xmlFree(escbase);
1489 if (eschref != NULL)
1490 xmlFree(eschref);
1491 }
1492 if (URI == NULL) {
1493 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1494 if (parse != NULL)
1495 xmlFree(parse);
1496 if (href != NULL)
1497 xmlFree(href);
1498 if (base != NULL)
1499 xmlFree(base);
1500 return(-1);
1501 }
1502#ifdef DEBUG_XINCLUDE
1503 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1504 xml ? "xml": "text");
1505 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1506#endif
1507
1508 /*
1509 * Cleanup
1510 */
1511 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001512 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001513 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1514 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001515 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1516 }
1517 if (ret < 0) {
1518 xmlNodePtr children;
1519
1520 /*
1521 * Time to try a fallback if availble
1522 */
1523#ifdef DEBUG_XINCLUDE
1524 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1525#endif
1526 children = cur->children;
1527 while (children != NULL) {
1528 if ((children->type == XML_ELEMENT_NODE) &&
1529 (children->ns != NULL) &&
1530 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1531 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1532 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1533 if (ret == 0)
1534 break;
1535 }
1536 children = children->next;
1537 }
1538 }
1539 if (ret < 0) {
1540 xmlGenericError(xmlGenericErrorContext,
1541 "XInclude: could not load %s, and no fallback was found\n",
1542 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001543 }
1544
1545 /*
1546 * Cleanup
1547 */
1548 if (URI != NULL)
1549 xmlFree(URI);
1550 if (parse != NULL)
1551 xmlFree(parse);
1552 if (href != NULL)
1553 xmlFree(href);
1554 if (base != NULL)
1555 xmlFree(base);
1556 return(0);
1557}
1558
1559/**
1560 * xmlXIncludeIncludeNode:
1561 * @ctxt: an XInclude context
1562 * @nr: the node number
1563 *
1564 * Inplement the infoset replacement for the given node
1565 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001566 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001567 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001568static int
Owen Taylor3473f882001-02-23 17:55:21 +00001569xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1570 xmlNodePtr cur, end, list;
1571
1572 if (ctxt == NULL)
1573 return(-1);
1574 if ((nr < 0) || (nr >= ctxt->incNr))
1575 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001576 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001577 if (cur == NULL)
1578 return(-1);
1579
1580 /*
1581 * Change the current node as an XInclude start one, and add an
1582 * entity end one
1583 */
1584 cur->type = XML_XINCLUDE_START;
1585 end = xmlNewNode(cur->ns, cur->name);
1586 if (end == NULL) {
1587 xmlGenericError(xmlGenericErrorContext,
1588 "XInclude: failed to build node\n");
1589 return(-1);
1590 }
1591 end->type = XML_XINCLUDE_END;
1592 xmlAddNextSibling(cur, end);
1593
1594 /*
1595 * Add the list of nodes
1596 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001597 list = ctxt->incTab[nr]->inc;
1598 ctxt->incTab[nr]->inc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001599 while (list != NULL) {
1600 cur = list;
1601 list = list->next;
1602
1603 xmlAddPrevSibling(end, cur);
1604 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001605
1606
Owen Taylor3473f882001-02-23 17:55:21 +00001607 return(0);
1608}
1609
1610/**
1611 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +00001612 * @node: an XInclude node
1613 *
1614 * test if the node is an XInclude node
1615 *
1616 * Returns 1 true, 0 otherwise
1617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001618static int
1619xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001620 if (node == NULL)
1621 return(0);
1622 if (node->ns == NULL)
1623 return(0);
1624 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
1625 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
1626 return(0);
1627}
1628
1629/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001630 * xmlXIncludeDoProcess:
1631 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +00001632 * @doc: an XML document
1633 *
1634 * Implement the XInclude substitution on the XML document @doc
1635 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001636 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001637 * or the number of substitutions done.
1638 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001639static int
1640xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001641 xmlNodePtr cur;
1642 int ret = 0;
1643 int i;
1644
1645 if (doc == NULL)
1646 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001647 if (ctxt == NULL)
1648 return(-1);
1649
1650 /*
1651 * First phase: lookup the elements in the document
1652 */
1653 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001654 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001655 xmlXIncludePreProcessNode(ctxt, cur);
1656 while (cur != NULL) {
1657 /* TODO: need to work on entities -> stack */
1658 if ((cur->children != NULL) &&
1659 (cur->children->type != XML_ENTITY_DECL)) {
1660 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001661 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001662 xmlXIncludePreProcessNode(ctxt, cur);
1663 } else if (cur->next != NULL) {
1664 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001665 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001666 xmlXIncludePreProcessNode(ctxt, cur);
1667 } else {
1668 do {
1669 cur = cur->parent;
1670 if (cur == NULL) break; /* do */
1671 if (cur->next != NULL) {
1672 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001673 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001674 xmlXIncludePreProcessNode(ctxt, cur);
1675 break; /* do */
1676 }
1677 } while (cur != NULL);
1678 }
1679 }
1680
1681 /*
1682 * Second Phase : collect the infosets fragments
1683 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001684 /*
1685 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
1686 xmlXIncludePreloadNode(ctxt, i);
1687 }
1688 */
1689 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001690 xmlXIncludeLoadNode(ctxt, i);
1691 }
1692
1693 /*
1694 * Third phase: extend the original document infoset.
1695 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001696 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001697 xmlXIncludeIncludeNode(ctxt, i);
1698 }
1699
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001700 return(ret);
1701}
1702
1703/**
1704 * xmlXIncludeProcess:
1705 * @doc: an XML document
1706 *
1707 * Implement the XInclude substitution on the XML document @doc
1708 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001709 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001710 * or the number of substitutions done.
1711 */
1712int
1713xmlXIncludeProcess(xmlDocPtr doc) {
1714 xmlXIncludeCtxtPtr ctxt;
1715 int ret = 0;
1716
1717 if (doc == NULL)
1718 return(-1);
1719 ctxt = xmlXIncludeNewContext(doc);
1720 if (ctxt == NULL)
1721 return(-1);
1722 ret = xmlXIncludeDoProcess(ctxt, doc);
1723
Owen Taylor3473f882001-02-23 17:55:21 +00001724 xmlXIncludeFreeContext(ctxt);
1725 return(ret);
1726}
1727
1728#else /* !LIBXML_XINCLUDE_ENABLED */
1729#endif