blob: 3c203638e273aa22478bda9d0ca131cb036d33e8 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
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/*
13 * TODO: compute XPointers nodesets
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>
29#include <libxml/parserInternals.h>
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"
42#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
43#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
44
45/* #define DEBUG_XINCLUDE */
46
47/************************************************************************
48 * *
49 * XInclude contexts handling *
50 * *
51 ************************************************************************/
52
53/*
54 * An XInclude context
55 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000056typedef xmlChar *xmlURL;
Owen Taylor3473f882001-02-23 17:55:21 +000057typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
58typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
59struct _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 */
65 int docNr; /* number of parsed documents */
66 int docMax; /* size of parsed documents tab */
67 xmlDocPtr *docTab; /* array of parsed documents */
Daniel Veillardedac3c92001-02-26 01:36:19 +000068 xmlURL *urlTab; /* array of parsed documents URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000069 int txtNr; /* number of unparsed documents */
70 int txtMax; /* size of unparsed documents tab */
71 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000072 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000073};
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 */
82void
83xmlXIncludeAddNode(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;
119 ctxt->repTab[ctxt->incNr] = NULL;
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 */
131void
Daniel Veillardedac3c92001-02-26 01:36:19 +0000132xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url) {
Owen Taylor3473f882001-02-23 17:55:21 +0000133 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 }
Daniel Veillardedac3c92001-02-26 01:36:19 +0000142 ctxt->urlTab = (xmlURL *) xmlMalloc(ctxt->docMax *
Owen Taylor3473f882001-02-23 17:55:21 +0000143 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 }
Daniel Veillardedac3c92001-02-26 01:36:19 +0000159 ctxt->urlTab = (xmlURL *) xmlRealloc(ctxt->urlTab,
Owen Taylor3473f882001-02-23 17:55:21 +0000160 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/**
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 */
180void
Daniel Veillardedac3c92001-02-26 01:36:19 +0000181xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Owen Taylor3473f882001-02-23 17:55:21 +0000182 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 }
Daniel Veillardedac3c92001-02-26 01:36:19 +0000191 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
Owen Taylor3473f882001-02-23 17:55:21 +0000192 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 }
Daniel Veillardedac3c92001-02-26 01:36:19 +0000208 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Owen Taylor3473f882001-02-23 17:55:21 +0000209 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/**
222 * xmlXIncludeNewContext:
223 * @doc: an XML Document
224 *
225 * Creates a new XInclude context
226 *
227 * Returns the new set
228 */
229xmlXIncludeCtxtPtr
230xmlXIncludeNewContext(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 */
257void
258xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
259 int i;
260
261 if (ctxt == NULL)
262 return;
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 }
272 if (ctxt->incTab != NULL)
273 xmlFree(ctxt->incTab);
274 if (ctxt->repTab != NULL)
275 xmlFree(ctxt->repTab);
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);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000284 MEM_CLEANUP(ctxt, sizeof(xmlXIncludeCtxt));
Owen Taylor3473f882001-02-23 17:55:21 +0000285 xmlFree(ctxt);
286}
287
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 */
302void
303xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
304 xmlDocPtr doc;
305 xmlURIPtr uri;
306 xmlChar *URL;
307 xmlChar *fragment = NULL;
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) {
319 fragment = (xmlChar *) uri->fragment;
320 uri->fragment = NULL;
321 }
322 URL = xmlSaveUri(uri);
323 xmlFreeURI(uri);
324 if (URL == NULL) {
325 xmlGenericError(xmlGenericErrorContext,
326 "XInclude: invalid value URI %s\n", url);
327 if (fragment != NULL)
328 xmlFree(fragment);
329 return;
330 }
331
332 /*
333 * Handling of references to the local document are done
334 * directly through ctxt->doc.
335 */
336 if ((URL[0] == 0) || (URL[0] == '#')) {
337 doc = NULL;
338 goto loaded;
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);
358 if (fragment != NULL)
359 xmlFree(fragment);
360 return;
361 }
362 xmlXIncludeAddDoc(ctxt, doc, URL);
363
364loaded:
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);
399 xmlXPathFreeContext(xptrctxt);
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 }
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 */
420void
421xmlXIncludeLoadTxt(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) {
437 xmlGenericError(xmlGenericErrorContext,
438 "XInclude: fragment identifier forbidden for text: %s\n",
439 uri->fragment);
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
509loaded:
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
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 */
532xmlNodePtr
533xmlXIncludePreProcessNode(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 */
547int
548xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
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 /*
568 * read the attributes
569 */
570 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
571 if (href == NULL) {
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 if (base == NULL) {
604 URI = xmlBuildURI(href, ctxt->doc->URL);
605 } else {
606 URI = xmlBuildURI(href, base);
607 }
608 if (URI == NULL) {
609 xmlChar *escbase;
610 xmlChar *eschref;
611 /*
612 * Some escapeing may be needed
613 */
614 escbase = xmlURIEscape(base);
615 eschref = xmlURIEscape(href);
616 URI = xmlBuildURI(eschref, escbase);
617 if (escbase != NULL)
618 xmlFree(escbase);
619 if (eschref != NULL)
620 xmlFree(eschref);
621 }
622 if (URI == NULL) {
623 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
624 if (parse != NULL)
625 xmlFree(parse);
626 if (href != NULL)
627 xmlFree(href);
628 if (base != NULL)
629 xmlFree(base);
630 return(-1);
631 }
632#ifdef DEBUG_XINCLUDE
633 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
634 xml ? "xml": "text");
635 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
636#endif
637
638 /*
639 * Cleanup
640 */
641 if (xml) {
642 xmlXIncludeLoadDoc(ctxt, URI, nr);
643 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
644 } else {
645 xmlXIncludeLoadTxt(ctxt, URI, nr);
646 }
647
648 /*
649 * Cleanup
650 */
651 if (URI != NULL)
652 xmlFree(URI);
653 if (parse != NULL)
654 xmlFree(parse);
655 if (href != NULL)
656 xmlFree(href);
657 if (base != NULL)
658 xmlFree(base);
659 return(0);
660}
661
662/**
663 * xmlXIncludeIncludeNode:
664 * @ctxt: an XInclude context
665 * @nr: the node number
666 *
667 * Inplement the infoset replacement for the given node
668 *
669 * Returns 0 if substition succeeded, -1 if some processing failed
670 */
671int
672xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
673 xmlNodePtr cur, end, list;
674
675 if (ctxt == NULL)
676 return(-1);
677 if ((nr < 0) || (nr >= ctxt->incNr))
678 return(-1);
679 cur = ctxt->incTab[nr];
680 if (cur == NULL)
681 return(-1);
682
683 /*
684 * Change the current node as an XInclude start one, and add an
685 * entity end one
686 */
687 cur->type = XML_XINCLUDE_START;
688 end = xmlNewNode(cur->ns, cur->name);
689 if (end == NULL) {
690 xmlGenericError(xmlGenericErrorContext,
691 "XInclude: failed to build node\n");
692 return(-1);
693 }
694 end->type = XML_XINCLUDE_END;
695 xmlAddNextSibling(cur, end);
696
697 /*
698 * Add the list of nodes
699 */
700 list = ctxt->repTab[nr];
701 ctxt->repTab[nr] = NULL;
702 while (list != NULL) {
703 cur = list;
704 list = list->next;
705
706 xmlAddPrevSibling(end, cur);
707 }
708 return(0);
709}
710
711/**
712 * xmlXIncludeTestNode:
713 * @doc: an XML document
714 * @node: an XInclude node
715 *
716 * test if the node is an XInclude node
717 *
718 * Returns 1 true, 0 otherwise
719 */
720int
721xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) {
722 if (node == NULL)
723 return(0);
724 if (node->ns == NULL)
725 return(0);
726 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
727 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
728 return(0);
729}
730
731/**
732 * xmlXIncludeProcess:
733 * @doc: an XML document
734 *
735 * Implement the XInclude substitution on the XML document @doc
736 *
737 * Returns 0 if no substition were done, -1 if some processing failed
738 * or the number of substitutions done.
739 */
740int
741xmlXIncludeProcess(xmlDocPtr doc) {
742 xmlXIncludeCtxtPtr ctxt;
743 xmlNodePtr cur;
744 int ret = 0;
745 int i;
746
747 if (doc == NULL)
748 return(-1);
749 ctxt = xmlXIncludeNewContext(doc);
750 if (ctxt == NULL)
751 return(-1);
752
753 /*
754 * First phase: lookup the elements in the document
755 */
756 cur = xmlDocGetRootElement(doc);
757 if (xmlXIncludeTestNode(doc, cur))
758 xmlXIncludePreProcessNode(ctxt, cur);
759 while (cur != NULL) {
760 /* TODO: need to work on entities -> stack */
761 if ((cur->children != NULL) &&
762 (cur->children->type != XML_ENTITY_DECL)) {
763 cur = cur->children;
764 if (xmlXIncludeTestNode(doc, cur))
765 xmlXIncludePreProcessNode(ctxt, cur);
766 } else if (cur->next != NULL) {
767 cur = cur->next;
768 if (xmlXIncludeTestNode(doc, cur))
769 xmlXIncludePreProcessNode(ctxt, cur);
770 } else {
771 do {
772 cur = cur->parent;
773 if (cur == NULL) break; /* do */
774 if (cur->next != NULL) {
775 cur = cur->next;
776 if (xmlXIncludeTestNode(doc, cur))
777 xmlXIncludePreProcessNode(ctxt, cur);
778 break; /* do */
779 }
780 } while (cur != NULL);
781 }
782 }
783
784 /*
785 * Second Phase : collect the infosets fragments
786 */
787 for (i = 0;i < ctxt->incNr; i++) {
788 xmlXIncludeLoadNode(ctxt, i);
789 }
790
791 /*
792 * Third phase: extend the original document infoset.
793 */
794 for (i = 0;i < ctxt->incNr; i++) {
795 xmlXIncludeIncludeNode(ctxt, i);
796 }
797
798 /*
799 * Cleanup
800 */
801 xmlXIncludeFreeContext(ctxt);
802 return(ret);
803}
804
805#else /* !LIBXML_XINCLUDE_ENABLED */
806#endif