blob: b659b44107e99b311778d81ba81c28c04be1f15d [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;
Daniel Veillard39196eb2001-06-19 18:09:42 +0000437 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +0000438
439 if (doc == NULL) {
440 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
441 } else {
442 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
443 }
444 if (xptrctxt == NULL) {
445 xmlGenericError(xmlGenericErrorContext,
446 "XInclude: could create XPointer context\n");
447 xmlFree(URL);
448 xmlFree(fragment);
449 return;
450 }
451 xptr = xmlXPtrEval(fragment, xptrctxt);
452 if (xptr == NULL) {
453 xmlGenericError(xmlGenericErrorContext,
454 "XInclude: XPointer evaluation failed: #%s\n",
455 fragment);
456 xmlXPathFreeContext(xptrctxt);
457 xmlFree(URL);
458 xmlFree(fragment);
459 return;
460 }
Daniel Veillard39196eb2001-06-19 18:09:42 +0000461 switch (xptr->type) {
462 case XPATH_UNDEFINED:
463 case XPATH_BOOLEAN:
464 case XPATH_NUMBER:
465 case XPATH_STRING:
466 case XPATH_POINT:
467 case XPATH_USERS:
468 case XPATH_XSLT_TREE:
469 xmlGenericError(xmlGenericErrorContext,
470 "XInclude: XPointer is not a range: #%s\n",
471 fragment);
472 xmlXPathFreeContext(xptrctxt);
473 xmlFree(URL);
474 xmlFree(fragment);
475 return;
476 case XPATH_NODESET:
477 case XPATH_RANGE:
478 case XPATH_LOCATIONSET:
479 break;
480 }
481 set = xptr->nodesetval;
482 if (set != NULL) {
483 for (i = 0;i < set->nodeNr;i++) {
484 if (set->nodeTab[i] == NULL)
485 continue;
486 switch (set->nodeTab[i]->type) {
487 case XML_TEXT_NODE:
488 case XML_CDATA_SECTION_NODE:
489 case XML_ELEMENT_NODE:
490 case XML_ENTITY_REF_NODE:
491 case XML_ENTITY_NODE:
492 case XML_PI_NODE:
493 case XML_COMMENT_NODE:
494 case XML_DOCUMENT_NODE:
495 case XML_HTML_DOCUMENT_NODE:
496#ifdef LIBXML_DOCB_ENABLED
497 case XML_DOCB_DOCUMENT_NODE:
498#endif
499 continue;
500 case XML_ATTRIBUTE_NODE:
501 xmlGenericError(xmlGenericErrorContext,
502 "XInclude: XPointer selects an attribute: #%s\n",
503 fragment);
504 set->nodeTab[i] = NULL;
505 continue;
506 case XML_NAMESPACE_DECL:
507 xmlGenericError(xmlGenericErrorContext,
508 "XInclude: XPointer selects a namespace: #%s\n",
509 fragment);
510 set->nodeTab[i] = NULL;
511 continue;
512 case XML_DOCUMENT_TYPE_NODE:
513 case XML_DOCUMENT_FRAG_NODE:
514 case XML_NOTATION_NODE:
515 case XML_DTD_NODE:
516 case XML_ELEMENT_DECL:
517 case XML_ATTRIBUTE_DECL:
518 case XML_ENTITY_DECL:
519 case XML_XINCLUDE_START:
520 case XML_XINCLUDE_END:
521 xmlGenericError(xmlGenericErrorContext,
522 "XInclude: XPointer selects unexpected nodes: #%s\n",
523 fragment);
524 set->nodeTab[i] = NULL;
525 set->nodeTab[i] = NULL;
526 continue; /* for */
527 }
528 }
529 }
Owen Taylor3473f882001-02-23 17:55:21 +0000530 ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
531 xmlXPathFreeObject(xptr);
532 xmlXPathFreeContext(xptrctxt);
533 xmlFree(fragment);
534 }
535 xmlFree(URL);
536}
537
538/**
539 * xmlXIncludeLoadTxt:
540 * @ctxt: the XInclude context
541 * @url: the associated URL
542 * @nr: the xinclude node number
543 *
544 * Load the content, and store the result in the XInclude context
545 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000546static void
Owen Taylor3473f882001-02-23 17:55:21 +0000547xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
548 xmlParserInputBufferPtr buf;
549 xmlNodePtr node;
550 xmlURIPtr uri;
551 xmlChar *URL;
552 int i;
553 /*
554 * Check the URL and remove any fragment identifier
555 */
556 uri = xmlParseURI((const char *)url);
557 if (uri == NULL) {
558 xmlGenericError(xmlGenericErrorContext,
559 "XInclude: invalid value URI %s\n", url);
560 return;
561 }
562 if (uri->fragment != NULL) {
563 xmlGenericError(xmlGenericErrorContext,
564 "XInclude: fragment identifier forbidden for text: %s\n",
565 uri->fragment);
566 xmlFreeURI(uri);
567 return;
568 }
569 URL = xmlSaveUri(uri);
570 xmlFreeURI(uri);
571 if (URL == NULL) {
572 xmlGenericError(xmlGenericErrorContext,
573 "XInclude: invalid value URI %s\n", url);
574 return;
575 }
576
577 /*
578 * Handling of references to the local document are done
579 * directly through ctxt->doc.
580 */
581 if (URL[0] == 0) {
582 xmlGenericError(xmlGenericErrorContext,
583 "XInclude: text serialization of document not available\n");
584 xmlFree(URL);
585 return;
586 }
587
588 /*
589 * Prevent reloading twice the document.
590 */
591 for (i = 0; i < ctxt->txtNr; i++) {
592 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
593 node = xmlCopyNode(ctxt->txtTab[i], 1);
594 goto loaded;
595 }
596 }
597 /*
598 * Load it.
599 * Issue 62: how to detect the encoding
600 */
601 buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
602 if (buf == NULL) {
603 xmlGenericError(xmlGenericErrorContext,
604 "XInclude: could not load %s\n", URL);
605 xmlFree(URL);
606 return;
607 }
608 node = xmlNewText(NULL);
609
610 /*
611 * Scan all chars from the resource and add the to the node
612 */
613 while (xmlParserInputBufferRead(buf, 128) > 0) {
614 int len;
615 const xmlChar *content;
616
617 content = xmlBufferContent(buf->buffer);
618 len = xmlBufferLength(buf->buffer);
619 for (i = 0;i < len; i++) {
620 /*
621 * TODO: if the encoding issue is solved, scan UTF8 chars instead
622 */
623 if (!IS_CHAR(content[i])) {
624 xmlGenericError(xmlGenericErrorContext,
625 "XInclude: %s contains invalid char %d\n", URL, content[i]);
626 } else {
627 xmlNodeAddContentLen(node, &content[i], 1);
628 }
629 }
630 xmlBufferShrink(buf->buffer, len);
631 }
632 xmlFreeParserInputBuffer(buf);
633 xmlXIncludeAddTxt(ctxt, node, URL);
634
635loaded:
636 /*
637 * Add the element as the replacement copy.
638 */
639 ctxt->repTab[nr] = node;
640 xmlFree(URL);
641}
642
643/************************************************************************
644 * *
645 * XInclude Processing *
646 * *
647 ************************************************************************/
648
649/**
650 * xmlXIncludePreProcessNode:
651 * @ctxt: an XInclude context
652 * @node: an XInclude node
653 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000654 * Implement the XInclude preprocessing, currently just adding the element
655 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +0000656 *
657 * Returns the result list or NULL in case of error
658 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000659static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +0000660xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
661 xmlXIncludeAddNode(ctxt, node);
662 return(0);
663}
664
665/**
666 * xmlXIncludeLoadNode:
667 * @ctxt: an XInclude context
668 * @nr: the node number
669 *
670 * Find and load the infoset replacement for the given node.
671 *
672 * Returns 0 if substition succeeded, -1 if some processing failed
673 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000674static int
Owen Taylor3473f882001-02-23 17:55:21 +0000675xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
676 xmlNodePtr cur;
677 xmlChar *href;
678 xmlChar *parse;
679 xmlChar *base;
680 xmlChar *URI;
681 int xml = 1; /* default Issue 64 */
682
683 if (ctxt == NULL)
684 return(-1);
685 if ((nr < 0) || (nr >= ctxt->incNr))
686 return(-1);
687 cur = ctxt->incTab[nr];
688 if (cur == NULL)
689 return(-1);
690
691#ifdef DEBUG_XINCLUDE
692 xmlDebugDumpNode(stdout, cur, 0);
693#endif
694 /*
695 * read the attributes
696 */
697 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
698 if (href == NULL) {
699 href = xmlGetProp(cur, XINCLUDE_HREF);
700 if (href == NULL) {
701 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
702 return(-1);
703 }
704 }
705 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
706 if (parse == NULL) {
707 parse = xmlGetProp(cur, XINCLUDE_PARSE);
708 }
709 if (parse != NULL) {
710 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
711 xml = 1;
712 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
713 xml = 0;
714 else {
715 xmlGenericError(xmlGenericErrorContext,
716 "XInclude: invalid value %s for %s\n",
717 parse, XINCLUDE_PARSE);
718 if (href != NULL)
719 xmlFree(href);
720 if (parse != NULL)
721 xmlFree(parse);
722 return(-1);
723 }
724 }
725
726 /*
727 * compute the URI
728 */
729 base = xmlNodeGetBase(ctxt->doc, cur);
730 if (base == NULL) {
731 URI = xmlBuildURI(href, ctxt->doc->URL);
732 } else {
733 URI = xmlBuildURI(href, base);
734 }
735 if (URI == NULL) {
736 xmlChar *escbase;
737 xmlChar *eschref;
738 /*
739 * Some escapeing may be needed
740 */
741 escbase = xmlURIEscape(base);
742 eschref = xmlURIEscape(href);
743 URI = xmlBuildURI(eschref, escbase);
744 if (escbase != NULL)
745 xmlFree(escbase);
746 if (eschref != NULL)
747 xmlFree(eschref);
748 }
749 if (URI == NULL) {
750 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
751 if (parse != NULL)
752 xmlFree(parse);
753 if (href != NULL)
754 xmlFree(href);
755 if (base != NULL)
756 xmlFree(base);
757 return(-1);
758 }
759#ifdef DEBUG_XINCLUDE
760 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
761 xml ? "xml": "text");
762 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
763#endif
764
765 /*
766 * Cleanup
767 */
768 if (xml) {
769 xmlXIncludeLoadDoc(ctxt, URI, nr);
770 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
771 } else {
772 xmlXIncludeLoadTxt(ctxt, URI, nr);
773 }
774
775 /*
776 * Cleanup
777 */
778 if (URI != NULL)
779 xmlFree(URI);
780 if (parse != NULL)
781 xmlFree(parse);
782 if (href != NULL)
783 xmlFree(href);
784 if (base != NULL)
785 xmlFree(base);
786 return(0);
787}
788
789/**
790 * xmlXIncludeIncludeNode:
791 * @ctxt: an XInclude context
792 * @nr: the node number
793 *
794 * Inplement the infoset replacement for the given node
795 *
796 * Returns 0 if substition succeeded, -1 if some processing failed
797 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000798static int
Owen Taylor3473f882001-02-23 17:55:21 +0000799xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
800 xmlNodePtr cur, end, list;
801
802 if (ctxt == NULL)
803 return(-1);
804 if ((nr < 0) || (nr >= ctxt->incNr))
805 return(-1);
806 cur = ctxt->incTab[nr];
807 if (cur == NULL)
808 return(-1);
809
810 /*
811 * Change the current node as an XInclude start one, and add an
812 * entity end one
813 */
814 cur->type = XML_XINCLUDE_START;
815 end = xmlNewNode(cur->ns, cur->name);
816 if (end == NULL) {
817 xmlGenericError(xmlGenericErrorContext,
818 "XInclude: failed to build node\n");
819 return(-1);
820 }
821 end->type = XML_XINCLUDE_END;
822 xmlAddNextSibling(cur, end);
823
824 /*
825 * Add the list of nodes
826 */
827 list = ctxt->repTab[nr];
828 ctxt->repTab[nr] = NULL;
829 while (list != NULL) {
830 cur = list;
831 list = list->next;
832
833 xmlAddPrevSibling(end, cur);
834 }
835 return(0);
836}
837
838/**
839 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +0000840 * @node: an XInclude node
841 *
842 * test if the node is an XInclude node
843 *
844 * Returns 1 true, 0 otherwise
845 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000846static int
847xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +0000848 if (node == NULL)
849 return(0);
850 if (node->ns == NULL)
851 return(0);
852 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
853 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
854 return(0);
855}
856
857/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000858 * xmlXIncludeDoProcess:
859 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +0000860 * @doc: an XML document
861 *
862 * Implement the XInclude substitution on the XML document @doc
863 *
864 * Returns 0 if no substition were done, -1 if some processing failed
865 * or the number of substitutions done.
866 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000867static int
868xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +0000869 xmlNodePtr cur;
870 int ret = 0;
871 int i;
872
873 if (doc == NULL)
874 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000875 if (ctxt == NULL)
876 return(-1);
877
878 /*
879 * First phase: lookup the elements in the document
880 */
881 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000882 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000883 xmlXIncludePreProcessNode(ctxt, cur);
884 while (cur != NULL) {
885 /* TODO: need to work on entities -> stack */
886 if ((cur->children != NULL) &&
887 (cur->children->type != XML_ENTITY_DECL)) {
888 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000889 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000890 xmlXIncludePreProcessNode(ctxt, cur);
891 } else if (cur->next != NULL) {
892 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000893 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000894 xmlXIncludePreProcessNode(ctxt, cur);
895 } else {
896 do {
897 cur = cur->parent;
898 if (cur == NULL) break; /* do */
899 if (cur->next != NULL) {
900 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000901 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +0000902 xmlXIncludePreProcessNode(ctxt, cur);
903 break; /* do */
904 }
905 } while (cur != NULL);
906 }
907 }
908
909 /*
910 * Second Phase : collect the infosets fragments
911 */
912 for (i = 0;i < ctxt->incNr; i++) {
913 xmlXIncludeLoadNode(ctxt, i);
914 }
915
916 /*
917 * Third phase: extend the original document infoset.
918 */
919 for (i = 0;i < ctxt->incNr; i++) {
920 xmlXIncludeIncludeNode(ctxt, i);
921 }
922
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000923 return(ret);
924}
925
926/**
927 * xmlXIncludeProcess:
928 * @doc: an XML document
929 *
930 * Implement the XInclude substitution on the XML document @doc
931 *
932 * Returns 0 if no substition were done, -1 if some processing failed
933 * or the number of substitutions done.
934 */
935int
936xmlXIncludeProcess(xmlDocPtr doc) {
937 xmlXIncludeCtxtPtr ctxt;
938 int ret = 0;
939
940 if (doc == NULL)
941 return(-1);
942 ctxt = xmlXIncludeNewContext(doc);
943 if (ctxt == NULL)
944 return(-1);
945 ret = xmlXIncludeDoProcess(ctxt, doc);
946
Owen Taylor3473f882001-02-23 17:55:21 +0000947 xmlXIncludeFreeContext(ctxt);
948 return(ret);
949}
950
951#else /* !LIBXML_XINCLUDE_ENABLED */
952#endif