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