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