Annotation of XML/xinclude.c, revision 1.4
1.1 veillard 1: /*
2: * xinclude.c : Code to implement XInclude processing
3: *
4: * World Wide Web Consortium Working Draft 26 October 2000
5: * http://www.w3.org/TR/2000/WD-xinclude-20001026
6: *
7: * See Copyright for the status of this software.
8: *
9: * Daniel.Veillard@w3.org
10: */
11:
12: /*
1.4 ! veillard 13: * TODO: compute XPointers nodesets
1.1 veillard 14: */
15:
16: #ifdef WIN32
17: #include "win32config.h"
18: #else
19: #include "config.h"
20: #endif
21:
22: #include <stdio.h>
23: #include <string.h>
24: #include <libxml/xmlmemory.h>
25: #include <libxml/tree.h>
26: #include <libxml/parser.h>
27: #include <libxml/uri.h>
28: #include <libxml/xpointer.h>
1.2 veillard 29: #include <libxml/parserInternals.h>
1.1 veillard 30: #ifdef LIBXML_DEBUG_ENABLED
31: #include <libxml/debugXML.h>
32: #endif
33: #include <libxml/xmlerror.h>
34:
35: #ifdef LIBXML_XINCLUDE_ENABLED
36: #include <libxml/xinclude.h>
37:
38: #define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/1999/XML/xinclude"
39: #define XINCLUDE_NODE (const xmlChar *) "include"
40: #define XINCLUDE_HREF (const xmlChar *) "href"
41: #define XINCLUDE_PARSE (const xmlChar *) "parse"
1.2 veillard 42: #define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
43: #define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
1.1 veillard 44:
1.4 ! veillard 45: /* #define DEBUG_XINCLUDE */
1.1 veillard 46:
1.2 veillard 47: /************************************************************************
48: * *
49: * XInclude contexts handling *
50: * *
51: ************************************************************************/
52:
1.1 veillard 53: /*
54: * An XInclude context
55: */
56: typedef xmlChar *URL;
57: typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
58: typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
59: struct _xmlXIncludeCtxt {
60: xmlDocPtr doc; /* the source document */
61: int incNr; /* number of includes */
62: int incMax; /* size of includes tab */
63: xmlNodePtr *incTab; /* array of include nodes */
64: xmlNodePtr *repTab; /* array of replacement node lists */
1.2 veillard 65: int docNr; /* number of parsed documents */
66: int docMax; /* size of parsed documents tab */
67: xmlDocPtr *docTab; /* array of parsed documents */
68: URL *urlTab; /* array of parsed documents URLs */
69: int txtNr; /* number of unparsed documents */
70: int txtMax; /* size of unparsed documents tab */
71: xmlNodePtr *txtTab; /* array of unparsed text nodes */
72: URL *txturlTab; /* array of unparsed txtuments URLs */
1.1 veillard 73: };
74:
75: /**
76: * xmlXIncludeAddNode:
77: * @ctxt: the XInclude context
78: * @node: the new node
79: *
80: * Add a new node to process to an XInclude context
81: */
82: void
83: xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
84: if (ctxt->incMax == 0) {
85: ctxt->incMax = 4;
86: ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
87: sizeof(ctxt->incTab[0]));
88: if (ctxt->incTab == NULL) {
89: xmlGenericError(xmlGenericErrorContext,
90: "malloc failed !\n");
91: return;
92: }
93: ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
94: sizeof(ctxt->repTab[0]));
95: if (ctxt->repTab == NULL) {
96: xmlGenericError(xmlGenericErrorContext,
97: "malloc failed !\n");
98: return;
99: }
100: }
101: if (ctxt->incNr >= ctxt->incMax) {
102: ctxt->incMax *= 2;
103: ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
104: ctxt->incMax * sizeof(ctxt->incTab[0]));
105: if (ctxt->incTab == NULL) {
106: xmlGenericError(xmlGenericErrorContext,
107: "realloc failed !\n");
108: return;
109: }
110: ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
111: ctxt->incMax * sizeof(ctxt->repTab[0]));
112: if (ctxt->repTab == NULL) {
113: xmlGenericError(xmlGenericErrorContext,
114: "realloc failed !\n");
115: return;
116: }
117: }
118: ctxt->incTab[ctxt->incNr] = node;
1.3 veillard 119: ctxt->repTab[ctxt->incNr] = NULL;
1.1 veillard 120: ctxt->incNr++;
121: }
122:
123: /**
124: * xmlXIncludeAddDoc:
125: * @ctxt: the XInclude context
126: * @doc: the new document
127: * @url: the associated URL
128: *
129: * Add a new document to the list
130: */
131: void
132: xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const URL url) {
133: if (ctxt->docMax == 0) {
134: ctxt->docMax = 4;
135: ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
136: sizeof(ctxt->docTab[0]));
137: if (ctxt->docTab == NULL) {
138: xmlGenericError(xmlGenericErrorContext,
139: "malloc failed !\n");
140: return;
141: }
142: ctxt->urlTab = (URL *) xmlMalloc(ctxt->docMax *
143: sizeof(ctxt->urlTab[0]));
144: if (ctxt->urlTab == NULL) {
145: xmlGenericError(xmlGenericErrorContext,
146: "malloc failed !\n");
147: return;
148: }
149: }
150: if (ctxt->docNr >= ctxt->docMax) {
151: ctxt->docMax *= 2;
152: ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
153: ctxt->docMax * sizeof(ctxt->docTab[0]));
154: if (ctxt->docTab == NULL) {
155: xmlGenericError(xmlGenericErrorContext,
156: "realloc failed !\n");
157: return;
158: }
159: ctxt->urlTab = (URL *) xmlRealloc(ctxt->urlTab,
160: ctxt->docMax * sizeof(ctxt->urlTab[0]));
161: if (ctxt->urlTab == NULL) {
162: xmlGenericError(xmlGenericErrorContext,
163: "realloc failed !\n");
164: return;
165: }
166: }
167: ctxt->docTab[ctxt->docNr] = doc;
168: ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
169: ctxt->docNr++;
170: }
171:
172: /**
1.2 veillard 173: * xmlXIncludeAddTxt:
174: * @ctxt: the XInclude context
175: * @txt: the new text node
176: * @url: the associated URL
177: *
178: * Add a new txtument to the list
179: */
180: void
181: xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const URL url) {
182: if (ctxt->txtMax == 0) {
183: ctxt->txtMax = 4;
184: ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
185: sizeof(ctxt->txtTab[0]));
186: if (ctxt->txtTab == NULL) {
187: xmlGenericError(xmlGenericErrorContext,
188: "malloc failed !\n");
189: return;
190: }
191: ctxt->txturlTab = (URL *) xmlMalloc(ctxt->txtMax *
192: sizeof(ctxt->txturlTab[0]));
193: if (ctxt->txturlTab == NULL) {
194: xmlGenericError(xmlGenericErrorContext,
195: "malloc failed !\n");
196: return;
197: }
198: }
199: if (ctxt->txtNr >= ctxt->txtMax) {
200: ctxt->txtMax *= 2;
201: ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
202: ctxt->txtMax * sizeof(ctxt->txtTab[0]));
203: if (ctxt->txtTab == NULL) {
204: xmlGenericError(xmlGenericErrorContext,
205: "realloc failed !\n");
206: return;
207: }
208: ctxt->txturlTab = (URL *) xmlRealloc(ctxt->txturlTab,
209: ctxt->txtMax * sizeof(ctxt->urlTab[0]));
210: if (ctxt->txturlTab == NULL) {
211: xmlGenericError(xmlGenericErrorContext,
212: "realloc failed !\n");
213: return;
214: }
215: }
216: ctxt->txtTab[ctxt->txtNr] = txt;
217: ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
218: ctxt->txtNr++;
219: }
220:
221: /**
1.1 veillard 222: * xmlXIncludeNewContext:
223: * @doc: an XML Document
224: *
225: * Creates a new XInclude context
226: *
227: * Returns the new set
228: */
229: xmlXIncludeCtxtPtr
230: xmlXIncludeNewContext(xmlDocPtr doc) {
231: xmlXIncludeCtxtPtr ret;
232:
233: if (doc == NULL)
234: return(NULL);
235: ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
236: if (ret == NULL)
237: return(NULL);
238: memset(ret, 0, sizeof(xmlXIncludeCtxt));
239: ret->doc = doc;
240: ret->incNr = 0;
241: ret->incMax = 0;
242: ret->incTab = NULL;
243: ret->repTab = NULL;
244: ret->docNr = 0;
245: ret->docMax = 0;
246: ret->docTab = NULL;
247: ret->urlTab = NULL;
248: return(ret);
249: }
250:
251: /**
252: * xmlXIncludeFreeContext:
253: * @ctxt: the XInclude context
254: *
255: * Free an XInclude context
256: */
257: void
258: xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
259: if (ctxt == NULL)
260: return;
261: if (ctxt->incTab != NULL)
262: xmlFree(ctxt->incTab);
263: if (ctxt->repTab != NULL)
264: xmlFree(ctxt->repTab);
265: memset(ctxt, 0xeb, sizeof(xmlXIncludeCtxt));
266: xmlFree(ctxt);
267: }
268:
1.2 veillard 269: /************************************************************************
270: * *
271: * XInclude I/O handling *
272: * *
273: ************************************************************************/
274:
275: /**
276: * xmlXIncludeLoadDoc:
277: * @ctxt: the XInclude context
278: * @url: the associated URL
279: * @nr: the xinclude node number
280: *
281: * Load the document, and store the result in the XInclude context
282: */
283: void
284: xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
285: xmlDocPtr doc;
286: xmlURIPtr uri;
287: xmlChar *URL;
288: int i;
289: /*
290: * Check the URL and remove any fragment identifier
291: */
292: uri = xmlParseURI((const char *)url);
293: if (uri == NULL) {
294: xmlGenericError(xmlGenericErrorContext,
295: "XInclude: invalid value URI %s\n", url);
296: return;
297: }
298: if (uri->fragment != NULL) {
299: xmlFree(uri->fragment);
300: uri->fragment = NULL; /* TODO: kkep it for later processing */
301: }
302: URL = xmlSaveUri(uri);
303: xmlFreeURI(uri);
304: if (URL == NULL) {
305: xmlGenericError(xmlGenericErrorContext,
306: "XInclude: invalid value URI %s\n", url);
307: return;
308: }
309:
310: /*
311: * Handling of references to the local document are done
312: * directly through ctxt->doc.
313: */
314: if (URL[0] == 0) {
315: xmlFree(URL);
316: return;
317: }
318:
319: /*
320: * Prevent reloading twice the document.
321: */
322: for (i = 0; i < ctxt->docNr; i++) {
323: if (xmlStrEqual(URL, ctxt->urlTab[i])) {
324: doc = ctxt->docTab[i];
325: goto loaded;
326: }
327: }
328: /*
329: * Load it.
330: */
331: doc = xmlParseFile((const char *)URL);
332: if (doc == NULL) {
333: xmlGenericError(xmlGenericErrorContext,
334: "XInclude: could not load %s\n", URL);
335: xmlFree(URL);
336: return;
337: }
338: xmlXIncludeAddDoc(ctxt, doc, URL);
339:
340: loaded:
341: /*
342: * Add the top children list as the replacement copy.
343: */
344: ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
345: xmlFree(URL);
346: }
347:
348: /**
349: * xmlXIncludeLoadTxt:
350: * @ctxt: the XInclude context
351: * @url: the associated URL
352: * @nr: the xinclude node number
353: *
354: * Load the content, and store the result in the XInclude context
355: */
356: void
357: xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
358: xmlParserInputBufferPtr buf;
359: xmlNodePtr node;
360: xmlURIPtr uri;
361: xmlChar *URL;
362: int i;
363: /*
364: * Check the URL and remove any fragment identifier
365: */
366: uri = xmlParseURI((const char *)url);
367: if (uri == NULL) {
368: xmlGenericError(xmlGenericErrorContext,
369: "XInclude: invalid value URI %s\n", url);
370: return;
371: }
372: if (uri->fragment != NULL) {
373: xmlFreeURI(uri);
374: xmlGenericError(xmlGenericErrorContext,
375: "XInclude: fragment identifier forbidden for text\n");
376: return;
377: }
378: URL = xmlSaveUri(uri);
379: xmlFreeURI(uri);
380: if (URL == NULL) {
381: xmlGenericError(xmlGenericErrorContext,
382: "XInclude: invalid value URI %s\n", url);
383: return;
384: }
385:
386: /*
387: * Handling of references to the local document are done
388: * directly through ctxt->doc.
389: */
390: if (URL[0] == 0) {
391: xmlGenericError(xmlGenericErrorContext,
392: "XInclude: text serialization of document not available\n");
393: xmlFree(URL);
394: return;
395: }
396:
397: /*
398: * Prevent reloading twice the document.
399: */
400: for (i = 0; i < ctxt->txtNr; i++) {
401: if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
402: node = xmlCopyNode(ctxt->txtTab[i], 1);
403: goto loaded;
404: }
405: }
406: /*
407: * Load it.
408: * Issue 62: how to detect the encoding
409: */
410: buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
411: if (buf == NULL) {
412: xmlGenericError(xmlGenericErrorContext,
413: "XInclude: could not load %s\n", URL);
414: xmlFree(URL);
415: return;
416: }
417: node = xmlNewText(NULL);
418:
419: /*
420: * Scan all chars from the resource and add the to the node
421: */
422: while (xmlParserInputBufferRead(buf, 128) > 0) {
423: int len;
424: const xmlChar *content;
425:
426: content = xmlBufferContent(buf->buffer);
427: len = xmlBufferLength(buf->buffer);
428: for (i = 0;i < len; i++) {
429: /*
430: * TODO: if the encoding issue is solved, scan UTF8 chars instead
431: */
432: if (!IS_CHAR(content[i])) {
433: xmlGenericError(xmlGenericErrorContext,
434: "XInclude: %s contains invalid char %d\n", URL, content[i]);
435: } else {
436: xmlNodeAddContentLen(node, &content[i], 1);
437: }
438: }
439: xmlBufferShrink(buf->buffer, len);
440: }
441: xmlFreeParserInputBuffer(buf);
442: xmlXIncludeAddTxt(ctxt, node, URL);
443:
444: loaded:
445: /*
446: * Add the element as the replacement copy.
447: */
448: ctxt->repTab[nr] = node;
449: xmlFree(URL);
450: }
451:
452: /************************************************************************
453: * *
454: * XInclude Processing *
455: * *
456: ************************************************************************/
457:
1.1 veillard 458: /**
459: * xmlXIncludePreProcessNode:
460: * @ctxt: an XInclude context
461: * @node: an XInclude node
462: *
463: * Implement the infoset replacement lookup on the XML element @node
464: *
465: * Returns the result list or NULL in case of error
466: */
467: xmlNodePtr
468: xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
469: xmlXIncludeAddNode(ctxt, node);
470: return(0);
471: }
472:
473: /**
474: * xmlXIncludeLoadNode:
475: * @ctxt: an XInclude context
476: * @nr: the node number
477: *
478: * Find and load the infoset replacement for the given node.
479: *
480: * Returns 0 if substition succeeded, -1 if some processing failed
481: */
482: int
1.2 veillard 483: xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1.1 veillard 484: xmlNodePtr cur;
485: xmlChar *href;
486: xmlChar *parse;
487: xmlChar *base;
488: xmlChar *URI;
489: int xml = 1; /* default Issue 64 */
490:
491: if (ctxt == NULL)
492: return(-1);
493: if ((nr < 0) || (nr >= ctxt->incNr))
494: return(-1);
495: cur = ctxt->incTab[nr];
496: if (cur == NULL)
497: return(-1);
498:
499: #ifdef DEBUG_XINCLUDE
500: xmlDebugDumpNode(stdout, cur, 0);
501: #endif
502: /*
1.2 veillard 503: * read the attributes
1.1 veillard 504: */
505: href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
506: if (href == NULL) {
1.2 veillard 507: href = xmlGetProp(cur, XINCLUDE_HREF);
508: if (href == NULL) {
509: xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
510: return(-1);
511: }
512: }
513: parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
514: if (parse == NULL) {
515: parse = xmlGetProp(cur, XINCLUDE_PARSE);
516: }
517: if (parse != NULL) {
518: if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
519: xml = 1;
520: else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
521: xml = 0;
522: else {
523: xmlGenericError(xmlGenericErrorContext,
524: "XInclude: invalid value %s for %s\n",
525: parse, XINCLUDE_PARSE);
526: if (href != NULL)
527: xmlFree(href);
528: if (parse != NULL)
529: xmlFree(parse);
530: return(-1);
531: }
532: }
533:
534: /*
535: * compute the URI
536: */
537: base = xmlNodeGetBase(ctxt->doc, cur);
538: URI = xmlBuildURI(href, base);
539: if (URI == NULL) {
540: xmlChar *escbase;
541: xmlChar *eschref;
542: /*
543: * Some escapeing may be needed
544: */
545: escbase = xmlURIEscape(base);
546: eschref = xmlURIEscape(href);
547: URI = xmlBuildURI(eschref, escbase);
548: if (escbase != NULL)
549: xmlFree(escbase);
550: if (eschref != NULL)
551: xmlFree(eschref);
552: }
553: if (URI == NULL) {
554: xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
555: if (parse != NULL)
556: xmlFree(parse);
557: if (href != NULL)
558: xmlFree(href);
559: if (base != NULL)
560: xmlFree(base);
561: return(-1);
562: }
563: #ifdef DEBUG_XINCLUDE
564: xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
565: xml ? "xml": "text");
566: xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
567: #endif
568:
569: /*
570: * Cleanup
571: */
572: if (xml) {
573: xmlXIncludeLoadDoc(ctxt, URI, nr);
574: /* xmlXIncludeGetFragment(ctxt, cur, URI); */
575: } else {
576: xmlXIncludeLoadTxt(ctxt, URI, nr);
577: }
578:
579: /*
580: * Cleanup
581: */
582: if (URI != NULL)
583: xmlFree(URI);
584: if (parse != NULL)
585: xmlFree(parse);
586: if (href != NULL)
587: xmlFree(href);
588: if (base != NULL)
589: xmlFree(base);
590: return(0);
591: }
592:
593: /**
594: * xmlXIncludeIncludeNode:
595: * @ctxt: an XInclude context
596: * @nr: the node number
597: *
598: * Inplement the infoset replacement for the given node
599: *
600: * Returns 0 if substition succeeded, -1 if some processing failed
601: */
602: int
603: xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
604: xmlNodePtr cur, end, list;
605:
606: if (ctxt == NULL)
607: return(-1);
608: if ((nr < 0) || (nr >= ctxt->incNr))
609: return(-1);
610: cur = ctxt->incTab[nr];
611: if (cur == NULL)
612: return(-1);
613:
614: /*
615: * Change the current node as an XInclude start one, and add an
616: * entity end one
617: */
618: cur->type = XML_XINCLUDE_START;
619: end = xmlNewNode(cur->ns, cur->name);
620: if (end == NULL) {
621: xmlGenericError(xmlGenericErrorContext,
622: "XInclude: failed to build node\n");
1.1 veillard 623: return(-1);
624: }
1.3 veillard 625: end->type = XML_XINCLUDE_END;
626: xmlAddNextSibling(cur, end);
1.2 veillard 627:
628: /*
629: * Add the list of nodes
630: */
631: list = ctxt->repTab[nr];
632: ctxt->repTab[nr] = NULL;
633: while (list != NULL) {
634: cur = list;
635: list = list->next;
1.1 veillard 636:
1.2 veillard 637: xmlAddPrevSibling(end, cur);
1.1 veillard 638: }
639: return(0);
640: }
641:
642: /**
643: * xmlXIncludeTestNode:
644: * @doc: an XML document
645: * @node: an XInclude node
646: *
647: * test if the node is an XInclude node
648: *
649: * Returns 1 true, 0 otherwise
650: */
651: int
652: xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) {
653: if (node == NULL)
654: return(0);
655: if (node->ns == NULL)
656: return(0);
657: if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
658: (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
659: return(0);
660: }
661:
662: /**
663: * xmlXIncludeProcess:
664: * @doc: an XML document
665: *
666: * Implement the XInclude substitution on the XML document @doc
667: *
668: * Returns 0 if no substition were done, -1 if some processing failed
669: * or the number of substitutions done.
670: */
671: int
672: xmlXIncludeProcess(xmlDocPtr doc) {
673: xmlXIncludeCtxtPtr ctxt;
674: xmlNodePtr cur;
675: int ret = 0;
676: int i;
677:
678: if (doc == NULL)
679: return(-1);
680: ctxt = xmlXIncludeNewContext(doc);
681: if (ctxt == NULL)
682: return(-1);
683:
684: /*
685: * First phase: lookup the elements in the document
686: */
687: cur = xmlDocGetRootElement(doc);
688: if (xmlXIncludeTestNode(doc, cur))
689: xmlXIncludePreProcessNode(ctxt, cur);
690: while (cur != NULL) {
1.3 veillard 691: /* TODO: need to work on entities -> stack */
692: if ((cur->children != NULL) &&
693: (cur->children->type != XML_ENTITY_DECL)) {
694: cur = cur->children;
695: if (xmlXIncludeTestNode(doc, cur))
696: xmlXIncludePreProcessNode(ctxt, cur);
1.1 veillard 697: } else if (cur->next != NULL) {
698: cur = cur->next;
699: if (xmlXIncludeTestNode(doc, cur))
700: xmlXIncludePreProcessNode(ctxt, cur);
701: } else {
702: do {
703: cur = cur->parent;
704: if (cur == NULL) break; /* do */
705: if (cur->next != NULL) {
706: cur = cur->next;
707: if (xmlXIncludeTestNode(doc, cur))
708: xmlXIncludePreProcessNode(ctxt, cur);
709: break; /* do */
710: }
711: } while (cur != NULL);
712: }
713: }
714:
715: /*
716: * Second Phase : collect the infosets fragments
717: */
718: for (i = 0;i < ctxt->incNr; i++) {
1.2 veillard 719: xmlXIncludeLoadNode(ctxt, i);
1.1 veillard 720: }
721:
722: /*
723: * Third phase: extend the original document infoset.
724: */
1.2 veillard 725: for (i = 0;i < ctxt->incNr; i++) {
726: xmlXIncludeIncludeNode(ctxt, i);
727: }
1.1 veillard 728:
729: /*
730: * Cleanup
731: */
732: xmlXIncludeFreeContext(ctxt);
733: return(ret);
734: }
735:
736: #else /* !LIBXML_XINCLUDE_ENABLED */
737: #endif
Webmaster