Annotation of XML/xinclude.c, revision 1.8
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) {
1.7 veillard 259: int i;
260:
1.1 veillard 261: if (ctxt == NULL)
262: return;
1.7 veillard 263: for (i = 0;i < ctxt->docNr;i++) {
264: xmlFreeDoc(ctxt->docTab[i]);
265: if (ctxt->urlTab[i] != NULL)
266: xmlFree(ctxt->urlTab[i]);
267: }
268: for (i = 0;i < ctxt->txtNr;i++) {
269: if (ctxt->txturlTab[i] != NULL)
270: xmlFree(ctxt->txturlTab[i]);
271: }
1.1 veillard 272: if (ctxt->incTab != NULL)
273: xmlFree(ctxt->incTab);
274: if (ctxt->repTab != NULL)
275: xmlFree(ctxt->repTab);
1.7 veillard 276: if (ctxt->urlTab != NULL)
277: xmlFree(ctxt->urlTab);
278: if (ctxt->docTab != NULL)
279: xmlFree(ctxt->docTab);
280: if (ctxt->txtTab != NULL)
281: xmlFree(ctxt->txtTab);
282: if (ctxt->txturlTab != NULL)
283: xmlFree(ctxt->txturlTab);
1.1 veillard 284: memset(ctxt, 0xeb, sizeof(xmlXIncludeCtxt));
285: xmlFree(ctxt);
286: }
287:
1.2 veillard 288: /************************************************************************
289: * *
290: * XInclude I/O handling *
291: * *
292: ************************************************************************/
293:
294: /**
295: * xmlXIncludeLoadDoc:
296: * @ctxt: the XInclude context
297: * @url: the associated URL
298: * @nr: the xinclude node number
299: *
300: * Load the document, and store the result in the XInclude context
301: */
302: void
303: xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
304: xmlDocPtr doc;
305: xmlURIPtr uri;
306: xmlChar *URL;
1.6 veillard 307: xmlChar *fragment = NULL;
1.2 veillard 308: int i;
309: /*
310: * Check the URL and remove any fragment identifier
311: */
312: uri = xmlParseURI((const char *)url);
313: if (uri == NULL) {
314: xmlGenericError(xmlGenericErrorContext,
315: "XInclude: invalid value URI %s\n", url);
316: return;
317: }
318: if (uri->fragment != NULL) {
1.6 veillard 319: fragment = (xmlChar *) uri->fragment;
320: uri->fragment = NULL;
1.2 veillard 321: }
322: URL = xmlSaveUri(uri);
323: xmlFreeURI(uri);
324: if (URL == NULL) {
325: xmlGenericError(xmlGenericErrorContext,
326: "XInclude: invalid value URI %s\n", url);
1.6 veillard 327: if (fragment != NULL)
328: xmlFree(fragment);
1.2 veillard 329: return;
330: }
331:
332: /*
333: * Handling of references to the local document are done
334: * directly through ctxt->doc.
335: */
1.6 veillard 336: if ((URL[0] == 0) || (URL[0] == '#')) {
337: doc = NULL;
338: goto loaded;
1.2 veillard 339: }
340:
341: /*
342: * Prevent reloading twice the document.
343: */
344: for (i = 0; i < ctxt->docNr; i++) {
345: if (xmlStrEqual(URL, ctxt->urlTab[i])) {
346: doc = ctxt->docTab[i];
347: goto loaded;
348: }
349: }
350: /*
351: * Load it.
352: */
353: doc = xmlParseFile((const char *)URL);
354: if (doc == NULL) {
355: xmlGenericError(xmlGenericErrorContext,
356: "XInclude: could not load %s\n", URL);
357: xmlFree(URL);
1.6 veillard 358: if (fragment != NULL)
359: xmlFree(fragment);
1.2 veillard 360: return;
361: }
362: xmlXIncludeAddDoc(ctxt, doc, URL);
363:
364: loaded:
1.6 veillard 365: if (fragment == NULL) {
366: /*
367: * Add the top children list as the replacement copy.
368: * ISSUE: seems we should scrap DTD info from the copied list.
369: */
370: if (doc == NULL)
371: ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
372: else
373: ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
374: } else {
375: /*
376: * Computes the XPointer expression and make a copy used
377: * as the replacement copy.
378: */
379: xmlXPathObjectPtr xptr;
380: xmlXPathContextPtr xptrctxt;
381:
382: if (doc == NULL) {
383: xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
384: } else {
385: xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
386: }
387: if (xptrctxt == NULL) {
388: xmlGenericError(xmlGenericErrorContext,
389: "XInclude: could create XPointer context\n");
390: xmlFree(URL);
391: xmlFree(fragment);
392: return;
393: }
394: xptr = xmlXPtrEval(fragment, xptrctxt);
395: if (xptr == NULL) {
396: xmlGenericError(xmlGenericErrorContext,
397: "XInclude: XPointer evaluation failed: #%s\n",
398: fragment);
1.8 ! veillard 399: xmlXPathFreeContext(xptrctxt);
1.6 veillard 400: xmlFree(URL);
401: xmlFree(fragment);
402: return;
403: }
404: ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
405: xmlXPathFreeObject(xptr);
406: xmlXPathFreeContext(xptrctxt);
407: xmlFree(fragment);
408: }
1.2 veillard 409: xmlFree(URL);
410: }
411:
412: /**
413: * xmlXIncludeLoadTxt:
414: * @ctxt: the XInclude context
415: * @url: the associated URL
416: * @nr: the xinclude node number
417: *
418: * Load the content, and store the result in the XInclude context
419: */
420: void
421: xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
422: xmlParserInputBufferPtr buf;
423: xmlNodePtr node;
424: xmlURIPtr uri;
425: xmlChar *URL;
426: int i;
427: /*
428: * Check the URL and remove any fragment identifier
429: */
430: uri = xmlParseURI((const char *)url);
431: if (uri == NULL) {
432: xmlGenericError(xmlGenericErrorContext,
433: "XInclude: invalid value URI %s\n", url);
434: return;
435: }
436: if (uri->fragment != NULL) {
1.5 veillard 437: xmlGenericError(xmlGenericErrorContext,
438: "XInclude: fragment identifier forbidden for text: %s\n",
439: uri->fragment);
1.2 veillard 440: xmlFreeURI(uri);
441: return;
442: }
443: URL = xmlSaveUri(uri);
444: xmlFreeURI(uri);
445: if (URL == NULL) {
446: xmlGenericError(xmlGenericErrorContext,
447: "XInclude: invalid value URI %s\n", url);
448: return;
449: }
450:
451: /*
452: * Handling of references to the local document are done
453: * directly through ctxt->doc.
454: */
455: if (URL[0] == 0) {
456: xmlGenericError(xmlGenericErrorContext,
457: "XInclude: text serialization of document not available\n");
458: xmlFree(URL);
459: return;
460: }
461:
462: /*
463: * Prevent reloading twice the document.
464: */
465: for (i = 0; i < ctxt->txtNr; i++) {
466: if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
467: node = xmlCopyNode(ctxt->txtTab[i], 1);
468: goto loaded;
469: }
470: }
471: /*
472: * Load it.
473: * Issue 62: how to detect the encoding
474: */
475: buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
476: if (buf == NULL) {
477: xmlGenericError(xmlGenericErrorContext,
478: "XInclude: could not load %s\n", URL);
479: xmlFree(URL);
480: return;
481: }
482: node = xmlNewText(NULL);
483:
484: /*
485: * Scan all chars from the resource and add the to the node
486: */
487: while (xmlParserInputBufferRead(buf, 128) > 0) {
488: int len;
489: const xmlChar *content;
490:
491: content = xmlBufferContent(buf->buffer);
492: len = xmlBufferLength(buf->buffer);
493: for (i = 0;i < len; i++) {
494: /*
495: * TODO: if the encoding issue is solved, scan UTF8 chars instead
496: */
497: if (!IS_CHAR(content[i])) {
498: xmlGenericError(xmlGenericErrorContext,
499: "XInclude: %s contains invalid char %d\n", URL, content[i]);
500: } else {
501: xmlNodeAddContentLen(node, &content[i], 1);
502: }
503: }
504: xmlBufferShrink(buf->buffer, len);
505: }
506: xmlFreeParserInputBuffer(buf);
507: xmlXIncludeAddTxt(ctxt, node, URL);
508:
509: loaded:
510: /*
511: * Add the element as the replacement copy.
512: */
513: ctxt->repTab[nr] = node;
514: xmlFree(URL);
515: }
516:
517: /************************************************************************
518: * *
519: * XInclude Processing *
520: * *
521: ************************************************************************/
522:
1.1 veillard 523: /**
524: * xmlXIncludePreProcessNode:
525: * @ctxt: an XInclude context
526: * @node: an XInclude node
527: *
528: * Implement the infoset replacement lookup on the XML element @node
529: *
530: * Returns the result list or NULL in case of error
531: */
532: xmlNodePtr
533: xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
534: xmlXIncludeAddNode(ctxt, node);
535: return(0);
536: }
537:
538: /**
539: * xmlXIncludeLoadNode:
540: * @ctxt: an XInclude context
541: * @nr: the node number
542: *
543: * Find and load the infoset replacement for the given node.
544: *
545: * Returns 0 if substition succeeded, -1 if some processing failed
546: */
547: int
1.2 veillard 548: xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1.1 veillard 549: xmlNodePtr cur;
550: xmlChar *href;
551: xmlChar *parse;
552: xmlChar *base;
553: xmlChar *URI;
554: int xml = 1; /* default Issue 64 */
555:
556: if (ctxt == NULL)
557: return(-1);
558: if ((nr < 0) || (nr >= ctxt->incNr))
559: return(-1);
560: cur = ctxt->incTab[nr];
561: if (cur == NULL)
562: return(-1);
563:
564: #ifdef DEBUG_XINCLUDE
565: xmlDebugDumpNode(stdout, cur, 0);
566: #endif
567: /*
1.2 veillard 568: * read the attributes
1.1 veillard 569: */
570: href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
571: if (href == NULL) {
1.2 veillard 572: href = xmlGetProp(cur, XINCLUDE_HREF);
573: if (href == NULL) {
574: xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
575: return(-1);
576: }
577: }
578: parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
579: if (parse == NULL) {
580: parse = xmlGetProp(cur, XINCLUDE_PARSE);
581: }
582: if (parse != NULL) {
583: if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
584: xml = 1;
585: else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
586: xml = 0;
587: else {
588: xmlGenericError(xmlGenericErrorContext,
589: "XInclude: invalid value %s for %s\n",
590: parse, XINCLUDE_PARSE);
591: if (href != NULL)
592: xmlFree(href);
593: if (parse != NULL)
594: xmlFree(parse);
595: return(-1);
596: }
597: }
598:
599: /*
600: * compute the URI
601: */
602: base = xmlNodeGetBase(ctxt->doc, cur);
603: URI = xmlBuildURI(href, base);
604: if (URI == NULL) {
605: xmlChar *escbase;
606: xmlChar *eschref;
607: /*
608: * Some escapeing may be needed
609: */
610: escbase = xmlURIEscape(base);
611: eschref = xmlURIEscape(href);
612: URI = xmlBuildURI(eschref, escbase);
613: if (escbase != NULL)
614: xmlFree(escbase);
615: if (eschref != NULL)
616: xmlFree(eschref);
617: }
618: if (URI == NULL) {
619: xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
620: if (parse != NULL)
621: xmlFree(parse);
622: if (href != NULL)
623: xmlFree(href);
624: if (base != NULL)
625: xmlFree(base);
626: return(-1);
627: }
628: #ifdef DEBUG_XINCLUDE
629: xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
630: xml ? "xml": "text");
631: xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
632: #endif
633:
634: /*
635: * Cleanup
636: */
637: if (xml) {
638: xmlXIncludeLoadDoc(ctxt, URI, nr);
639: /* xmlXIncludeGetFragment(ctxt, cur, URI); */
640: } else {
641: xmlXIncludeLoadTxt(ctxt, URI, nr);
642: }
643:
644: /*
645: * Cleanup
646: */
647: if (URI != NULL)
648: xmlFree(URI);
649: if (parse != NULL)
650: xmlFree(parse);
651: if (href != NULL)
652: xmlFree(href);
653: if (base != NULL)
654: xmlFree(base);
655: return(0);
656: }
657:
658: /**
659: * xmlXIncludeIncludeNode:
660: * @ctxt: an XInclude context
661: * @nr: the node number
662: *
663: * Inplement the infoset replacement for the given node
664: *
665: * Returns 0 if substition succeeded, -1 if some processing failed
666: */
667: int
668: xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
669: xmlNodePtr cur, end, list;
670:
671: if (ctxt == NULL)
672: return(-1);
673: if ((nr < 0) || (nr >= ctxt->incNr))
674: return(-1);
675: cur = ctxt->incTab[nr];
676: if (cur == NULL)
677: return(-1);
678:
679: /*
680: * Change the current node as an XInclude start one, and add an
681: * entity end one
682: */
683: cur->type = XML_XINCLUDE_START;
684: end = xmlNewNode(cur->ns, cur->name);
685: if (end == NULL) {
686: xmlGenericError(xmlGenericErrorContext,
687: "XInclude: failed to build node\n");
1.1 veillard 688: return(-1);
689: }
1.3 veillard 690: end->type = XML_XINCLUDE_END;
691: xmlAddNextSibling(cur, end);
1.2 veillard 692:
693: /*
694: * Add the list of nodes
695: */
696: list = ctxt->repTab[nr];
697: ctxt->repTab[nr] = NULL;
698: while (list != NULL) {
699: cur = list;
700: list = list->next;
1.1 veillard 701:
1.2 veillard 702: xmlAddPrevSibling(end, cur);
1.1 veillard 703: }
704: return(0);
705: }
706:
707: /**
708: * xmlXIncludeTestNode:
709: * @doc: an XML document
710: * @node: an XInclude node
711: *
712: * test if the node is an XInclude node
713: *
714: * Returns 1 true, 0 otherwise
715: */
716: int
717: xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) {
718: if (node == NULL)
719: return(0);
720: if (node->ns == NULL)
721: return(0);
722: if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
723: (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
724: return(0);
725: }
726:
727: /**
728: * xmlXIncludeProcess:
729: * @doc: an XML document
730: *
731: * Implement the XInclude substitution on the XML document @doc
732: *
733: * Returns 0 if no substition were done, -1 if some processing failed
734: * or the number of substitutions done.
735: */
736: int
737: xmlXIncludeProcess(xmlDocPtr doc) {
738: xmlXIncludeCtxtPtr ctxt;
739: xmlNodePtr cur;
740: int ret = 0;
741: int i;
742:
743: if (doc == NULL)
744: return(-1);
745: ctxt = xmlXIncludeNewContext(doc);
746: if (ctxt == NULL)
747: return(-1);
748:
749: /*
750: * First phase: lookup the elements in the document
751: */
752: cur = xmlDocGetRootElement(doc);
753: if (xmlXIncludeTestNode(doc, cur))
754: xmlXIncludePreProcessNode(ctxt, cur);
755: while (cur != NULL) {
1.3 veillard 756: /* TODO: need to work on entities -> stack */
757: if ((cur->children != NULL) &&
758: (cur->children->type != XML_ENTITY_DECL)) {
759: cur = cur->children;
760: if (xmlXIncludeTestNode(doc, cur))
761: xmlXIncludePreProcessNode(ctxt, cur);
1.1 veillard 762: } else if (cur->next != NULL) {
763: cur = cur->next;
764: if (xmlXIncludeTestNode(doc, cur))
765: xmlXIncludePreProcessNode(ctxt, cur);
766: } else {
767: do {
768: cur = cur->parent;
769: if (cur == NULL) break; /* do */
770: if (cur->next != NULL) {
771: cur = cur->next;
772: if (xmlXIncludeTestNode(doc, cur))
773: xmlXIncludePreProcessNode(ctxt, cur);
774: break; /* do */
775: }
776: } while (cur != NULL);
777: }
778: }
779:
780: /*
781: * Second Phase : collect the infosets fragments
782: */
783: for (i = 0;i < ctxt->incNr; i++) {
1.2 veillard 784: xmlXIncludeLoadNode(ctxt, i);
1.1 veillard 785: }
786:
787: /*
788: * Third phase: extend the original document infoset.
789: */
1.2 veillard 790: for (i = 0;i < ctxt->incNr; i++) {
791: xmlXIncludeIncludeNode(ctxt, i);
792: }
1.1 veillard 793:
794: /*
795: * Cleanup
796: */
797: xmlXIncludeFreeContext(ctxt);
798: return(ret);
799: }
800:
801: #else /* !LIBXML_XINCLUDE_ENABLED */
802: #endif
Webmaster