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