blob: 965f4b66b1f6a75f2c82634b5bd4ff1aab0d0d2b [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xinclude.c : Code to implement XInclude processing
3 *
4 * World Wide Web Consortium Working Draft 26 October 2000
5 * http://www.w3.org/TR/2000/WD-xinclude-20001026
6 *
7 * See Copyright for the status of this software.
8 *
9 * Daniel.Veillard@w3.org
10 */
11
12/*
13 * TODO: compute XPointers nodesets
14 */
15
Bjorn Reese70a9da52001-04-21 16:57:29 +000016#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000017
Owen Taylor3473f882001-02-23 17:55:21 +000018#include <string.h>
19#include <libxml/xmlmemory.h>
20#include <libxml/tree.h>
21#include <libxml/parser.h>
22#include <libxml/uri.h>
23#include <libxml/xpointer.h>
24#include <libxml/parserInternals.h>
25#ifdef LIBXML_DEBUG_ENABLED
26#include <libxml/debugXML.h>
27#endif
28#include <libxml/xmlerror.h>
29
30#ifdef LIBXML_XINCLUDE_ENABLED
31#include <libxml/xinclude.h>
32
33#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/1999/XML/xinclude"
34#define XINCLUDE_NODE (const xmlChar *) "include"
35#define XINCLUDE_HREF (const xmlChar *) "href"
36#define XINCLUDE_PARSE (const xmlChar *) "parse"
37#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
38#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
39
40/* #define DEBUG_XINCLUDE */
41
42/************************************************************************
43 * *
44 * XInclude contexts handling *
45 * *
46 ************************************************************************/
47
48/*
49 * An XInclude context
50 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000051typedef xmlChar *xmlURL;
Owen Taylor3473f882001-02-23 17:55:21 +000052typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
53typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
54struct _xmlXIncludeCtxt {
55 xmlDocPtr doc; /* the source document */
56 int incNr; /* number of includes */
57 int incMax; /* size of includes tab */
58 xmlNodePtr *incTab; /* array of include nodes */
59 xmlNodePtr *repTab; /* array of replacement node lists */
60 int docNr; /* number of parsed documents */
61 int docMax; /* size of parsed documents tab */
62 xmlDocPtr *docTab; /* array of parsed documents */
Daniel Veillardedac3c92001-02-26 01:36:19 +000063 xmlURL *urlTab; /* array of parsed documents URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000064 int txtNr; /* number of unparsed documents */
65 int txtMax; /* size of unparsed documents tab */
66 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000067 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000068};
69
70/**
71 * xmlXIncludeAddNode:
72 * @ctxt: the XInclude context
73 * @node: the new node
74 *
75 * Add a new node to process to an XInclude context
76 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000077static void
Owen Taylor3473f882001-02-23 17:55:21 +000078xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
79 if (ctxt->incMax == 0) {
80 ctxt->incMax = 4;
81 ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
82 sizeof(ctxt->incTab[0]));
83 if (ctxt->incTab == NULL) {
84 xmlGenericError(xmlGenericErrorContext,
85 "malloc failed !\n");
86 return;
87 }
88 ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
89 sizeof(ctxt->repTab[0]));
90 if (ctxt->repTab == NULL) {
91 xmlGenericError(xmlGenericErrorContext,
92 "malloc failed !\n");
93 return;
94 }
95 }
96 if (ctxt->incNr >= ctxt->incMax) {
97 ctxt->incMax *= 2;
98 ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
99 ctxt->incMax * sizeof(ctxt->incTab[0]));
100 if (ctxt->incTab == NULL) {
101 xmlGenericError(xmlGenericErrorContext,
102 "realloc failed !\n");
103 return;
104 }
105 ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
106 ctxt->incMax * sizeof(ctxt->repTab[0]));
107 if (ctxt->repTab == NULL) {
108 xmlGenericError(xmlGenericErrorContext,
109 "realloc failed !\n");
110 return;
111 }
112 }
113 ctxt->incTab[ctxt->incNr] = node;
114 ctxt->repTab[ctxt->incNr] = NULL;
115 ctxt->incNr++;
116}
117
118/**
119 * xmlXIncludeAddDoc:
120 * @ctxt: the XInclude context
121 * @doc: the new document
122 * @url: the associated URL
123 *
124 * Add a new document to the list
125 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000126static void
Daniel Veillardedac3c92001-02-26 01:36:19 +0000127xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url) {
Owen Taylor3473f882001-02-23 17:55:21 +0000128 if (ctxt->docMax == 0) {
129 ctxt->docMax = 4;
130 ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
131 sizeof(ctxt->docTab[0]));
132 if (ctxt->docTab == NULL) {
133 xmlGenericError(xmlGenericErrorContext,
134 "malloc failed !\n");
135 return;
136 }
Daniel Veillardedac3c92001-02-26 01:36:19 +0000137 ctxt->urlTab = (xmlURL *) xmlMalloc(ctxt->docMax *
Owen Taylor3473f882001-02-23 17:55:21 +0000138 sizeof(ctxt->urlTab[0]));
139 if (ctxt->urlTab == NULL) {
140 xmlGenericError(xmlGenericErrorContext,
141 "malloc failed !\n");
142 return;
143 }
144 }
145 if (ctxt->docNr >= ctxt->docMax) {
146 ctxt->docMax *= 2;
147 ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
148 ctxt->docMax * sizeof(ctxt->docTab[0]));
149 if (ctxt->docTab == NULL) {
150 xmlGenericError(xmlGenericErrorContext,
151 "realloc failed !\n");
152 return;
153 }
Daniel Veillardedac3c92001-02-26 01:36:19 +0000154 ctxt->urlTab = (xmlURL *) xmlRealloc(ctxt->urlTab,
Owen Taylor3473f882001-02-23 17:55:21 +0000155 ctxt->docMax * sizeof(ctxt->urlTab[0]));
156 if (ctxt->urlTab == NULL) {
157 xmlGenericError(xmlGenericErrorContext,
158 "realloc failed !\n");
159 return;
160 }
161 }
162 ctxt->docTab[ctxt->docNr] = doc;
163 ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
164 ctxt->docNr++;
165}
166
167/**
168 * xmlXIncludeAddTxt:
169 * @ctxt: the XInclude context
170 * @txt: the new text node
171 * @url: the associated URL
172 *
173 * Add a new txtument to the list
174 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000175static void
Daniel Veillardedac3c92001-02-26 01:36:19 +0000176xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Owen Taylor3473f882001-02-23 17:55:21 +0000177 if (ctxt->txtMax == 0) {
178 ctxt->txtMax = 4;
179 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
180 sizeof(ctxt->txtTab[0]));
181 if (ctxt->txtTab == NULL) {
182 xmlGenericError(xmlGenericErrorContext,
183 "malloc failed !\n");
184 return;
185 }
Daniel Veillardedac3c92001-02-26 01:36:19 +0000186 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
Owen Taylor3473f882001-02-23 17:55:21 +0000187 sizeof(ctxt->txturlTab[0]));
188 if (ctxt->txturlTab == NULL) {
189 xmlGenericError(xmlGenericErrorContext,
190 "malloc failed !\n");
191 return;
192 }
193 }
194 if (ctxt->txtNr >= ctxt->txtMax) {
195 ctxt->txtMax *= 2;
196 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
197 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
198 if (ctxt->txtTab == NULL) {
199 xmlGenericError(xmlGenericErrorContext,
200 "realloc failed !\n");
201 return;
202 }
Daniel Veillardedac3c92001-02-26 01:36:19 +0000203 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Owen Taylor3473f882001-02-23 17:55:21 +0000204 ctxt->txtMax * sizeof(ctxt->urlTab[0]));
205 if (ctxt->txturlTab == NULL) {
206 xmlGenericError(xmlGenericErrorContext,
207 "realloc failed !\n");
208 return;
209 }
210 }
211 ctxt->txtTab[ctxt->txtNr] = txt;
212 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
213 ctxt->txtNr++;
214}
215
216/**
217 * xmlXIncludeNewContext:
218 * @doc: an XML Document
219 *
220 * Creates a new XInclude context
221 *
222 * Returns the new set
223 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000224static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000225xmlXIncludeNewContext(xmlDocPtr doc) {
226 xmlXIncludeCtxtPtr ret;
227
228 if (doc == NULL)
229 return(NULL);
230 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
231 if (ret == NULL)
232 return(NULL);
233 memset(ret, 0, sizeof(xmlXIncludeCtxt));
234 ret->doc = doc;
235 ret->incNr = 0;
236 ret->incMax = 0;
237 ret->incTab = NULL;
238 ret->repTab = NULL;
239 ret->docNr = 0;
240 ret->docMax = 0;
241 ret->docTab = NULL;
242 ret->urlTab = NULL;
243 return(ret);
244}
245
246/**
247 * xmlXIncludeFreeContext:
248 * @ctxt: the XInclude context
249 *
250 * Free an XInclude context
251 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000252static void
Owen Taylor3473f882001-02-23 17:55:21 +0000253xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
254 int i;
255
256 if (ctxt == NULL)
257 return;
258 for (i = 0;i < ctxt->docNr;i++) {
259 xmlFreeDoc(ctxt->docTab[i]);
260 if (ctxt->urlTab[i] != NULL)
261 xmlFree(ctxt->urlTab[i]);
262 }
263 for (i = 0;i < ctxt->txtNr;i++) {
264 if (ctxt->txturlTab[i] != NULL)
265 xmlFree(ctxt->txturlTab[i]);
266 }
267 if (ctxt->incTab != NULL)
268 xmlFree(ctxt->incTab);
269 if (ctxt->repTab != NULL)
270 xmlFree(ctxt->repTab);
271 if (ctxt->urlTab != NULL)
272 xmlFree(ctxt->urlTab);
273 if (ctxt->docTab != NULL)
274 xmlFree(ctxt->docTab);
275 if (ctxt->txtTab != NULL)
276 xmlFree(ctxt->txtTab);
277 if (ctxt->txturlTab != NULL)
278 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000279 xmlFree(ctxt);
280}
281
282/************************************************************************
283 * *
284 * XInclude I/O handling *
285 * *
286 ************************************************************************/
287
288/**
289 * xmlXIncludeLoadDoc:
290 * @ctxt: the XInclude context
291 * @url: the associated URL
292 * @nr: the xinclude node number
293 *
294 * Load the document, and store the result in the XInclude context
295 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000296static void
Owen Taylor3473f882001-02-23 17:55:21 +0000297xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
298 xmlDocPtr doc;
299 xmlURIPtr uri;
300 xmlChar *URL;
301 xmlChar *fragment = NULL;
302 int i;
303 /*
304 * Check the URL and remove any fragment identifier
305 */
306 uri = xmlParseURI((const char *)url);
307 if (uri == NULL) {
308 xmlGenericError(xmlGenericErrorContext,
309 "XInclude: invalid value URI %s\n", url);
310 return;
311 }
312 if (uri->fragment != NULL) {
313 fragment = (xmlChar *) uri->fragment;
314 uri->fragment = NULL;
315 }
316 URL = xmlSaveUri(uri);
317 xmlFreeURI(uri);
318 if (URL == NULL) {
319 xmlGenericError(xmlGenericErrorContext,
320 "XInclude: invalid value URI %s\n", url);
321 if (fragment != NULL)
322 xmlFree(fragment);
323 return;
324 }
325
326 /*
327 * Handling of references to the local document are done
328 * directly through ctxt->doc.
329 */
330 if ((URL[0] == 0) || (URL[0] == '#')) {
331 doc = NULL;
332 goto loaded;
333 }
334
335 /*
336 * Prevent reloading twice the document.
337 */
338 for (i = 0; i < ctxt->docNr; i++) {
339 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
340 doc = ctxt->docTab[i];
341 goto loaded;
342 }
343 }
344 /*
345 * Load it.
346 */
347 doc = xmlParseFile((const char *)URL);
348 if (doc == NULL) {
349 xmlGenericError(xmlGenericErrorContext,
350 "XInclude: could not load %s\n", URL);
351 xmlFree(URL);
352 if (fragment != NULL)
353 xmlFree(fragment);
354 return;
355 }
356 xmlXIncludeAddDoc(ctxt, doc, URL);
357
358loaded:
359 if (fragment == NULL) {
360 /*
361 * Add the top children list as the replacement copy.
362 * ISSUE: seems we should scrap DTD info from the copied list.
363 */
364 if (doc == NULL)
365 ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
366 else
367 ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
368 } else {
369 /*
370 * Computes the XPointer expression and make a copy used
371 * as the replacement copy.
372 */
373 xmlXPathObjectPtr xptr;
374 xmlXPathContextPtr xptrctxt;
375
376 if (doc == NULL) {
377 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
378 } else {
379 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
380 }
381 if (xptrctxt == NULL) {
382 xmlGenericError(xmlGenericErrorContext,
383 "XInclude: could create XPointer context\n");
384 xmlFree(URL);
385 xmlFree(fragment);
386 return;
387 }
388 xptr = xmlXPtrEval(fragment, xptrctxt);
389 if (xptr == NULL) {
390 xmlGenericError(xmlGenericErrorContext,
391 "XInclude: XPointer evaluation failed: #%s\n",
392 fragment);
393 xmlXPathFreeContext(xptrctxt);
394 xmlFree(URL);
395 xmlFree(fragment);
396 return;
397 }
398 ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
399 xmlXPathFreeObject(xptr);
400 xmlXPathFreeContext(xptrctxt);
401 xmlFree(fragment);
402 }
403 xmlFree(URL);
404}
405
406/**
407 * xmlXIncludeLoadTxt:
408 * @ctxt: the XInclude context
409 * @url: the associated URL
410 * @nr: the xinclude node number
411 *
412 * Load the content, and store the result in the XInclude context
413 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000414static void
Owen Taylor3473f882001-02-23 17:55:21 +0000415xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
416 xmlParserInputBufferPtr buf;
417 xmlNodePtr node;
418 xmlURIPtr uri;
419 xmlChar *URL;
420 int i;
421 /*
422 * Check the URL and remove any fragment identifier
423 */
424 uri = xmlParseURI((const char *)url);
425 if (uri == NULL) {
426 xmlGenericError(xmlGenericErrorContext,
427 "XInclude: invalid value URI %s\n", url);
428 return;
429 }
430 if (uri->fragment != NULL) {
431 xmlGenericError(xmlGenericErrorContext,
432 "XInclude: fragment identifier forbidden for text: %s\n",
433 uri->fragment);
434 xmlFreeURI(uri);
435 return;
436 }
437 URL = xmlSaveUri(uri);
438 xmlFreeURI(uri);
439 if (URL == NULL) {
440 xmlGenericError(xmlGenericErrorContext,
441 "XInclude: invalid value URI %s\n", url);
442 return;
443 }
444
445 /*
446 * Handling of references to the local document are done
447 * directly through ctxt->doc.
448 */
449 if (URL[0] == 0) {
450 xmlGenericError(xmlGenericErrorContext,
451 "XInclude: text serialization of document not available\n");
452 xmlFree(URL);
453 return;
454 }
455
456 /*
457 * Prevent reloading twice the document.
458 */
459 for (i = 0; i < ctxt->txtNr; i++) {
460 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
461 node = xmlCopyNode(ctxt->txtTab[i], 1);
462 goto loaded;
463 }
464 }
465 /*
466 * Load it.
467 * Issue 62: how to detect the encoding
468 */
469 buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
470 if (buf == NULL) {
471 xmlGenericError(xmlGenericErrorContext,
472 "XInclude: could not load %s\n", URL);
473 xmlFree(URL);
474 return;
475 }
476 node = xmlNewText(NULL);
477
478 /*
479 * Scan all chars from the resource and add the to the node
480 */
481 while (xmlParserInputBufferRead(buf, 128) > 0) {
482 int len;
483 const xmlChar *content;
484
485 content = xmlBufferContent(buf->buffer);
486 len = xmlBufferLength(buf->buffer);
487 for (i = 0;i < len; i++) {
488 /*
489 * TODO: if the encoding issue is solved, scan UTF8 chars instead
490 */
491 if (!IS_CHAR(content[i])) {
492 xmlGenericError(xmlGenericErrorContext,
493 "XInclude: %s contains invalid char %d\n", URL, content[i]);
494 } else {
495 xmlNodeAddContentLen(node, &content[i], 1);
496 }
497 }
498 xmlBufferShrink(buf->buffer, len);
499 }
500 xmlFreeParserInputBuffer(buf);
501 xmlXIncludeAddTxt(ctxt, node, URL);
502
503loaded:
504 /*
505 * Add the element as the replacement copy.
506 */
507 ctxt->repTab[nr] = node;
508 xmlFree(URL);
509}
510
511/************************************************************************
512 * *
513 * XInclude Processing *
514 * *
515 ************************************************************************/
516
517/**
518 * xmlXIncludePreProcessNode:
519 * @ctxt: an XInclude context
520 * @node: an XInclude node
521 *
522 * Implement the infoset replacement lookup on the XML element @node
523 *
524 * Returns the result list or NULL in case of error
525 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000526static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +0000527xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
528 xmlXIncludeAddNode(ctxt, node);
529 return(0);
530}
531
532/**
533 * xmlXIncludeLoadNode:
534 * @ctxt: an XInclude context
535 * @nr: the node number
536 *
537 * Find and load the infoset replacement for the given node.
538 *
539 * Returns 0 if substition succeeded, -1 if some processing failed
540 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000541static int
Owen Taylor3473f882001-02-23 17:55:21 +0000542xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
543 xmlNodePtr cur;
544 xmlChar *href;
545 xmlChar *parse;
546 xmlChar *base;
547 xmlChar *URI;
548 int xml = 1; /* default Issue 64 */
549
550 if (ctxt == NULL)
551 return(-1);
552 if ((nr < 0) || (nr >= ctxt->incNr))
553 return(-1);
554 cur = ctxt->incTab[nr];
555 if (cur == NULL)
556 return(-1);
557
558#ifdef DEBUG_XINCLUDE
559 xmlDebugDumpNode(stdout, cur, 0);
560#endif
561 /*
562 * read the attributes
563 */
564 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
565 if (href == NULL) {
566 href = xmlGetProp(cur, XINCLUDE_HREF);
567 if (href == NULL) {
568 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
569 return(-1);
570 }
571 }
572 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
573 if (parse == NULL) {
574 parse = xmlGetProp(cur, XINCLUDE_PARSE);
575 }
576 if (parse != NULL) {
577 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
578 xml = 1;
579 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
580 xml = 0;
581 else {
582 xmlGenericError(xmlGenericErrorContext,
583 "XInclude: invalid value %s for %s\n",
584 parse, XINCLUDE_PARSE);
585 if (href != NULL)
586 xmlFree(href);
587 if (parse != NULL)
588 xmlFree(parse);
589 return(-1);
590 }
591 }
592
593 /*
594 * compute the URI
595 */
596 base = xmlNodeGetBase(ctxt->doc, cur);
597 if (base == NULL) {
598 URI = xmlBuildURI(href, ctxt->doc->URL);
599 } else {
600 URI = xmlBuildURI(href, base);
601 }
602 if (URI == NULL) {
603 xmlChar *escbase;
604 xmlChar *eschref;
605 /*
606 * Some escapeing may be needed
607 */
608 escbase = xmlURIEscape(base);
609 eschref = xmlURIEscape(href);
610 URI = xmlBuildURI(eschref, escbase);
611 if (escbase != NULL)
612 xmlFree(escbase);
613 if (eschref != NULL)
614 xmlFree(eschref);
615 }
616 if (URI == NULL) {
617 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
618 if (parse != NULL)
619 xmlFree(parse);
620 if (href != NULL)
621 xmlFree(href);
622 if (base != NULL)
623 xmlFree(base);
624 return(-1);
625 }
626#ifdef DEBUG_XINCLUDE
627 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
628 xml ? "xml": "text");
629 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
630#endif
631
632 /*
633 * Cleanup
634 */
635 if (xml) {
636 xmlXIncludeLoadDoc(ctxt, URI, nr);
637 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
638 } else {
639 xmlXIncludeLoadTxt(ctxt, URI, nr);
640 }
641
642 /*
643 * Cleanup
644 */
645 if (URI != NULL)
646 xmlFree(URI);
647 if (parse != NULL)
648 xmlFree(parse);
649 if (href != NULL)
650 xmlFree(href);
651 if (base != NULL)
652 xmlFree(base);
653 return(0);
654}
655
656/**
657 * xmlXIncludeIncludeNode:
658 * @ctxt: an XInclude context
659 * @nr: the node number
660 *
661 * Inplement the infoset replacement for the given node
662 *
663 * Returns 0 if substition succeeded, -1 if some processing failed
664 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000665static int
Owen Taylor3473f882001-02-23 17:55:21 +0000666xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
667 xmlNodePtr cur, end, list;
668
669 if (ctxt == NULL)
670 return(-1);
671 if ((nr < 0) || (nr >= ctxt->incNr))
672 return(-1);
673 cur = ctxt->incTab[nr];
674 if (cur == NULL)
675 return(-1);
676
677 /*
678 * Change the current node as an XInclude start one, and add an
679 * entity end one
680 */
681 cur->type = XML_XINCLUDE_START;
682 end = xmlNewNode(cur->ns, cur->name);
683 if (end == NULL) {
684 xmlGenericError(xmlGenericErrorContext,
685 "XInclude: failed to build node\n");
686 return(-1);
687 }
688 end->type = XML_XINCLUDE_END;
689 xmlAddNextSibling(cur, end);
690
691 /*
692 * Add the list of nodes
693 */
694 list = ctxt->repTab[nr];
695 ctxt->repTab[nr] = NULL;
696 while (list != NULL) {
697 cur = list;
698 list = list->next;
699
700 xmlAddPrevSibling(end, cur);
701 }
702 return(0);
703}
704
705/**
706 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +0000707 * @node: an XInclude node
708 *
709 * test if the node is an XInclude node
710 *
711 * Returns 1 true, 0 otherwise
712 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000713static int
714xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +0000715 if (node == NULL)
716 return(0);
717 if (node->ns == NULL)
718 return(0);
719 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
720 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
721 return(0);
722}
723
724/**
725 * xmlXIncludeProcess:
726 * @doc: an XML document
727 *
728 * Implement the XInclude substitution on the XML document @doc
729 *
730 * Returns 0 if no substition were done, -1 if some processing failed
731 * or the number of substitutions done.
732 */
733int
734xmlXIncludeProcess(xmlDocPtr doc) {
735 xmlXIncludeCtxtPtr ctxt;
736 xmlNodePtr cur;
737 int ret = 0;
738 int i;
739
740 if (doc == NULL)
741 return(-1);
742 ctxt = xmlXIncludeNewContext(doc);
743 if (ctxt == NULL)
744 return(-1);
745
746 /*
747 * First phase: lookup the elements in the document
748 */
749 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000750 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000751 xmlXIncludePreProcessNode(ctxt, cur);
752 while (cur != NULL) {
753 /* TODO: need to work on entities -> stack */
754 if ((cur->children != NULL) &&
755 (cur->children->type != XML_ENTITY_DECL)) {
756 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000757 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000758 xmlXIncludePreProcessNode(ctxt, cur);
759 } else if (cur->next != NULL) {
760 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000761 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000762 xmlXIncludePreProcessNode(ctxt, cur);
763 } else {
764 do {
765 cur = cur->parent;
766 if (cur == NULL) break; /* do */
767 if (cur->next != NULL) {
768 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000769 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000770 xmlXIncludePreProcessNode(ctxt, cur);
771 break; /* do */
772 }
773 } while (cur != NULL);
774 }
775 }
776
777 /*
778 * Second Phase : collect the infosets fragments
779 */
780 for (i = 0;i < ctxt->incNr; i++) {
781 xmlXIncludeLoadNode(ctxt, i);
782 }
783
784 /*
785 * Third phase: extend the original document infoset.
786 */
787 for (i = 0;i < ctxt->incNr; i++) {
788 xmlXIncludeIncludeNode(ctxt, i);
789 }
790
791 /*
792 * Cleanup
793 */
794 xmlXIncludeFreeContext(ctxt);
795 return(ret);
796}
797
798#else /* !LIBXML_XINCLUDE_ENABLED */
799#endif