blob: 0909d3eb75cec551a9e7d56dba5f3b62053a51aa [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.
Owen Taylor3473f882001-02-23 17:55:21 +0000410 */
411 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +0000412 {
413 /* Hopefully a DTD declaration won't be copied from
414 * the same document */
Owen Taylor3473f882001-02-23 17:55:21 +0000415 ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000416 } else {
417 /* DTD declarations can't be copied from included files */
418 xmlNodePtr node = doc->children;
419 while (node != NULL)
420 {
421 if (node->type == XML_DTD_NODE)
422 {
423 xmlUnlinkNode(node);
424 xmlFreeNode(node);
425 }
426 node = node->next;
427 }
Owen Taylor3473f882001-02-23 17:55:21 +0000428 ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000429 }
Owen Taylor3473f882001-02-23 17:55:21 +0000430 } else {
431 /*
432 * Computes the XPointer expression and make a copy used
433 * as the replacement copy.
434 */
435 xmlXPathObjectPtr xptr;
436 xmlXPathContextPtr xptrctxt;
437
438 if (doc == NULL) {
439 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
440 } else {
441 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
442 }
443 if (xptrctxt == NULL) {
444 xmlGenericError(xmlGenericErrorContext,
445 "XInclude: could create XPointer context\n");
446 xmlFree(URL);
447 xmlFree(fragment);
448 return;
449 }
450 xptr = xmlXPtrEval(fragment, xptrctxt);
451 if (xptr == NULL) {
452 xmlGenericError(xmlGenericErrorContext,
453 "XInclude: XPointer evaluation failed: #%s\n",
454 fragment);
455 xmlXPathFreeContext(xptrctxt);
456 xmlFree(URL);
457 xmlFree(fragment);
458 return;
459 }
460 ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
461 xmlXPathFreeObject(xptr);
462 xmlXPathFreeContext(xptrctxt);
463 xmlFree(fragment);
464 }
465 xmlFree(URL);
466}
467
468/**
469 * xmlXIncludeLoadTxt:
470 * @ctxt: the XInclude context
471 * @url: the associated URL
472 * @nr: the xinclude node number
473 *
474 * Load the content, and store the result in the XInclude context
475 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000476static void
Owen Taylor3473f882001-02-23 17:55:21 +0000477xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
478 xmlParserInputBufferPtr buf;
479 xmlNodePtr node;
480 xmlURIPtr uri;
481 xmlChar *URL;
482 int i;
483 /*
484 * Check the URL and remove any fragment identifier
485 */
486 uri = xmlParseURI((const char *)url);
487 if (uri == NULL) {
488 xmlGenericError(xmlGenericErrorContext,
489 "XInclude: invalid value URI %s\n", url);
490 return;
491 }
492 if (uri->fragment != NULL) {
493 xmlGenericError(xmlGenericErrorContext,
494 "XInclude: fragment identifier forbidden for text: %s\n",
495 uri->fragment);
496 xmlFreeURI(uri);
497 return;
498 }
499 URL = xmlSaveUri(uri);
500 xmlFreeURI(uri);
501 if (URL == NULL) {
502 xmlGenericError(xmlGenericErrorContext,
503 "XInclude: invalid value URI %s\n", url);
504 return;
505 }
506
507 /*
508 * Handling of references to the local document are done
509 * directly through ctxt->doc.
510 */
511 if (URL[0] == 0) {
512 xmlGenericError(xmlGenericErrorContext,
513 "XInclude: text serialization of document not available\n");
514 xmlFree(URL);
515 return;
516 }
517
518 /*
519 * Prevent reloading twice the document.
520 */
521 for (i = 0; i < ctxt->txtNr; i++) {
522 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
523 node = xmlCopyNode(ctxt->txtTab[i], 1);
524 goto loaded;
525 }
526 }
527 /*
528 * Load it.
529 * Issue 62: how to detect the encoding
530 */
531 buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
532 if (buf == NULL) {
533 xmlGenericError(xmlGenericErrorContext,
534 "XInclude: could not load %s\n", URL);
535 xmlFree(URL);
536 return;
537 }
538 node = xmlNewText(NULL);
539
540 /*
541 * Scan all chars from the resource and add the to the node
542 */
543 while (xmlParserInputBufferRead(buf, 128) > 0) {
544 int len;
545 const xmlChar *content;
546
547 content = xmlBufferContent(buf->buffer);
548 len = xmlBufferLength(buf->buffer);
549 for (i = 0;i < len; i++) {
550 /*
551 * TODO: if the encoding issue is solved, scan UTF8 chars instead
552 */
553 if (!IS_CHAR(content[i])) {
554 xmlGenericError(xmlGenericErrorContext,
555 "XInclude: %s contains invalid char %d\n", URL, content[i]);
556 } else {
557 xmlNodeAddContentLen(node, &content[i], 1);
558 }
559 }
560 xmlBufferShrink(buf->buffer, len);
561 }
562 xmlFreeParserInputBuffer(buf);
563 xmlXIncludeAddTxt(ctxt, node, URL);
564
565loaded:
566 /*
567 * Add the element as the replacement copy.
568 */
569 ctxt->repTab[nr] = node;
570 xmlFree(URL);
571}
572
573/************************************************************************
574 * *
575 * XInclude Processing *
576 * *
577 ************************************************************************/
578
579/**
580 * xmlXIncludePreProcessNode:
581 * @ctxt: an XInclude context
582 * @node: an XInclude node
583 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000584 * Implement the XInclude preprocessing, currently just adding the element
585 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +0000586 *
587 * Returns the result list or NULL in case of error
588 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000589static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +0000590xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
591 xmlXIncludeAddNode(ctxt, node);
592 return(0);
593}
594
595/**
596 * xmlXIncludeLoadNode:
597 * @ctxt: an XInclude context
598 * @nr: the node number
599 *
600 * Find and load the infoset replacement for the given node.
601 *
602 * Returns 0 if substition succeeded, -1 if some processing failed
603 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000604static int
Owen Taylor3473f882001-02-23 17:55:21 +0000605xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
606 xmlNodePtr cur;
607 xmlChar *href;
608 xmlChar *parse;
609 xmlChar *base;
610 xmlChar *URI;
611 int xml = 1; /* default Issue 64 */
612
613 if (ctxt == NULL)
614 return(-1);
615 if ((nr < 0) || (nr >= ctxt->incNr))
616 return(-1);
617 cur = ctxt->incTab[nr];
618 if (cur == NULL)
619 return(-1);
620
621#ifdef DEBUG_XINCLUDE
622 xmlDebugDumpNode(stdout, cur, 0);
623#endif
624 /*
625 * read the attributes
626 */
627 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
628 if (href == NULL) {
629 href = xmlGetProp(cur, XINCLUDE_HREF);
630 if (href == NULL) {
631 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
632 return(-1);
633 }
634 }
635 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
636 if (parse == NULL) {
637 parse = xmlGetProp(cur, XINCLUDE_PARSE);
638 }
639 if (parse != NULL) {
640 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
641 xml = 1;
642 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
643 xml = 0;
644 else {
645 xmlGenericError(xmlGenericErrorContext,
646 "XInclude: invalid value %s for %s\n",
647 parse, XINCLUDE_PARSE);
648 if (href != NULL)
649 xmlFree(href);
650 if (parse != NULL)
651 xmlFree(parse);
652 return(-1);
653 }
654 }
655
656 /*
657 * compute the URI
658 */
659 base = xmlNodeGetBase(ctxt->doc, cur);
660 if (base == NULL) {
661 URI = xmlBuildURI(href, ctxt->doc->URL);
662 } else {
663 URI = xmlBuildURI(href, base);
664 }
665 if (URI == NULL) {
666 xmlChar *escbase;
667 xmlChar *eschref;
668 /*
669 * Some escapeing may be needed
670 */
671 escbase = xmlURIEscape(base);
672 eschref = xmlURIEscape(href);
673 URI = xmlBuildURI(eschref, escbase);
674 if (escbase != NULL)
675 xmlFree(escbase);
676 if (eschref != NULL)
677 xmlFree(eschref);
678 }
679 if (URI == NULL) {
680 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
681 if (parse != NULL)
682 xmlFree(parse);
683 if (href != NULL)
684 xmlFree(href);
685 if (base != NULL)
686 xmlFree(base);
687 return(-1);
688 }
689#ifdef DEBUG_XINCLUDE
690 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
691 xml ? "xml": "text");
692 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
693#endif
694
695 /*
696 * Cleanup
697 */
698 if (xml) {
699 xmlXIncludeLoadDoc(ctxt, URI, nr);
700 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
701 } else {
702 xmlXIncludeLoadTxt(ctxt, URI, nr);
703 }
704
705 /*
706 * Cleanup
707 */
708 if (URI != NULL)
709 xmlFree(URI);
710 if (parse != NULL)
711 xmlFree(parse);
712 if (href != NULL)
713 xmlFree(href);
714 if (base != NULL)
715 xmlFree(base);
716 return(0);
717}
718
719/**
720 * xmlXIncludeIncludeNode:
721 * @ctxt: an XInclude context
722 * @nr: the node number
723 *
724 * Inplement the infoset replacement for the given node
725 *
726 * Returns 0 if substition succeeded, -1 if some processing failed
727 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000728static int
Owen Taylor3473f882001-02-23 17:55:21 +0000729xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
730 xmlNodePtr cur, end, list;
731
732 if (ctxt == NULL)
733 return(-1);
734 if ((nr < 0) || (nr >= ctxt->incNr))
735 return(-1);
736 cur = ctxt->incTab[nr];
737 if (cur == NULL)
738 return(-1);
739
740 /*
741 * Change the current node as an XInclude start one, and add an
742 * entity end one
743 */
744 cur->type = XML_XINCLUDE_START;
745 end = xmlNewNode(cur->ns, cur->name);
746 if (end == NULL) {
747 xmlGenericError(xmlGenericErrorContext,
748 "XInclude: failed to build node\n");
749 return(-1);
750 }
751 end->type = XML_XINCLUDE_END;
752 xmlAddNextSibling(cur, end);
753
754 /*
755 * Add the list of nodes
756 */
757 list = ctxt->repTab[nr];
758 ctxt->repTab[nr] = NULL;
759 while (list != NULL) {
760 cur = list;
761 list = list->next;
762
763 xmlAddPrevSibling(end, cur);
764 }
765 return(0);
766}
767
768/**
769 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +0000770 * @node: an XInclude node
771 *
772 * test if the node is an XInclude node
773 *
774 * Returns 1 true, 0 otherwise
775 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000776static int
777xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +0000778 if (node == NULL)
779 return(0);
780 if (node->ns == NULL)
781 return(0);
782 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
783 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
784 return(0);
785}
786
787/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000788 * xmlXIncludeDoProcess:
789 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +0000790 * @doc: an XML document
791 *
792 * Implement the XInclude substitution on the XML document @doc
793 *
794 * Returns 0 if no substition were done, -1 if some processing failed
795 * or the number of substitutions done.
796 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000797static int
798xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +0000799 xmlNodePtr cur;
800 int ret = 0;
801 int i;
802
803 if (doc == NULL)
804 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000805 if (ctxt == NULL)
806 return(-1);
807
808 /*
809 * First phase: lookup the elements in the document
810 */
811 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000812 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000813 xmlXIncludePreProcessNode(ctxt, cur);
814 while (cur != NULL) {
815 /* TODO: need to work on entities -> stack */
816 if ((cur->children != NULL) &&
817 (cur->children->type != XML_ENTITY_DECL)) {
818 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000819 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000820 xmlXIncludePreProcessNode(ctxt, cur);
821 } else if (cur->next != NULL) {
822 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000823 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000824 xmlXIncludePreProcessNode(ctxt, cur);
825 } else {
826 do {
827 cur = cur->parent;
828 if (cur == NULL) break; /* do */
829 if (cur->next != NULL) {
830 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000831 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000832 xmlXIncludePreProcessNode(ctxt, cur);
833 break; /* do */
834 }
835 } while (cur != NULL);
836 }
837 }
838
839 /*
840 * Second Phase : collect the infosets fragments
841 */
842 for (i = 0;i < ctxt->incNr; i++) {
843 xmlXIncludeLoadNode(ctxt, i);
844 }
845
846 /*
847 * Third phase: extend the original document infoset.
848 */
849 for (i = 0;i < ctxt->incNr; i++) {
850 xmlXIncludeIncludeNode(ctxt, i);
851 }
852
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000853 return(ret);
854}
855
856/**
857 * xmlXIncludeProcess:
858 * @doc: an XML document
859 *
860 * Implement the XInclude substitution on the XML document @doc
861 *
862 * Returns 0 if no substition were done, -1 if some processing failed
863 * or the number of substitutions done.
864 */
865int
866xmlXIncludeProcess(xmlDocPtr doc) {
867 xmlXIncludeCtxtPtr ctxt;
868 int ret = 0;
869
870 if (doc == NULL)
871 return(-1);
872 ctxt = xmlXIncludeNewContext(doc);
873 if (ctxt == NULL)
874 return(-1);
875 ret = xmlXIncludeDoProcess(ctxt, doc);
876
Owen Taylor3473f882001-02-23 17:55:21 +0000877 xmlXIncludeFreeContext(ctxt);
878 return(ret);
879}
880
881#else /* !LIBXML_XINCLUDE_ENABLED */
882#endif