blob: 63cb5e9b8a0cc6afeea55c64488b5e884e329c2e [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
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21#include <libxml/xmlmemory.h>
22#include <libxml/tree.h>
23#include <libxml/parser.h>
24#include <libxml/uri.h>
25#include <libxml/xpointer.h>
26#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000027#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000028#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000029
30#ifdef LIBXML_XINCLUDE_ENABLED
31#include <libxml/xinclude.h>
32
Daniel Veillardbbd22452001-05-23 12:02:27 +000033#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
Owen Taylor3473f882001-02-23 17:55:21 +000034#define XINCLUDE_NODE (const xmlChar *) "include"
Daniel Veillard58e44c92002-08-02 22:19:49 +000035#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
Owen Taylor3473f882001-02-23 17:55:21 +000036#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 */
Daniel Veillard017b1082001-06-21 11:20:21 +000042#ifdef DEBUG_XINCLUDE
43#ifdef LIBXML_DEBUG_ENABLED
44#include <libxml/debugXML.h>
45#endif
46#endif
Owen Taylor3473f882001-02-23 17:55:21 +000047
48/************************************************************************
49 * *
50 * XInclude contexts handling *
51 * *
52 ************************************************************************/
53
54/*
55 * An XInclude context
56 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000057typedef xmlChar *xmlURL;
Owen Taylor3473f882001-02-23 17:55:21 +000058typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
59typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
60struct _xmlXIncludeCtxt {
61 xmlDocPtr doc; /* the source document */
62 int incNr; /* number of includes */
63 int incMax; /* size of includes tab */
64 xmlNodePtr *incTab; /* array of include nodes */
65 xmlNodePtr *repTab; /* array of replacement node lists */
66 int docNr; /* number of parsed documents */
67 int docMax; /* size of parsed documents tab */
68 xmlDocPtr *docTab; /* array of parsed documents */
Daniel Veillardedac3c92001-02-26 01:36:19 +000069 xmlURL *urlTab; /* array of parsed documents URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000070 int txtNr; /* number of unparsed documents */
71 int txtMax; /* size of unparsed documents tab */
72 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000073 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000074};
75
Daniel Veillardd16df9f2001-05-23 13:44:21 +000076static int
77xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
Owen Taylor3473f882001-02-23 17:55:21 +000078
79/**
80 * xmlXIncludeNewContext:
81 * @doc: an XML Document
82 *
83 * Creates a new XInclude context
84 *
85 * Returns the new set
86 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000087static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +000088xmlXIncludeNewContext(xmlDocPtr doc) {
89 xmlXIncludeCtxtPtr ret;
90
91 if (doc == NULL)
92 return(NULL);
93 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
94 if (ret == NULL)
95 return(NULL);
96 memset(ret, 0, sizeof(xmlXIncludeCtxt));
97 ret->doc = doc;
98 ret->incNr = 0;
99 ret->incMax = 0;
100 ret->incTab = NULL;
101 ret->repTab = NULL;
102 ret->docNr = 0;
103 ret->docMax = 0;
104 ret->docTab = NULL;
105 ret->urlTab = NULL;
106 return(ret);
107}
108
109/**
110 * xmlXIncludeFreeContext:
111 * @ctxt: the XInclude context
112 *
113 * Free an XInclude context
114 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000115static void
Owen Taylor3473f882001-02-23 17:55:21 +0000116xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
117 int i;
118
119 if (ctxt == NULL)
120 return;
121 for (i = 0;i < ctxt->docNr;i++) {
122 xmlFreeDoc(ctxt->docTab[i]);
123 if (ctxt->urlTab[i] != NULL)
124 xmlFree(ctxt->urlTab[i]);
125 }
126 for (i = 0;i < ctxt->txtNr;i++) {
127 if (ctxt->txturlTab[i] != NULL)
128 xmlFree(ctxt->txturlTab[i]);
129 }
130 if (ctxt->incTab != NULL)
131 xmlFree(ctxt->incTab);
132 if (ctxt->repTab != NULL)
133 xmlFree(ctxt->repTab);
134 if (ctxt->urlTab != NULL)
135 xmlFree(ctxt->urlTab);
136 if (ctxt->docTab != NULL)
137 xmlFree(ctxt->docTab);
138 if (ctxt->txtTab != NULL)
139 xmlFree(ctxt->txtTab);
140 if (ctxt->txturlTab != NULL)
141 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000142 xmlFree(ctxt);
143}
144
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000145/**
146 * xmlXIncludeAddNode:
147 * @ctxt: the XInclude context
148 * @node: the new node
149 *
150 * Add a new node to process to an XInclude context
151 */
152static void
153xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
154 if (ctxt->incMax == 0) {
155 ctxt->incMax = 4;
156 ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
157 sizeof(ctxt->incTab[0]));
158 if (ctxt->incTab == NULL) {
159 xmlGenericError(xmlGenericErrorContext,
160 "malloc failed !\n");
161 return;
162 }
163 ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
164 sizeof(ctxt->repTab[0]));
165 if (ctxt->repTab == NULL) {
166 xmlGenericError(xmlGenericErrorContext,
167 "malloc failed !\n");
168 return;
169 }
170 }
171 if (ctxt->incNr >= ctxt->incMax) {
172 ctxt->incMax *= 2;
173 ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
174 ctxt->incMax * sizeof(ctxt->incTab[0]));
175 if (ctxt->incTab == NULL) {
176 xmlGenericError(xmlGenericErrorContext,
177 "realloc failed !\n");
178 return;
179 }
180 ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
181 ctxt->incMax * sizeof(ctxt->repTab[0]));
182 if (ctxt->repTab == NULL) {
183 xmlGenericError(xmlGenericErrorContext,
184 "realloc failed !\n");
185 return;
186 }
187 }
188 ctxt->incTab[ctxt->incNr] = node;
189 ctxt->repTab[ctxt->incNr] = NULL;
190 ctxt->incNr++;
191}
192
193/**
194 * xmlXIncludeAddDoc:
195 * @ctxt: the XInclude context
196 * @doc: the new document
197 * @url: the associated URL
198 *
199 * Add a new document to the list. The XInclude recursive nature is handled
200 * at this point.
201 */
202static void
203xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url) {
204 xmlXIncludeCtxtPtr newctxt;
205 int i;
206
207 if (ctxt->docMax == 0) {
208 ctxt->docMax = 4;
209 ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
210 sizeof(ctxt->docTab[0]));
211 if (ctxt->docTab == NULL) {
212 xmlGenericError(xmlGenericErrorContext,
213 "malloc failed !\n");
214 return;
215 }
216 ctxt->urlTab = (xmlURL *) xmlMalloc(ctxt->docMax *
217 sizeof(ctxt->urlTab[0]));
218 if (ctxt->urlTab == NULL) {
219 xmlGenericError(xmlGenericErrorContext,
220 "malloc failed !\n");
221 return;
222 }
223 }
224 if (ctxt->docNr >= ctxt->docMax) {
225 ctxt->docMax *= 2;
226 ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
227 ctxt->docMax * sizeof(ctxt->docTab[0]));
228 if (ctxt->docTab == NULL) {
229 xmlGenericError(xmlGenericErrorContext,
230 "realloc failed !\n");
231 return;
232 }
233 ctxt->urlTab = (xmlURL *) xmlRealloc(ctxt->urlTab,
234 ctxt->docMax * sizeof(ctxt->urlTab[0]));
235 if (ctxt->urlTab == NULL) {
236 xmlGenericError(xmlGenericErrorContext,
237 "realloc failed !\n");
238 return;
239 }
240 }
241 ctxt->docTab[ctxt->docNr] = doc;
242 ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
243 ctxt->docNr++;
244
245 /*
246 * Handle recursion here.
247 */
248
249 newctxt = xmlXIncludeNewContext(doc);
250 if (newctxt != NULL) {
251 /*
252 * Copy the existing document set
253 */
254 newctxt->docMax = ctxt->docMax;
255 newctxt->docNr = ctxt->docNr;
256 newctxt->docTab = (xmlDocPtr *) xmlMalloc(newctxt->docMax *
257 sizeof(newctxt->docTab[0]));
258 if (newctxt->docTab == NULL) {
259 xmlGenericError(xmlGenericErrorContext,
260 "malloc failed !\n");
261 xmlFree(newctxt);
262 return;
263 }
264 newctxt->urlTab = (xmlURL *) xmlMalloc(newctxt->docMax *
265 sizeof(newctxt->urlTab[0]));
266 if (ctxt->urlTab == NULL) {
267 xmlGenericError(xmlGenericErrorContext,
268 "malloc failed !\n");
269 xmlFree(newctxt);
270 return;
271 }
272
273 for (i = 0;i < ctxt->docNr;i++) {
274 newctxt->docTab[i] = ctxt->docTab[i];
275 newctxt->urlTab[i] = ctxt->urlTab[i];
276 }
277 xmlXIncludeDoProcess(newctxt, doc);
278 for (i = 0;i < ctxt->docNr;i++) {
279 newctxt->docTab[i] = NULL;
280 newctxt->urlTab[i] = NULL;
281 }
282 xmlXIncludeFreeContext(newctxt);
283 }
284}
285
286/**
287 * xmlXIncludeAddTxt:
288 * @ctxt: the XInclude context
289 * @txt: the new text node
290 * @url: the associated URL
291 *
292 * Add a new txtument to the list
293 */
294static void
295xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
296 if (ctxt->txtMax == 0) {
297 ctxt->txtMax = 4;
298 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
299 sizeof(ctxt->txtTab[0]));
300 if (ctxt->txtTab == NULL) {
301 xmlGenericError(xmlGenericErrorContext,
302 "malloc failed !\n");
303 return;
304 }
305 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
306 sizeof(ctxt->txturlTab[0]));
307 if (ctxt->txturlTab == NULL) {
308 xmlGenericError(xmlGenericErrorContext,
309 "malloc failed !\n");
310 return;
311 }
312 }
313 if (ctxt->txtNr >= ctxt->txtMax) {
314 ctxt->txtMax *= 2;
315 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
316 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
317 if (ctxt->txtTab == NULL) {
318 xmlGenericError(xmlGenericErrorContext,
319 "realloc failed !\n");
320 return;
321 }
322 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
323 ctxt->txtMax * sizeof(ctxt->urlTab[0]));
324 if (ctxt->txturlTab == NULL) {
325 xmlGenericError(xmlGenericErrorContext,
326 "realloc failed !\n");
327 return;
328 }
329 }
330 ctxt->txtTab[ctxt->txtNr] = txt;
331 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
332 ctxt->txtNr++;
333}
334
Owen Taylor3473f882001-02-23 17:55:21 +0000335/************************************************************************
336 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000337 * Node copy with specific semantic *
338 * *
339 ************************************************************************/
340
341/**
342 * xmlXIncludeCopyNode:
343 * @ctxt: the XInclude context
344 * @target: the document target
345 * @source: the document source
346 * @elem: the element
347 *
348 * Make a copy of the node while preserving the XInclude semantic
349 * of the Infoset copy
350 */
351static xmlNodePtr
352xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
353 xmlDocPtr source, xmlNodePtr elem) {
354 xmlNodePtr result = NULL;
355
356 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
357 (elem == NULL))
358 return(NULL);
359 if (elem->type == XML_DTD_NODE)
360 return(NULL);
361 result = xmlDocCopyNode(elem, target, 1);
362 return(result);
363}
364
365/**
366 * xmlXIncludeCopyNodeList:
367 * @ctxt: the XInclude context
368 * @target: the document target
369 * @source: the document source
370 * @elem: the element list
371 *
372 * Make a copy of the node list while preserving the XInclude semantic
373 * of the Infoset copy
374 */
375static xmlNodePtr
376xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
377 xmlDocPtr source, xmlNodePtr elem) {
378 xmlNodePtr cur, res, result = NULL, last = NULL;
379
380 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
381 (elem == NULL))
382 return(NULL);
383 cur = elem;
384 while (cur != NULL) {
385 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
386 if (res != NULL) {
387 if (result == NULL) {
388 result = last = res;
389 } else {
390 last->next = res;
391 res->prev = last;
392 last = res;
393 }
394 }
395 cur = cur->next;
396 }
397 return(result);
398}
399
400/**
401 * xmlXInclueGetNthChild:
402 * @cur: the node
403 * @no: the child number
404 *
405 * Returns the @no'th element child of @cur or NULL
406 */
407static xmlNodePtr
408xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
409 int i;
410 if (cur == NULL)
411 return(cur);
412 cur = cur->children;
413 for (i = 0;i <= no;cur = cur->next) {
414 if (cur == NULL)
415 return(cur);
416 if ((cur->type == XML_ELEMENT_NODE) ||
417 (cur->type == XML_DOCUMENT_NODE) ||
418 (cur->type == XML_HTML_DOCUMENT_NODE)) {
419 i++;
420 if (i == no)
421 break;
422 }
423 }
424 return(cur);
425}
426
427xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
428
429/**
430 * xmlXIncludeCopyRange:
431 * @ctxt: the XInclude context
432 * @target: the document target
433 * @source: the document source
434 * @obj: the XPointer result from the evaluation.
435 *
436 * Build a node list tree copy of the XPointer result.
437 *
438 * Returns an xmlNodePtr list or NULL.
439 * the caller has to free the node tree.
440 */
441static xmlNodePtr
442xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
443 xmlDocPtr source, xmlXPathObjectPtr range) {
444 /* pointers to generated nodes */
445 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
446 /* pointers to traversal nodes */
447 xmlNodePtr start, cur, end;
448 int index1, index2;
449
450 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
451 (range == NULL))
452 return(NULL);
453 if (range->type != XPATH_RANGE)
454 return(NULL);
455 start = (xmlNodePtr) range->user;
456
457 if (start == NULL)
458 return(NULL);
459 end = range->user2;
460 if (end == NULL)
461 return(xmlDocCopyNode(start, target, 1));
462
463 cur = start;
464 index1 = range->index;
465 index2 = range->index2;
466 while (cur != NULL) {
467 if (cur == end) {
468 if (cur->type == XML_TEXT_NODE) {
469 const xmlChar *content = cur->content;
470 int len;
471
472 if (content == NULL) {
473 tmp = xmlNewTextLen(NULL, 0);
474 } else {
475 len = index2;
476 if ((cur == start) && (index1 > 1)) {
477 content += (index1 - 1);
478 len -= (index1 - 1);
479 index1 = 0;
480 } else {
481 len = index2;
482 }
483 tmp = xmlNewTextLen(content, len);
484 }
485 /* single sub text node selection */
486 if (list == NULL)
487 return(tmp);
488 /* prune and return full set */
489 if (last != NULL)
490 xmlAddNextSibling(last, tmp);
491 else
492 xmlAddChild(parent, tmp);
493 return(list);
494 } else {
495 tmp = xmlDocCopyNode(cur, target, 0);
496 if (list == NULL)
497 list = tmp;
498 else {
499 if (last != NULL)
500 xmlAddNextSibling(last, tmp);
501 else
502 xmlAddChild(parent, tmp);
503 }
504 last = NULL;
505 parent = tmp;
506
507 if (index2 > 1) {
508 end = xmlXIncludeGetNthChild(cur, index2 - 1);
509 index2 = 0;
510 }
511 if ((cur == start) && (index1 > 1)) {
512 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
513 index1 = 0;
514 } else {
515 cur = cur->children;
516 }
517 /*
518 * Now gather the remaining nodes from cur to end
519 */
520 continue; /* while */
521 }
522 } else if ((cur == start) &&
523 (list == NULL) /* looks superfluous but ... */ ) {
524 if ((cur->type == XML_TEXT_NODE) ||
525 (cur->type == XML_CDATA_SECTION_NODE)) {
526 const xmlChar *content = cur->content;
527
528 if (content == NULL) {
529 tmp = xmlNewTextLen(NULL, 0);
530 } else {
531 if (index1 > 1) {
532 content += (index1 - 1);
533 }
534 tmp = xmlNewText(content);
535 }
536 last = list = tmp;
537 } else {
538 if ((cur == start) && (index1 > 1)) {
539 tmp = xmlDocCopyNode(cur, target, 0);
540 list = tmp;
541 parent = tmp;
542 last = NULL;
543 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
544 index1 = 0;
545 /*
546 * Now gather the remaining nodes from cur to end
547 */
548 continue; /* while */
549 }
550 tmp = xmlDocCopyNode(cur, target, 1);
551 list = tmp;
552 parent = NULL;
553 last = tmp;
554 }
555 } else {
556 tmp = NULL;
557 switch (cur->type) {
558 case XML_DTD_NODE:
559 case XML_ELEMENT_DECL:
560 case XML_ATTRIBUTE_DECL:
561 case XML_ENTITY_NODE:
562 /* Do not copy DTD informations */
563 break;
564 case XML_ENTITY_DECL:
565 /* handle crossing entities -> stack needed */
566 break;
567 case XML_XINCLUDE_START:
568 case XML_XINCLUDE_END:
569 /* don't consider it part of the tree content */
570 break;
571 case XML_ATTRIBUTE_NODE:
572 /* Humm, should not happen ! */
573 break;
574 default:
575 tmp = xmlDocCopyNode(cur, target, 1);
576 break;
577 }
578 if (tmp != NULL) {
579 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
580 return(NULL);
581 }
582 if (last != NULL)
583 xmlAddNextSibling(last, tmp);
584 else {
585 xmlAddChild(parent, tmp);
586 last = tmp;
587 }
588 }
589 }
590 /*
591 * Skip to next node in document order
592 */
593 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
594 return(NULL);
595 }
596 cur = xmlXPtrAdvanceNode(cur);
597 }
598 return(list);
599}
600
601/**
602 * xmlXIncludeBuildNodeList:
603 * @ctxt: the XInclude context
604 * @target: the document target
605 * @source: the document source
606 * @obj: the XPointer result from the evaluation.
607 *
608 * Build a node list tree copy of the XPointer result.
609 * This will drop Attributes and Namespace declarations.
610 *
611 * Returns an xmlNodePtr list or NULL.
612 * the caller has to free the node tree.
613 */
614static xmlNodePtr
615xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
616 xmlDocPtr source, xmlXPathObjectPtr obj) {
617 xmlNodePtr list = NULL, last = NULL;
618 int i;
619
620 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
621 (obj == NULL))
622 return(NULL);
623 switch (obj->type) {
624 case XPATH_NODESET: {
625 xmlNodeSetPtr set = obj->nodesetval;
626 if (set == NULL)
627 return(NULL);
628 for (i = 0;i < set->nodeNr;i++) {
629 if (set->nodeTab[i] == NULL)
630 continue;
631 switch (set->nodeTab[i]->type) {
632 case XML_TEXT_NODE:
633 case XML_CDATA_SECTION_NODE:
634 case XML_ELEMENT_NODE:
635 case XML_ENTITY_REF_NODE:
636 case XML_ENTITY_NODE:
637 case XML_PI_NODE:
638 case XML_COMMENT_NODE:
639 case XML_DOCUMENT_NODE:
640 case XML_HTML_DOCUMENT_NODE:
641#ifdef LIBXML_DOCB_ENABLED
642 case XML_DOCB_DOCUMENT_NODE:
643#endif
644 case XML_XINCLUDE_START:
645 case XML_XINCLUDE_END:
646 break;
647 case XML_ATTRIBUTE_NODE:
648 case XML_NAMESPACE_DECL:
649 case XML_DOCUMENT_TYPE_NODE:
650 case XML_DOCUMENT_FRAG_NODE:
651 case XML_NOTATION_NODE:
652 case XML_DTD_NODE:
653 case XML_ELEMENT_DECL:
654 case XML_ATTRIBUTE_DECL:
655 case XML_ENTITY_DECL:
656 continue; /* for */
657 }
658 if (last == NULL)
659 list = last = xmlXIncludeCopyNode(ctxt, target, source,
660 set->nodeTab[i]);
661 else {
662 xmlAddNextSibling(last,
663 xmlXIncludeCopyNode(ctxt, target, source,
664 set->nodeTab[i]));
665 if (last->next != NULL)
666 last = last->next;
667 }
668 }
669 break;
670 }
671 case XPATH_LOCATIONSET: {
672 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
673 if (set == NULL)
674 return(NULL);
675 for (i = 0;i < set->locNr;i++) {
676 if (last == NULL)
677 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
678 set->locTab[i]);
679 else
680 xmlAddNextSibling(last,
681 xmlXIncludeCopyXPointer(ctxt, target, source,
682 set->locTab[i]));
683 if (last != NULL) {
684 while (last->next != NULL)
685 last = last->next;
686 }
687 }
688 break;
689 }
690 case XPATH_RANGE:
691 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
692 case XPATH_POINT:
693 /* points are ignored in XInclude */
694 break;
695 default:
696 break;
697 }
698 return(list);
699}
700/************************************************************************
701 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000702 * XInclude I/O handling *
703 * *
704 ************************************************************************/
705
706/**
707 * xmlXIncludeLoadDoc:
708 * @ctxt: the XInclude context
709 * @url: the associated URL
710 * @nr: the xinclude node number
711 *
712 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000713 *
714 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000715 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000716static int
Owen Taylor3473f882001-02-23 17:55:21 +0000717xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
718 xmlDocPtr doc;
719 xmlURIPtr uri;
720 xmlChar *URL;
721 xmlChar *fragment = NULL;
722 int i;
723 /*
724 * Check the URL and remove any fragment identifier
725 */
726 uri = xmlParseURI((const char *)url);
727 if (uri == NULL) {
728 xmlGenericError(xmlGenericErrorContext,
729 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000730 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000731 }
732 if (uri->fragment != NULL) {
733 fragment = (xmlChar *) uri->fragment;
734 uri->fragment = NULL;
735 }
736 URL = xmlSaveUri(uri);
737 xmlFreeURI(uri);
738 if (URL == NULL) {
739 xmlGenericError(xmlGenericErrorContext,
740 "XInclude: invalid value URI %s\n", url);
741 if (fragment != NULL)
742 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000743 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000744 }
745
746 /*
747 * Handling of references to the local document are done
748 * directly through ctxt->doc.
749 */
750 if ((URL[0] == 0) || (URL[0] == '#')) {
751 doc = NULL;
752 goto loaded;
753 }
754
755 /*
756 * Prevent reloading twice the document.
757 */
758 for (i = 0; i < ctxt->docNr; i++) {
759 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
760 doc = ctxt->docTab[i];
761 goto loaded;
762 }
763 }
764 /*
765 * Load it.
766 */
767 doc = xmlParseFile((const char *)URL);
768 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000769 xmlFree(URL);
770 if (fragment != NULL)
771 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000772 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000773 }
774 xmlXIncludeAddDoc(ctxt, doc, URL);
775
776loaded:
777 if (fragment == NULL) {
778 /*
779 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +0000780 */
781 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +0000782 {
783 /* Hopefully a DTD declaration won't be copied from
784 * the same document */
Owen Taylor3473f882001-02-23 17:55:21 +0000785 ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000786 } else {
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000787 ctxt->repTab[nr] = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
788 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000789 }
Owen Taylor3473f882001-02-23 17:55:21 +0000790 } else {
791 /*
792 * Computes the XPointer expression and make a copy used
793 * as the replacement copy.
794 */
795 xmlXPathObjectPtr xptr;
796 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +0000797 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +0000798
799 if (doc == NULL) {
800 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
801 } else {
802 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
803 }
804 if (xptrctxt == NULL) {
805 xmlGenericError(xmlGenericErrorContext,
806 "XInclude: could create XPointer context\n");
807 xmlFree(URL);
808 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000809 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000810 }
811 xptr = xmlXPtrEval(fragment, xptrctxt);
812 if (xptr == NULL) {
813 xmlGenericError(xmlGenericErrorContext,
814 "XInclude: XPointer evaluation failed: #%s\n",
815 fragment);
816 xmlXPathFreeContext(xptrctxt);
817 xmlFree(URL);
818 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000819 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000820 }
Daniel Veillard39196eb2001-06-19 18:09:42 +0000821 switch (xptr->type) {
822 case XPATH_UNDEFINED:
823 case XPATH_BOOLEAN:
824 case XPATH_NUMBER:
825 case XPATH_STRING:
826 case XPATH_POINT:
827 case XPATH_USERS:
828 case XPATH_XSLT_TREE:
829 xmlGenericError(xmlGenericErrorContext,
830 "XInclude: XPointer is not a range: #%s\n",
831 fragment);
832 xmlXPathFreeContext(xptrctxt);
833 xmlFree(URL);
834 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000835 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +0000836 case XPATH_NODESET:
837 case XPATH_RANGE:
838 case XPATH_LOCATIONSET:
839 break;
840 }
841 set = xptr->nodesetval;
842 if (set != NULL) {
843 for (i = 0;i < set->nodeNr;i++) {
844 if (set->nodeTab[i] == NULL)
845 continue;
846 switch (set->nodeTab[i]->type) {
847 case XML_TEXT_NODE:
848 case XML_CDATA_SECTION_NODE:
849 case XML_ELEMENT_NODE:
850 case XML_ENTITY_REF_NODE:
851 case XML_ENTITY_NODE:
852 case XML_PI_NODE:
853 case XML_COMMENT_NODE:
854 case XML_DOCUMENT_NODE:
855 case XML_HTML_DOCUMENT_NODE:
856#ifdef LIBXML_DOCB_ENABLED
857 case XML_DOCB_DOCUMENT_NODE:
858#endif
859 continue;
860 case XML_ATTRIBUTE_NODE:
861 xmlGenericError(xmlGenericErrorContext,
862 "XInclude: XPointer selects an attribute: #%s\n",
863 fragment);
864 set->nodeTab[i] = NULL;
865 continue;
866 case XML_NAMESPACE_DECL:
867 xmlGenericError(xmlGenericErrorContext,
868 "XInclude: XPointer selects a namespace: #%s\n",
869 fragment);
870 set->nodeTab[i] = NULL;
871 continue;
872 case XML_DOCUMENT_TYPE_NODE:
873 case XML_DOCUMENT_FRAG_NODE:
874 case XML_NOTATION_NODE:
875 case XML_DTD_NODE:
876 case XML_ELEMENT_DECL:
877 case XML_ATTRIBUTE_DECL:
878 case XML_ENTITY_DECL:
879 case XML_XINCLUDE_START:
880 case XML_XINCLUDE_END:
881 xmlGenericError(xmlGenericErrorContext,
882 "XInclude: XPointer selects unexpected nodes: #%s\n",
883 fragment);
884 set->nodeTab[i] = NULL;
885 set->nodeTab[i] = NULL;
886 continue; /* for */
887 }
888 }
889 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000890 ctxt->repTab[nr] = xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
Owen Taylor3473f882001-02-23 17:55:21 +0000891 xmlXPathFreeObject(xptr);
892 xmlXPathFreeContext(xptrctxt);
893 xmlFree(fragment);
894 }
895 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000896 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +0000897}
898
899/**
900 * xmlXIncludeLoadTxt:
901 * @ctxt: the XInclude context
902 * @url: the associated URL
903 * @nr: the xinclude node number
904 *
905 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000906 *
907 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000908 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000909static int
Owen Taylor3473f882001-02-23 17:55:21 +0000910xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
911 xmlParserInputBufferPtr buf;
912 xmlNodePtr node;
913 xmlURIPtr uri;
914 xmlChar *URL;
915 int i;
916 /*
917 * Check the URL and remove any fragment identifier
918 */
919 uri = xmlParseURI((const char *)url);
920 if (uri == NULL) {
921 xmlGenericError(xmlGenericErrorContext,
922 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000923 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000924 }
925 if (uri->fragment != NULL) {
926 xmlGenericError(xmlGenericErrorContext,
927 "XInclude: fragment identifier forbidden for text: %s\n",
928 uri->fragment);
929 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000930 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000931 }
932 URL = xmlSaveUri(uri);
933 xmlFreeURI(uri);
934 if (URL == NULL) {
935 xmlGenericError(xmlGenericErrorContext,
936 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000937 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000938 }
939
940 /*
941 * Handling of references to the local document are done
942 * directly through ctxt->doc.
943 */
944 if (URL[0] == 0) {
945 xmlGenericError(xmlGenericErrorContext,
946 "XInclude: text serialization of document not available\n");
947 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000948 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000949 }
950
951 /*
952 * Prevent reloading twice the document.
953 */
954 for (i = 0; i < ctxt->txtNr; i++) {
955 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
956 node = xmlCopyNode(ctxt->txtTab[i], 1);
957 goto loaded;
958 }
959 }
960 /*
961 * Load it.
962 * Issue 62: how to detect the encoding
963 */
964 buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
965 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000966 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000967 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000968 }
969 node = xmlNewText(NULL);
970
971 /*
972 * Scan all chars from the resource and add the to the node
973 */
974 while (xmlParserInputBufferRead(buf, 128) > 0) {
975 int len;
976 const xmlChar *content;
977
978 content = xmlBufferContent(buf->buffer);
979 len = xmlBufferLength(buf->buffer);
980 for (i = 0;i < len; i++) {
981 /*
982 * TODO: if the encoding issue is solved, scan UTF8 chars instead
983 */
984 if (!IS_CHAR(content[i])) {
985 xmlGenericError(xmlGenericErrorContext,
986 "XInclude: %s contains invalid char %d\n", URL, content[i]);
987 } else {
988 xmlNodeAddContentLen(node, &content[i], 1);
989 }
990 }
991 xmlBufferShrink(buf->buffer, len);
992 }
993 xmlFreeParserInputBuffer(buf);
994 xmlXIncludeAddTxt(ctxt, node, URL);
995
996loaded:
997 /*
998 * Add the element as the replacement copy.
999 */
1000 ctxt->repTab[nr] = node;
1001 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001002 return(0);
1003}
1004
1005/**
1006 * xmlXIncludeLoadFallback:
1007 * @ctxt: the XInclude context
1008 * @fallback: the fallback node
1009 * @nr: the xinclude node number
1010 *
1011 * Load the content of teh fallback node, and store the result
1012 * in the XInclude context
1013 *
1014 * Returns 0 in case of success, -1 in case of failure
1015 */
1016static int
1017xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1018 if ((fallback == NULL) || (ctxt == NULL))
1019 return(-1);
1020
1021 ctxt->repTab[nr] = xmlCopyNode(fallback->children, 1);
1022 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001023}
1024
1025/************************************************************************
1026 * *
1027 * XInclude Processing *
1028 * *
1029 ************************************************************************/
1030
1031/**
1032 * xmlXIncludePreProcessNode:
1033 * @ctxt: an XInclude context
1034 * @node: an XInclude node
1035 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001036 * Implement the XInclude preprocessing, currently just adding the element
1037 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001038 *
1039 * Returns the result list or NULL in case of error
1040 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001041static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001042xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1043 xmlXIncludeAddNode(ctxt, node);
1044 return(0);
1045}
1046
1047/**
1048 * xmlXIncludeLoadNode:
1049 * @ctxt: an XInclude context
1050 * @nr: the node number
1051 *
1052 * Find and load the infoset replacement for the given node.
1053 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001054 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001055 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001056static int
Owen Taylor3473f882001-02-23 17:55:21 +00001057xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1058 xmlNodePtr cur;
1059 xmlChar *href;
1060 xmlChar *parse;
1061 xmlChar *base;
1062 xmlChar *URI;
1063 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001064 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001065
1066 if (ctxt == NULL)
1067 return(-1);
1068 if ((nr < 0) || (nr >= ctxt->incNr))
1069 return(-1);
1070 cur = ctxt->incTab[nr];
1071 if (cur == NULL)
1072 return(-1);
1073
1074#ifdef DEBUG_XINCLUDE
1075 xmlDebugDumpNode(stdout, cur, 0);
1076#endif
1077 /*
1078 * read the attributes
1079 */
1080 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1081 if (href == NULL) {
1082 href = xmlGetProp(cur, XINCLUDE_HREF);
1083 if (href == NULL) {
1084 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1085 return(-1);
1086 }
1087 }
1088 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1089 if (parse == NULL) {
1090 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1091 }
1092 if (parse != NULL) {
1093 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1094 xml = 1;
1095 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1096 xml = 0;
1097 else {
1098 xmlGenericError(xmlGenericErrorContext,
1099 "XInclude: invalid value %s for %s\n",
1100 parse, XINCLUDE_PARSE);
1101 if (href != NULL)
1102 xmlFree(href);
1103 if (parse != NULL)
1104 xmlFree(parse);
1105 return(-1);
1106 }
1107 }
1108
1109 /*
1110 * compute the URI
1111 */
1112 base = xmlNodeGetBase(ctxt->doc, cur);
1113 if (base == NULL) {
1114 URI = xmlBuildURI(href, ctxt->doc->URL);
1115 } else {
1116 URI = xmlBuildURI(href, base);
1117 }
1118 if (URI == NULL) {
1119 xmlChar *escbase;
1120 xmlChar *eschref;
1121 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001122 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001123 */
1124 escbase = xmlURIEscape(base);
1125 eschref = xmlURIEscape(href);
1126 URI = xmlBuildURI(eschref, escbase);
1127 if (escbase != NULL)
1128 xmlFree(escbase);
1129 if (eschref != NULL)
1130 xmlFree(eschref);
1131 }
1132 if (URI == NULL) {
1133 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1134 if (parse != NULL)
1135 xmlFree(parse);
1136 if (href != NULL)
1137 xmlFree(href);
1138 if (base != NULL)
1139 xmlFree(base);
1140 return(-1);
1141 }
1142#ifdef DEBUG_XINCLUDE
1143 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1144 xml ? "xml": "text");
1145 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1146#endif
1147
1148 /*
1149 * Cleanup
1150 */
1151 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001152 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001153 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1154 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001155 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1156 }
1157 if (ret < 0) {
1158 xmlNodePtr children;
1159
1160 /*
1161 * Time to try a fallback if availble
1162 */
1163#ifdef DEBUG_XINCLUDE
1164 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1165#endif
1166 children = cur->children;
1167 while (children != NULL) {
1168 if ((children->type == XML_ELEMENT_NODE) &&
1169 (children->ns != NULL) &&
1170 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1171 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1172 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1173 if (ret == 0)
1174 break;
1175 }
1176 children = children->next;
1177 }
1178 }
1179 if (ret < 0) {
1180 xmlGenericError(xmlGenericErrorContext,
1181 "XInclude: could not load %s, and no fallback was found\n",
1182 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001183 }
1184
1185 /*
1186 * Cleanup
1187 */
1188 if (URI != NULL)
1189 xmlFree(URI);
1190 if (parse != NULL)
1191 xmlFree(parse);
1192 if (href != NULL)
1193 xmlFree(href);
1194 if (base != NULL)
1195 xmlFree(base);
1196 return(0);
1197}
1198
1199/**
1200 * xmlXIncludeIncludeNode:
1201 * @ctxt: an XInclude context
1202 * @nr: the node number
1203 *
1204 * Inplement the infoset replacement for the given node
1205 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001206 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001207 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001208static int
Owen Taylor3473f882001-02-23 17:55:21 +00001209xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1210 xmlNodePtr cur, end, list;
1211
1212 if (ctxt == NULL)
1213 return(-1);
1214 if ((nr < 0) || (nr >= ctxt->incNr))
1215 return(-1);
1216 cur = ctxt->incTab[nr];
1217 if (cur == NULL)
1218 return(-1);
1219
1220 /*
1221 * Change the current node as an XInclude start one, and add an
1222 * entity end one
1223 */
1224 cur->type = XML_XINCLUDE_START;
1225 end = xmlNewNode(cur->ns, cur->name);
1226 if (end == NULL) {
1227 xmlGenericError(xmlGenericErrorContext,
1228 "XInclude: failed to build node\n");
1229 return(-1);
1230 }
1231 end->type = XML_XINCLUDE_END;
1232 xmlAddNextSibling(cur, end);
1233
1234 /*
1235 * Add the list of nodes
1236 */
1237 list = ctxt->repTab[nr];
1238 ctxt->repTab[nr] = NULL;
1239 while (list != NULL) {
1240 cur = list;
1241 list = list->next;
1242
1243 xmlAddPrevSibling(end, cur);
1244 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001245
1246
Owen Taylor3473f882001-02-23 17:55:21 +00001247 return(0);
1248}
1249
1250/**
1251 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +00001252 * @node: an XInclude node
1253 *
1254 * test if the node is an XInclude node
1255 *
1256 * Returns 1 true, 0 otherwise
1257 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001258static int
1259xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001260 if (node == NULL)
1261 return(0);
1262 if (node->ns == NULL)
1263 return(0);
1264 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
1265 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
1266 return(0);
1267}
1268
1269/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001270 * xmlXIncludeDoProcess:
1271 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +00001272 * @doc: an XML document
1273 *
1274 * Implement the XInclude substitution on the XML document @doc
1275 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001276 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001277 * or the number of substitutions done.
1278 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001279static int
1280xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001281 xmlNodePtr cur;
1282 int ret = 0;
1283 int i;
1284
1285 if (doc == NULL)
1286 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001287 if (ctxt == NULL)
1288 return(-1);
1289
1290 /*
1291 * First phase: lookup the elements in the document
1292 */
1293 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001294 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001295 xmlXIncludePreProcessNode(ctxt, cur);
1296 while (cur != NULL) {
1297 /* TODO: need to work on entities -> stack */
1298 if ((cur->children != NULL) &&
1299 (cur->children->type != XML_ENTITY_DECL)) {
1300 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001301 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001302 xmlXIncludePreProcessNode(ctxt, cur);
1303 } else if (cur->next != NULL) {
1304 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001305 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001306 xmlXIncludePreProcessNode(ctxt, cur);
1307 } else {
1308 do {
1309 cur = cur->parent;
1310 if (cur == NULL) break; /* do */
1311 if (cur->next != NULL) {
1312 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001313 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001314 xmlXIncludePreProcessNode(ctxt, cur);
1315 break; /* do */
1316 }
1317 } while (cur != NULL);
1318 }
1319 }
1320
1321 /*
1322 * Second Phase : collect the infosets fragments
1323 */
1324 for (i = 0;i < ctxt->incNr; i++) {
1325 xmlXIncludeLoadNode(ctxt, i);
1326 }
1327
1328 /*
1329 * Third phase: extend the original document infoset.
1330 */
1331 for (i = 0;i < ctxt->incNr; i++) {
1332 xmlXIncludeIncludeNode(ctxt, i);
1333 }
1334
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001335 return(ret);
1336}
1337
1338/**
1339 * xmlXIncludeProcess:
1340 * @doc: an XML document
1341 *
1342 * Implement the XInclude substitution on the XML document @doc
1343 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001344 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001345 * or the number of substitutions done.
1346 */
1347int
1348xmlXIncludeProcess(xmlDocPtr doc) {
1349 xmlXIncludeCtxtPtr ctxt;
1350 int ret = 0;
1351
1352 if (doc == NULL)
1353 return(-1);
1354 ctxt = xmlXIncludeNewContext(doc);
1355 if (ctxt == NULL)
1356 return(-1);
1357 ret = xmlXIncludeDoProcess(ctxt, doc);
1358
Owen Taylor3473f882001-02-23 17:55:21 +00001359 xmlXIncludeFreeContext(ctxt);
1360 return(ret);
1361}
1362
1363#else /* !LIBXML_XINCLUDE_ENABLED */
1364#endif