blob: 813e3e66e58c84fa4d2b45409e9563adc1aea5db [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xinclude.c : Code to implement XInclude processing
3 *
Daniel Veillardbbd22452001-05-23 12:02:27 +00004 * World Wide Web Consortium W3C Last Call Working Draft 16 May 2001
5 * http://www.w3.org/TR/2001/WD-xinclude-20010516/
Owen Taylor3473f882001-02-23 17:55:21 +00006 *
7 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 */
11
12/*
13 * TODO: compute XPointers nodesets
Daniel Veillardd16df9f2001-05-23 13:44:21 +000014 * TODO: add an node intermediate API and handle recursion at this level
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
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>
Owen Taylor3473f882001-02-23 17:55:21 +000026#include <libxml/xmlerror.h>
27
28#ifdef LIBXML_XINCLUDE_ENABLED
29#include <libxml/xinclude.h>
30
Daniel Veillardbbd22452001-05-23 12:02:27 +000031#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
Owen Taylor3473f882001-02-23 17:55:21 +000032#define XINCLUDE_NODE (const xmlChar *) "include"
33#define XINCLUDE_HREF (const xmlChar *) "href"
34#define XINCLUDE_PARSE (const xmlChar *) "parse"
35#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
36#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
37
38/* #define DEBUG_XINCLUDE */
Daniel Veillard017b1082001-06-21 11:20:21 +000039#ifdef DEBUG_XINCLUDE
40#ifdef LIBXML_DEBUG_ENABLED
41#include <libxml/debugXML.h>
42#endif
43#endif
Owen Taylor3473f882001-02-23 17:55:21 +000044
45/************************************************************************
46 * *
47 * XInclude contexts handling *
48 * *
49 ************************************************************************/
50
51/*
52 * An XInclude context
53 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000054typedef xmlChar *xmlURL;
Owen Taylor3473f882001-02-23 17:55:21 +000055typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
56typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
57struct _xmlXIncludeCtxt {
58 xmlDocPtr doc; /* the source document */
59 int incNr; /* number of includes */
60 int incMax; /* size of includes tab */
61 xmlNodePtr *incTab; /* array of include nodes */
62 xmlNodePtr *repTab; /* array of replacement node lists */
63 int docNr; /* number of parsed documents */
64 int docMax; /* size of parsed documents tab */
65 xmlDocPtr *docTab; /* array of parsed documents */
Daniel Veillardedac3c92001-02-26 01:36:19 +000066 xmlURL *urlTab; /* array of parsed documents URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000067 int txtNr; /* number of unparsed documents */
68 int txtMax; /* size of unparsed documents tab */
69 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000070 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000071};
72
Daniel Veillardd16df9f2001-05-23 13:44:21 +000073static int
74xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
Owen Taylor3473f882001-02-23 17:55:21 +000075
76/**
77 * xmlXIncludeNewContext:
78 * @doc: an XML Document
79 *
80 * Creates a new XInclude context
81 *
82 * Returns the new set
83 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000084static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +000085xmlXIncludeNewContext(xmlDocPtr doc) {
86 xmlXIncludeCtxtPtr ret;
87
88 if (doc == NULL)
89 return(NULL);
90 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
91 if (ret == NULL)
92 return(NULL);
93 memset(ret, 0, sizeof(xmlXIncludeCtxt));
94 ret->doc = doc;
95 ret->incNr = 0;
96 ret->incMax = 0;
97 ret->incTab = NULL;
98 ret->repTab = NULL;
99 ret->docNr = 0;
100 ret->docMax = 0;
101 ret->docTab = NULL;
102 ret->urlTab = NULL;
103 return(ret);
104}
105
106/**
107 * xmlXIncludeFreeContext:
108 * @ctxt: the XInclude context
109 *
110 * Free an XInclude context
111 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000112static void
Owen Taylor3473f882001-02-23 17:55:21 +0000113xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
114 int i;
115
116 if (ctxt == NULL)
117 return;
118 for (i = 0;i < ctxt->docNr;i++) {
119 xmlFreeDoc(ctxt->docTab[i]);
120 if (ctxt->urlTab[i] != NULL)
121 xmlFree(ctxt->urlTab[i]);
122 }
123 for (i = 0;i < ctxt->txtNr;i++) {
124 if (ctxt->txturlTab[i] != NULL)
125 xmlFree(ctxt->txturlTab[i]);
126 }
127 if (ctxt->incTab != NULL)
128 xmlFree(ctxt->incTab);
129 if (ctxt->repTab != NULL)
130 xmlFree(ctxt->repTab);
131 if (ctxt->urlTab != NULL)
132 xmlFree(ctxt->urlTab);
133 if (ctxt->docTab != NULL)
134 xmlFree(ctxt->docTab);
135 if (ctxt->txtTab != NULL)
136 xmlFree(ctxt->txtTab);
137 if (ctxt->txturlTab != NULL)
138 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000139 xmlFree(ctxt);
140}
141
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000142/**
143 * xmlXIncludeAddNode:
144 * @ctxt: the XInclude context
145 * @node: the new node
146 *
147 * Add a new node to process to an XInclude context
148 */
149static void
150xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
151 if (ctxt->incMax == 0) {
152 ctxt->incMax = 4;
153 ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
154 sizeof(ctxt->incTab[0]));
155 if (ctxt->incTab == NULL) {
156 xmlGenericError(xmlGenericErrorContext,
157 "malloc failed !\n");
158 return;
159 }
160 ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
161 sizeof(ctxt->repTab[0]));
162 if (ctxt->repTab == NULL) {
163 xmlGenericError(xmlGenericErrorContext,
164 "malloc failed !\n");
165 return;
166 }
167 }
168 if (ctxt->incNr >= ctxt->incMax) {
169 ctxt->incMax *= 2;
170 ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
171 ctxt->incMax * sizeof(ctxt->incTab[0]));
172 if (ctxt->incTab == NULL) {
173 xmlGenericError(xmlGenericErrorContext,
174 "realloc failed !\n");
175 return;
176 }
177 ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
178 ctxt->incMax * sizeof(ctxt->repTab[0]));
179 if (ctxt->repTab == NULL) {
180 xmlGenericError(xmlGenericErrorContext,
181 "realloc failed !\n");
182 return;
183 }
184 }
185 ctxt->incTab[ctxt->incNr] = node;
186 ctxt->repTab[ctxt->incNr] = NULL;
187 ctxt->incNr++;
188}
189
190/**
191 * xmlXIncludeAddDoc:
192 * @ctxt: the XInclude context
193 * @doc: the new document
194 * @url: the associated URL
195 *
196 * Add a new document to the list. The XInclude recursive nature is handled
197 * at this point.
198 */
199static void
200xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url) {
201 xmlXIncludeCtxtPtr newctxt;
202 int i;
203
204 if (ctxt->docMax == 0) {
205 ctxt->docMax = 4;
206 ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
207 sizeof(ctxt->docTab[0]));
208 if (ctxt->docTab == NULL) {
209 xmlGenericError(xmlGenericErrorContext,
210 "malloc failed !\n");
211 return;
212 }
213 ctxt->urlTab = (xmlURL *) xmlMalloc(ctxt->docMax *
214 sizeof(ctxt->urlTab[0]));
215 if (ctxt->urlTab == NULL) {
216 xmlGenericError(xmlGenericErrorContext,
217 "malloc failed !\n");
218 return;
219 }
220 }
221 if (ctxt->docNr >= ctxt->docMax) {
222 ctxt->docMax *= 2;
223 ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
224 ctxt->docMax * sizeof(ctxt->docTab[0]));
225 if (ctxt->docTab == NULL) {
226 xmlGenericError(xmlGenericErrorContext,
227 "realloc failed !\n");
228 return;
229 }
230 ctxt->urlTab = (xmlURL *) xmlRealloc(ctxt->urlTab,
231 ctxt->docMax * sizeof(ctxt->urlTab[0]));
232 if (ctxt->urlTab == NULL) {
233 xmlGenericError(xmlGenericErrorContext,
234 "realloc failed !\n");
235 return;
236 }
237 }
238 ctxt->docTab[ctxt->docNr] = doc;
239 ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
240 ctxt->docNr++;
241
242 /*
243 * Handle recursion here.
244 */
245
246 newctxt = xmlXIncludeNewContext(doc);
247 if (newctxt != NULL) {
248 /*
249 * Copy the existing document set
250 */
251 newctxt->docMax = ctxt->docMax;
252 newctxt->docNr = ctxt->docNr;
253 newctxt->docTab = (xmlDocPtr *) xmlMalloc(newctxt->docMax *
254 sizeof(newctxt->docTab[0]));
255 if (newctxt->docTab == NULL) {
256 xmlGenericError(xmlGenericErrorContext,
257 "malloc failed !\n");
258 xmlFree(newctxt);
259 return;
260 }
261 newctxt->urlTab = (xmlURL *) xmlMalloc(newctxt->docMax *
262 sizeof(newctxt->urlTab[0]));
263 if (ctxt->urlTab == NULL) {
264 xmlGenericError(xmlGenericErrorContext,
265 "malloc failed !\n");
266 xmlFree(newctxt);
267 return;
268 }
269
270 for (i = 0;i < ctxt->docNr;i++) {
271 newctxt->docTab[i] = ctxt->docTab[i];
272 newctxt->urlTab[i] = ctxt->urlTab[i];
273 }
274 xmlXIncludeDoProcess(newctxt, doc);
275 for (i = 0;i < ctxt->docNr;i++) {
276 newctxt->docTab[i] = NULL;
277 newctxt->urlTab[i] = NULL;
278 }
279 xmlXIncludeFreeContext(newctxt);
280 }
281}
282
283/**
284 * xmlXIncludeAddTxt:
285 * @ctxt: the XInclude context
286 * @txt: the new text node
287 * @url: the associated URL
288 *
289 * Add a new txtument to the list
290 */
291static void
292xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
293 if (ctxt->txtMax == 0) {
294 ctxt->txtMax = 4;
295 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
296 sizeof(ctxt->txtTab[0]));
297 if (ctxt->txtTab == NULL) {
298 xmlGenericError(xmlGenericErrorContext,
299 "malloc failed !\n");
300 return;
301 }
302 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
303 sizeof(ctxt->txturlTab[0]));
304 if (ctxt->txturlTab == NULL) {
305 xmlGenericError(xmlGenericErrorContext,
306 "malloc failed !\n");
307 return;
308 }
309 }
310 if (ctxt->txtNr >= ctxt->txtMax) {
311 ctxt->txtMax *= 2;
312 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
313 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
314 if (ctxt->txtTab == NULL) {
315 xmlGenericError(xmlGenericErrorContext,
316 "realloc failed !\n");
317 return;
318 }
319 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
320 ctxt->txtMax * sizeof(ctxt->urlTab[0]));
321 if (ctxt->txturlTab == NULL) {
322 xmlGenericError(xmlGenericErrorContext,
323 "realloc failed !\n");
324 return;
325 }
326 }
327 ctxt->txtTab[ctxt->txtNr] = txt;
328 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
329 ctxt->txtNr++;
330}
331
Owen Taylor3473f882001-02-23 17:55:21 +0000332/************************************************************************
333 * *
334 * XInclude I/O handling *
335 * *
336 ************************************************************************/
337
338/**
339 * xmlXIncludeLoadDoc:
340 * @ctxt: the XInclude context
341 * @url: the associated URL
342 * @nr: the xinclude node number
343 *
344 * Load the document, and store the result in the XInclude context
345 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000346static void
Owen Taylor3473f882001-02-23 17:55:21 +0000347xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
348 xmlDocPtr doc;
349 xmlURIPtr uri;
350 xmlChar *URL;
351 xmlChar *fragment = NULL;
352 int i;
353 /*
354 * Check the URL and remove any fragment identifier
355 */
356 uri = xmlParseURI((const char *)url);
357 if (uri == NULL) {
358 xmlGenericError(xmlGenericErrorContext,
359 "XInclude: invalid value URI %s\n", url);
360 return;
361 }
362 if (uri->fragment != NULL) {
363 fragment = (xmlChar *) uri->fragment;
364 uri->fragment = NULL;
365 }
366 URL = xmlSaveUri(uri);
367 xmlFreeURI(uri);
368 if (URL == NULL) {
369 xmlGenericError(xmlGenericErrorContext,
370 "XInclude: invalid value URI %s\n", url);
371 if (fragment != NULL)
372 xmlFree(fragment);
373 return;
374 }
375
376 /*
377 * Handling of references to the local document are done
378 * directly through ctxt->doc.
379 */
380 if ((URL[0] == 0) || (URL[0] == '#')) {
381 doc = NULL;
382 goto loaded;
383 }
384
385 /*
386 * Prevent reloading twice the document.
387 */
388 for (i = 0; i < ctxt->docNr; i++) {
389 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
390 doc = ctxt->docTab[i];
391 goto loaded;
392 }
393 }
394 /*
395 * Load it.
396 */
397 doc = xmlParseFile((const char *)URL);
398 if (doc == NULL) {
399 xmlGenericError(xmlGenericErrorContext,
400 "XInclude: could not load %s\n", URL);
401 xmlFree(URL);
402 if (fragment != NULL)
403 xmlFree(fragment);
404 return;
405 }
406 xmlXIncludeAddDoc(ctxt, doc, URL);
407
408loaded:
409 if (fragment == NULL) {
410 /*
411 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +0000412 */
413 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +0000414 {
415 /* Hopefully a DTD declaration won't be copied from
416 * the same document */
Owen Taylor3473f882001-02-23 17:55:21 +0000417 ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000418 } else {
419 /* DTD declarations can't be copied from included files */
420 xmlNodePtr node = doc->children;
421 while (node != NULL)
422 {
423 if (node->type == XML_DTD_NODE)
424 {
425 xmlUnlinkNode(node);
426 xmlFreeNode(node);
427 }
428 node = node->next;
429 }
Owen Taylor3473f882001-02-23 17:55:21 +0000430 ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000431 }
Owen Taylor3473f882001-02-23 17:55:21 +0000432 } else {
433 /*
434 * Computes the XPointer expression and make a copy used
435 * as the replacement copy.
436 */
437 xmlXPathObjectPtr xptr;
438 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +0000439 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +0000440
441 if (doc == NULL) {
442 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
443 } else {
444 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
445 }
446 if (xptrctxt == NULL) {
447 xmlGenericError(xmlGenericErrorContext,
448 "XInclude: could create XPointer context\n");
449 xmlFree(URL);
450 xmlFree(fragment);
451 return;
452 }
453 xptr = xmlXPtrEval(fragment, xptrctxt);
454 if (xptr == NULL) {
455 xmlGenericError(xmlGenericErrorContext,
456 "XInclude: XPointer evaluation failed: #%s\n",
457 fragment);
458 xmlXPathFreeContext(xptrctxt);
459 xmlFree(URL);
460 xmlFree(fragment);
461 return;
462 }
Daniel Veillard39196eb2001-06-19 18:09:42 +0000463 switch (xptr->type) {
464 case XPATH_UNDEFINED:
465 case XPATH_BOOLEAN:
466 case XPATH_NUMBER:
467 case XPATH_STRING:
468 case XPATH_POINT:
469 case XPATH_USERS:
470 case XPATH_XSLT_TREE:
471 xmlGenericError(xmlGenericErrorContext,
472 "XInclude: XPointer is not a range: #%s\n",
473 fragment);
474 xmlXPathFreeContext(xptrctxt);
475 xmlFree(URL);
476 xmlFree(fragment);
477 return;
478 case XPATH_NODESET:
479 case XPATH_RANGE:
480 case XPATH_LOCATIONSET:
481 break;
482 }
483 set = xptr->nodesetval;
484 if (set != NULL) {
485 for (i = 0;i < set->nodeNr;i++) {
486 if (set->nodeTab[i] == NULL)
487 continue;
488 switch (set->nodeTab[i]->type) {
489 case XML_TEXT_NODE:
490 case XML_CDATA_SECTION_NODE:
491 case XML_ELEMENT_NODE:
492 case XML_ENTITY_REF_NODE:
493 case XML_ENTITY_NODE:
494 case XML_PI_NODE:
495 case XML_COMMENT_NODE:
496 case XML_DOCUMENT_NODE:
497 case XML_HTML_DOCUMENT_NODE:
498#ifdef LIBXML_DOCB_ENABLED
499 case XML_DOCB_DOCUMENT_NODE:
500#endif
501 continue;
502 case XML_ATTRIBUTE_NODE:
503 xmlGenericError(xmlGenericErrorContext,
504 "XInclude: XPointer selects an attribute: #%s\n",
505 fragment);
506 set->nodeTab[i] = NULL;
507 continue;
508 case XML_NAMESPACE_DECL:
509 xmlGenericError(xmlGenericErrorContext,
510 "XInclude: XPointer selects a namespace: #%s\n",
511 fragment);
512 set->nodeTab[i] = NULL;
513 continue;
514 case XML_DOCUMENT_TYPE_NODE:
515 case XML_DOCUMENT_FRAG_NODE:
516 case XML_NOTATION_NODE:
517 case XML_DTD_NODE:
518 case XML_ELEMENT_DECL:
519 case XML_ATTRIBUTE_DECL:
520 case XML_ENTITY_DECL:
521 case XML_XINCLUDE_START:
522 case XML_XINCLUDE_END:
523 xmlGenericError(xmlGenericErrorContext,
524 "XInclude: XPointer selects unexpected nodes: #%s\n",
525 fragment);
526 set->nodeTab[i] = NULL;
527 set->nodeTab[i] = NULL;
528 continue; /* for */
529 }
530 }
531 }
Owen Taylor3473f882001-02-23 17:55:21 +0000532 ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
533 xmlXPathFreeObject(xptr);
534 xmlXPathFreeContext(xptrctxt);
535 xmlFree(fragment);
536 }
537 xmlFree(URL);
538}
539
540/**
541 * xmlXIncludeLoadTxt:
542 * @ctxt: the XInclude context
543 * @url: the associated URL
544 * @nr: the xinclude node number
545 *
546 * Load the content, and store the result in the XInclude context
547 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000548static void
Owen Taylor3473f882001-02-23 17:55:21 +0000549xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
550 xmlParserInputBufferPtr buf;
551 xmlNodePtr node;
552 xmlURIPtr uri;
553 xmlChar *URL;
554 int i;
555 /*
556 * Check the URL and remove any fragment identifier
557 */
558 uri = xmlParseURI((const char *)url);
559 if (uri == NULL) {
560 xmlGenericError(xmlGenericErrorContext,
561 "XInclude: invalid value URI %s\n", url);
562 return;
563 }
564 if (uri->fragment != NULL) {
565 xmlGenericError(xmlGenericErrorContext,
566 "XInclude: fragment identifier forbidden for text: %s\n",
567 uri->fragment);
568 xmlFreeURI(uri);
569 return;
570 }
571 URL = xmlSaveUri(uri);
572 xmlFreeURI(uri);
573 if (URL == NULL) {
574 xmlGenericError(xmlGenericErrorContext,
575 "XInclude: invalid value URI %s\n", url);
576 return;
577 }
578
579 /*
580 * Handling of references to the local document are done
581 * directly through ctxt->doc.
582 */
583 if (URL[0] == 0) {
584 xmlGenericError(xmlGenericErrorContext,
585 "XInclude: text serialization of document not available\n");
586 xmlFree(URL);
587 return;
588 }
589
590 /*
591 * Prevent reloading twice the document.
592 */
593 for (i = 0; i < ctxt->txtNr; i++) {
594 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
595 node = xmlCopyNode(ctxt->txtTab[i], 1);
596 goto loaded;
597 }
598 }
599 /*
600 * Load it.
601 * Issue 62: how to detect the encoding
602 */
603 buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
604 if (buf == NULL) {
605 xmlGenericError(xmlGenericErrorContext,
606 "XInclude: could not load %s\n", URL);
607 xmlFree(URL);
608 return;
609 }
610 node = xmlNewText(NULL);
611
612 /*
613 * Scan all chars from the resource and add the to the node
614 */
615 while (xmlParserInputBufferRead(buf, 128) > 0) {
616 int len;
617 const xmlChar *content;
618
619 content = xmlBufferContent(buf->buffer);
620 len = xmlBufferLength(buf->buffer);
621 for (i = 0;i < len; i++) {
622 /*
623 * TODO: if the encoding issue is solved, scan UTF8 chars instead
624 */
625 if (!IS_CHAR(content[i])) {
626 xmlGenericError(xmlGenericErrorContext,
627 "XInclude: %s contains invalid char %d\n", URL, content[i]);
628 } else {
629 xmlNodeAddContentLen(node, &content[i], 1);
630 }
631 }
632 xmlBufferShrink(buf->buffer, len);
633 }
634 xmlFreeParserInputBuffer(buf);
635 xmlXIncludeAddTxt(ctxt, node, URL);
636
637loaded:
638 /*
639 * Add the element as the replacement copy.
640 */
641 ctxt->repTab[nr] = node;
642 xmlFree(URL);
643}
644
645/************************************************************************
646 * *
647 * XInclude Processing *
648 * *
649 ************************************************************************/
650
651/**
652 * xmlXIncludePreProcessNode:
653 * @ctxt: an XInclude context
654 * @node: an XInclude node
655 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000656 * Implement the XInclude preprocessing, currently just adding the element
657 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +0000658 *
659 * Returns the result list or NULL in case of error
660 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000661static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +0000662xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
663 xmlXIncludeAddNode(ctxt, node);
664 return(0);
665}
666
667/**
668 * xmlXIncludeLoadNode:
669 * @ctxt: an XInclude context
670 * @nr: the node number
671 *
672 * Find and load the infoset replacement for the given node.
673 *
674 * Returns 0 if substition succeeded, -1 if some processing failed
675 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000676static int
Owen Taylor3473f882001-02-23 17:55:21 +0000677xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
678 xmlNodePtr cur;
679 xmlChar *href;
680 xmlChar *parse;
681 xmlChar *base;
682 xmlChar *URI;
683 int xml = 1; /* default Issue 64 */
684
685 if (ctxt == NULL)
686 return(-1);
687 if ((nr < 0) || (nr >= ctxt->incNr))
688 return(-1);
689 cur = ctxt->incTab[nr];
690 if (cur == NULL)
691 return(-1);
692
693#ifdef DEBUG_XINCLUDE
694 xmlDebugDumpNode(stdout, cur, 0);
695#endif
696 /*
697 * read the attributes
698 */
699 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
700 if (href == NULL) {
701 href = xmlGetProp(cur, XINCLUDE_HREF);
702 if (href == NULL) {
703 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
704 return(-1);
705 }
706 }
707 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
708 if (parse == NULL) {
709 parse = xmlGetProp(cur, XINCLUDE_PARSE);
710 }
711 if (parse != NULL) {
712 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
713 xml = 1;
714 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
715 xml = 0;
716 else {
717 xmlGenericError(xmlGenericErrorContext,
718 "XInclude: invalid value %s for %s\n",
719 parse, XINCLUDE_PARSE);
720 if (href != NULL)
721 xmlFree(href);
722 if (parse != NULL)
723 xmlFree(parse);
724 return(-1);
725 }
726 }
727
728 /*
729 * compute the URI
730 */
731 base = xmlNodeGetBase(ctxt->doc, cur);
732 if (base == NULL) {
733 URI = xmlBuildURI(href, ctxt->doc->URL);
734 } else {
735 URI = xmlBuildURI(href, base);
736 }
737 if (URI == NULL) {
738 xmlChar *escbase;
739 xmlChar *eschref;
740 /*
741 * Some escapeing may be needed
742 */
743 escbase = xmlURIEscape(base);
744 eschref = xmlURIEscape(href);
745 URI = xmlBuildURI(eschref, escbase);
746 if (escbase != NULL)
747 xmlFree(escbase);
748 if (eschref != NULL)
749 xmlFree(eschref);
750 }
751 if (URI == NULL) {
752 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
753 if (parse != NULL)
754 xmlFree(parse);
755 if (href != NULL)
756 xmlFree(href);
757 if (base != NULL)
758 xmlFree(base);
759 return(-1);
760 }
761#ifdef DEBUG_XINCLUDE
762 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
763 xml ? "xml": "text");
764 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
765#endif
766
767 /*
768 * Cleanup
769 */
770 if (xml) {
771 xmlXIncludeLoadDoc(ctxt, URI, nr);
772 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
773 } else {
774 xmlXIncludeLoadTxt(ctxt, URI, nr);
775 }
776
777 /*
778 * Cleanup
779 */
780 if (URI != NULL)
781 xmlFree(URI);
782 if (parse != NULL)
783 xmlFree(parse);
784 if (href != NULL)
785 xmlFree(href);
786 if (base != NULL)
787 xmlFree(base);
788 return(0);
789}
790
791/**
792 * xmlXIncludeIncludeNode:
793 * @ctxt: an XInclude context
794 * @nr: the node number
795 *
796 * Inplement the infoset replacement for the given node
797 *
798 * Returns 0 if substition succeeded, -1 if some processing failed
799 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000800static int
Owen Taylor3473f882001-02-23 17:55:21 +0000801xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
802 xmlNodePtr cur, end, list;
803
804 if (ctxt == NULL)
805 return(-1);
806 if ((nr < 0) || (nr >= ctxt->incNr))
807 return(-1);
808 cur = ctxt->incTab[nr];
809 if (cur == NULL)
810 return(-1);
811
812 /*
813 * Change the current node as an XInclude start one, and add an
814 * entity end one
815 */
816 cur->type = XML_XINCLUDE_START;
817 end = xmlNewNode(cur->ns, cur->name);
818 if (end == NULL) {
819 xmlGenericError(xmlGenericErrorContext,
820 "XInclude: failed to build node\n");
821 return(-1);
822 }
823 end->type = XML_XINCLUDE_END;
824 xmlAddNextSibling(cur, end);
825
826 /*
827 * Add the list of nodes
828 */
829 list = ctxt->repTab[nr];
830 ctxt->repTab[nr] = NULL;
831 while (list != NULL) {
832 cur = list;
833 list = list->next;
834
835 xmlAddPrevSibling(end, cur);
836 }
837 return(0);
838}
839
840/**
841 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +0000842 * @node: an XInclude node
843 *
844 * test if the node is an XInclude node
845 *
846 * Returns 1 true, 0 otherwise
847 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000848static int
849xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +0000850 if (node == NULL)
851 return(0);
852 if (node->ns == NULL)
853 return(0);
854 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
855 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
856 return(0);
857}
858
859/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000860 * xmlXIncludeDoProcess:
861 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +0000862 * @doc: an XML document
863 *
864 * Implement the XInclude substitution on the XML document @doc
865 *
866 * Returns 0 if no substition were done, -1 if some processing failed
867 * or the number of substitutions done.
868 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000869static int
870xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +0000871 xmlNodePtr cur;
872 int ret = 0;
873 int i;
874
875 if (doc == NULL)
876 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000877 if (ctxt == NULL)
878 return(-1);
879
880 /*
881 * First phase: lookup the elements in the document
882 */
883 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000884 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000885 xmlXIncludePreProcessNode(ctxt, cur);
886 while (cur != NULL) {
887 /* TODO: need to work on entities -> stack */
888 if ((cur->children != NULL) &&
889 (cur->children->type != XML_ENTITY_DECL)) {
890 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000891 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000892 xmlXIncludePreProcessNode(ctxt, cur);
893 } else if (cur->next != NULL) {
894 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000895 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000896 xmlXIncludePreProcessNode(ctxt, cur);
897 } else {
898 do {
899 cur = cur->parent;
900 if (cur == NULL) break; /* do */
901 if (cur->next != NULL) {
902 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000903 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000904 xmlXIncludePreProcessNode(ctxt, cur);
905 break; /* do */
906 }
907 } while (cur != NULL);
908 }
909 }
910
911 /*
912 * Second Phase : collect the infosets fragments
913 */
914 for (i = 0;i < ctxt->incNr; i++) {
915 xmlXIncludeLoadNode(ctxt, i);
916 }
917
918 /*
919 * Third phase: extend the original document infoset.
920 */
921 for (i = 0;i < ctxt->incNr; i++) {
922 xmlXIncludeIncludeNode(ctxt, i);
923 }
924
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000925 return(ret);
926}
927
928/**
929 * xmlXIncludeProcess:
930 * @doc: an XML document
931 *
932 * Implement the XInclude substitution on the XML document @doc
933 *
934 * Returns 0 if no substition were done, -1 if some processing failed
935 * or the number of substitutions done.
936 */
937int
938xmlXIncludeProcess(xmlDocPtr doc) {
939 xmlXIncludeCtxtPtr ctxt;
940 int ret = 0;
941
942 if (doc == NULL)
943 return(-1);
944 ctxt = xmlXIncludeNewContext(doc);
945 if (ctxt == NULL)
946 return(-1);
947 ret = xmlXIncludeDoProcess(ctxt, doc);
948
Owen Taylor3473f882001-02-23 17:55:21 +0000949 xmlXIncludeFreeContext(ctxt);
950 return(ret);
951}
952
953#else /* !LIBXML_XINCLUDE_ENABLED */
954#endif