missing project/build files
[client-tools.git] / src / external / 3rd / library / libxml / xinclude.c
blob78ee0427b2ec28ccc78a4f509b0952ede36cc8a9
1 /*
2 * xinclude.c : Code to implement XInclude processing
4 * World Wide Web Consortium W3C Last Call Working Draft 16 May 2001
5 * http://www.w3.org/TR/2001/WD-xinclude-20010516/
7 * See Copyright for the status of this software.
9 * daniel@veillard.com
13 * TODO: compute XPointers nodesets
14 * TODO: add an node intermediate API and handle recursion at this level
17 #define IN_LIBXML
18 #include "libxml.h"
20 #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>
27 #include <libxml/xmlerror.h>
28 #include <libxml/encoding.h>
29 #include <libxml/globals.h>
31 #ifdef LIBXML_XINCLUDE_ENABLED
32 #include <libxml/xinclude.h>
34 #define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
35 #define XINCLUDE_NODE (const xmlChar *) "include"
36 #define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
37 #define XINCLUDE_HREF (const xmlChar *) "href"
38 #define XINCLUDE_PARSE (const xmlChar *) "parse"
39 #define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
40 #define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
41 #define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
43 /* #define DEBUG_XINCLUDE */
44 #ifdef DEBUG_XINCLUDE
45 #ifdef LIBXML_DEBUG_ENABLED
46 #include <libxml/debugXML.h>
47 #endif
48 #endif
50 /************************************************************************
51 * *
52 * XInclude contexts handling *
53 * *
54 ************************************************************************/
57 * An XInclude context
59 typedef xmlChar *xmlURL;
61 typedef struct _xmlXIncludeRef xmlXIncludeRef;
62 typedef xmlXIncludeRef *xmlXIncludeRefPtr;
63 struct _xmlXIncludeRef {
64 xmlChar *URI; /* the rully resolved resource URL */
65 xmlChar *fragment; /* the fragment in the URI */
66 xmlDocPtr doc; /* the parsed document */
67 xmlNodePtr ref; /* the node making the reference in the source */
68 xmlNodePtr inc; /* the included copy */
69 int xml; /* xml or txt */
70 int count; /* how many refs use that specific doc */
73 typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
74 typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
75 struct _xmlXIncludeCtxt {
76 xmlDocPtr doc; /* the source document */
77 int incBase; /* the first include for this document */
78 int incNr; /* number of includes */
79 int incMax; /* size of includes tab */
80 xmlXIncludeRefPtr *incTab; /* array of included references */
82 int txtNr; /* number of unparsed documents */
83 int txtMax; /* size of unparsed documents tab */
84 xmlNodePtr *txtTab; /* array of unparsed text nodes */
85 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
88 static int
89 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
91 /**
92 * xmlXIncludeFreeRef:
93 * @ref: the XInclude reference
95 * Free an XInclude reference
97 static void
98 xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
99 if (ref == NULL)
100 return;
101 #ifdef DEBUG_XINCLUDE
102 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
103 #endif
104 if (ref->doc != NULL) {
105 #ifdef DEBUG_XINCLUDE
106 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
107 #endif
108 xmlFreeDoc(ref->doc);
110 if (ref->URI != NULL)
111 xmlFree(ref->URI);
112 if (ref->fragment != NULL)
113 xmlFree(ref->fragment);
114 xmlFree(ref);
118 * xmlXIncludeNewRef:
119 * @ctxt: the XInclude context
120 * @URI: the resource URI
122 * Creates a new reference within an XInclude context
124 * Returns the new set
126 static xmlXIncludeRefPtr
127 xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
128 xmlNodePtr ref) {
129 xmlXIncludeRefPtr ret;
131 #ifdef DEBUG_XINCLUDE
132 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
133 #endif
134 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
135 if (ret == NULL)
136 return(NULL);
137 memset(ret, 0, sizeof(xmlXIncludeRef));
138 if (URI == NULL)
139 ret->URI = NULL;
140 else
141 ret->URI = xmlStrdup(URI);
142 ret->fragment = NULL;
143 ret->ref = ref;
144 ret->doc = 0;
145 ret->count = 0;
146 ret->xml = 0;
147 ret->inc = NULL;
148 if (ctxt->incMax == 0) {
149 ctxt->incMax = 4;
150 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
151 sizeof(ctxt->incTab[0]));
152 if (ctxt->incTab == NULL) {
153 xmlGenericError(xmlGenericErrorContext,
154 "malloc failed !\n");
155 xmlXIncludeFreeRef(ret);
156 return(NULL);
159 if (ctxt->incNr >= ctxt->incMax) {
160 ctxt->incMax *= 2;
161 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
162 ctxt->incMax * sizeof(ctxt->incTab[0]));
163 if (ctxt->incTab == NULL) {
164 xmlGenericError(xmlGenericErrorContext,
165 "realloc failed !\n");
166 xmlXIncludeFreeRef(ret);
167 return(NULL);
170 ctxt->incTab[ctxt->incNr++] = ret;
171 return(ret);
175 * xmlXIncludeNewContext:
176 * @doc: an XML Document
178 * Creates a new XInclude context
180 * Returns the new set
182 static xmlXIncludeCtxtPtr
183 xmlXIncludeNewContext(xmlDocPtr doc) {
184 xmlXIncludeCtxtPtr ret;
186 #ifdef DEBUG_XINCLUDE
187 xmlGenericError(xmlGenericErrorContext, "New context\n");
188 #endif
189 if (doc == NULL)
190 return(NULL);
191 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
192 if (ret == NULL)
193 return(NULL);
194 memset(ret, 0, sizeof(xmlXIncludeCtxt));
195 ret->doc = doc;
196 ret->incNr = 0;
197 ret->incBase = 0;
198 ret->incMax = 0;
199 ret->incTab = NULL;
200 return(ret);
204 * xmlXIncludeFreeContext:
205 * @ctxt: the XInclude context
207 * Free an XInclude context
209 static void
210 xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
211 int i;
213 #ifdef DEBUG_XINCLUDE
214 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
215 #endif
216 if (ctxt == NULL)
217 return;
218 for (i = 0;i < ctxt->incNr;i++) {
219 if (ctxt->incTab[i] != NULL)
220 xmlXIncludeFreeRef(ctxt->incTab[i]);
222 for (i = 0;i < ctxt->txtNr;i++) {
223 if (ctxt->txturlTab[i] != NULL)
224 xmlFree(ctxt->txturlTab[i]);
226 if (ctxt->incTab != NULL)
227 xmlFree(ctxt->incTab);
228 if (ctxt->txtTab != NULL)
229 xmlFree(ctxt->txtTab);
230 if (ctxt->txturlTab != NULL)
231 xmlFree(ctxt->txturlTab);
232 xmlFree(ctxt);
236 * xmlXIncludeAddNode:
237 * @ctxt: the XInclude context
238 * @cur: the new node
240 * Add a new node to process to an XInclude context
242 static int
243 xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
244 xmlXIncludeRefPtr ref;
245 xmlURIPtr uri;
246 xmlChar *URL;
247 xmlChar *fragment = NULL;
248 xmlChar *href;
249 xmlChar *parse;
250 xmlChar *base;
251 xmlChar *URI;
252 int xml = 1; /* default Issue 64 */
255 if (ctxt == NULL)
256 return(-1);
257 if (cur == NULL)
258 return(-1);
260 #ifdef DEBUG_XINCLUDE
261 xmlGenericError(xmlGenericErrorContext, "Add node\n");
262 #endif
264 * read the attributes
266 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
267 if (href == NULL) {
268 href = xmlGetProp(cur, XINCLUDE_HREF);
269 if (href == NULL) {
270 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
271 return(-1);
274 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
275 if (parse == NULL) {
276 parse = xmlGetProp(cur, XINCLUDE_PARSE);
278 if (parse != NULL) {
279 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
280 xml = 1;
281 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
282 xml = 0;
283 else {
284 xmlGenericError(xmlGenericErrorContext,
285 "XInclude: invalid value %s for %s\n",
286 parse, XINCLUDE_PARSE);
287 if (href != NULL)
288 xmlFree(href);
289 if (parse != NULL)
290 xmlFree(parse);
291 return(-1);
296 * compute the URI
298 base = xmlNodeGetBase(ctxt->doc, cur);
299 if (base == NULL) {
300 URI = xmlBuildURI(href, ctxt->doc->URL);
301 } else {
302 URI = xmlBuildURI(href, base);
304 if (URI == NULL) {
305 xmlChar *escbase;
306 xmlChar *eschref;
308 * Some escaping may be needed
310 escbase = xmlURIEscape(base);
311 eschref = xmlURIEscape(href);
312 URI = xmlBuildURI(eschref, escbase);
313 if (escbase != NULL)
314 xmlFree(escbase);
315 if (eschref != NULL)
316 xmlFree(eschref);
318 if (parse != NULL)
319 xmlFree(parse);
320 if (href != NULL)
321 xmlFree(href);
322 if (base != NULL)
323 xmlFree(base);
324 if (URI == NULL) {
325 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
326 return(-1);
330 * Check the URL and remove any fragment identifier
332 uri = xmlParseURI((const char *)URI);
333 if (uri == NULL) {
334 xmlGenericError(xmlGenericErrorContext,
335 "XInclude: invalid value URI %s\n", URI);
336 return(-1);
338 if (uri->fragment != NULL) {
339 fragment = (xmlChar *) uri->fragment;
340 uri->fragment = NULL;
342 URL = xmlSaveUri(uri);
343 xmlFreeURI(uri);
344 xmlFree(URI);
345 if (URL == NULL) {
346 xmlGenericError(xmlGenericErrorContext,
347 "XInclude: invalid value URI %s\n", URI);
348 if (fragment != NULL)
349 xmlFree(fragment);
350 return(-1);
353 ref = xmlXIncludeNewRef(ctxt, URL, cur);
354 if (ref == NULL) {
355 return(-1);
357 ref->fragment = fragment;
358 ref->doc = NULL;
359 ref->xml = xml;
360 ref->count = 1;
361 xmlFree(URL);
362 return(0);
366 * xmlXIncludeRecurseDoc:
367 * @ctxt: the XInclude context
368 * @doc: the new document
369 * @url: the associated URL
371 * The XInclude recursive nature is handled at this point.
373 static void
374 xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
375 const xmlURL url ATTRIBUTE_UNUSED) {
376 xmlXIncludeCtxtPtr newctxt;
377 int i;
379 #ifdef DEBUG_XINCLUDE
380 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
381 #endif
383 * Handle recursion here.
386 newctxt = xmlXIncludeNewContext(doc);
387 if (newctxt != NULL) {
389 * Copy the existing document set
391 newctxt->incMax = ctxt->incMax;
392 newctxt->incNr = ctxt->incNr;
393 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
394 sizeof(newctxt->incTab[0]));
395 if (newctxt->incTab == NULL) {
396 xmlGenericError(xmlGenericErrorContext,
397 "malloc failed !\n");
398 xmlFree(newctxt);
399 return;
403 * Inherit the documents already in use by others includes
405 newctxt->incBase = ctxt->incNr;
406 for (i = 0;i < ctxt->incNr;i++) {
407 newctxt->incTab[i] = ctxt->incTab[i];
408 newctxt->incTab[i]->count++; /* prevent the recursion from
409 freeing it */
411 xmlXIncludeDoProcess(newctxt, doc);
412 for (i = 0;i < ctxt->incNr;i++) {
413 newctxt->incTab[i]->count--;
414 newctxt->incTab[i] = NULL;
416 xmlXIncludeFreeContext(newctxt);
418 #ifdef DEBUG_XINCLUDE
419 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
420 #endif
424 * xmlXIncludeAddTxt:
425 * @ctxt: the XInclude context
426 * @txt: the new text node
427 * @url: the associated URL
429 * Add a new txtument to the list
431 static void
432 xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
433 #ifdef DEBUG_XINCLUDE
434 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
435 #endif
436 if (ctxt->txtMax == 0) {
437 ctxt->txtMax = 4;
438 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
439 sizeof(ctxt->txtTab[0]));
440 if (ctxt->txtTab == NULL) {
441 xmlGenericError(xmlGenericErrorContext,
442 "malloc failed !\n");
443 return;
445 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
446 sizeof(ctxt->txturlTab[0]));
447 if (ctxt->txturlTab == NULL) {
448 xmlGenericError(xmlGenericErrorContext,
449 "malloc failed !\n");
450 return;
453 if (ctxt->txtNr >= ctxt->txtMax) {
454 ctxt->txtMax *= 2;
455 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
456 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
457 if (ctxt->txtTab == NULL) {
458 xmlGenericError(xmlGenericErrorContext,
459 "realloc failed !\n");
460 return;
462 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
463 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
464 if (ctxt->txturlTab == NULL) {
465 xmlGenericError(xmlGenericErrorContext,
466 "realloc failed !\n");
467 return;
470 ctxt->txtTab[ctxt->txtNr] = txt;
471 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
472 ctxt->txtNr++;
475 /************************************************************************
477 * Node copy with specific semantic *
479 ************************************************************************/
482 * xmlXIncludeCopyNode:
483 * @ctxt: the XInclude context
484 * @target: the document target
485 * @source: the document source
486 * @elem: the element
488 * Make a copy of the node while preserving the XInclude semantic
489 * of the Infoset copy
491 static xmlNodePtr
492 xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
493 xmlDocPtr source, xmlNodePtr elem) {
494 xmlNodePtr result = NULL;
496 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
497 (elem == NULL))
498 return(NULL);
499 if (elem->type == XML_DTD_NODE)
500 return(NULL);
501 result = xmlDocCopyNode(elem, target, 1);
502 return(result);
506 * xmlXIncludeCopyNodeList:
507 * @ctxt: the XInclude context
508 * @target: the document target
509 * @source: the document source
510 * @elem: the element list
512 * Make a copy of the node list while preserving the XInclude semantic
513 * of the Infoset copy
515 static xmlNodePtr
516 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
517 xmlDocPtr source, xmlNodePtr elem) {
518 xmlNodePtr cur, res, result = NULL, last = NULL;
520 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
521 (elem == NULL))
522 return(NULL);
523 cur = elem;
524 while (cur != NULL) {
525 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
526 if (res != NULL) {
527 if (result == NULL) {
528 result = last = res;
529 } else {
530 last->next = res;
531 res->prev = last;
532 last = res;
535 cur = cur->next;
537 return(result);
541 * xmlXInclueGetNthChild:
542 * @cur: the node
543 * @no: the child number
545 * Returns the @no'th element child of @cur or NULL
547 static xmlNodePtr
548 xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
549 int i;
550 if (cur == NULL)
551 return(cur);
552 cur = cur->children;
553 for (i = 0;i <= no;cur = cur->next) {
554 if (cur == NULL)
555 return(cur);
556 if ((cur->type == XML_ELEMENT_NODE) ||
557 (cur->type == XML_DOCUMENT_NODE) ||
558 (cur->type == XML_HTML_DOCUMENT_NODE)) {
559 i++;
560 if (i == no)
561 break;
564 return(cur);
567 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
570 * xmlXIncludeCopyRange:
571 * @ctxt: the XInclude context
572 * @target: the document target
573 * @source: the document source
574 * @obj: the XPointer result from the evaluation.
576 * Build a node list tree copy of the XPointer result.
578 * Returns an xmlNodePtr list or NULL.
579 * the caller has to free the node tree.
581 static xmlNodePtr
582 xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
583 xmlDocPtr source, xmlXPathObjectPtr range) {
584 /* pointers to generated nodes */
585 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
586 /* pointers to traversal nodes */
587 xmlNodePtr start, cur, end;
588 int index1, index2;
590 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
591 (range == NULL))
592 return(NULL);
593 if (range->type != XPATH_RANGE)
594 return(NULL);
595 start = (xmlNodePtr) range->user;
597 if (start == NULL)
598 return(NULL);
599 end = range->user2;
600 if (end == NULL)
601 return(xmlDocCopyNode(start, target, 1));
603 cur = start;
604 index1 = range->index;
605 index2 = range->index2;
606 while (cur != NULL) {
607 if (cur == end) {
608 if (cur->type == XML_TEXT_NODE) {
609 const xmlChar *content = cur->content;
610 int len;
612 if (content == NULL) {
613 tmp = xmlNewTextLen(NULL, 0);
614 } else {
615 len = index2;
616 if ((cur == start) && (index1 > 1)) {
617 content += (index1 - 1);
618 len -= (index1 - 1);
619 index1 = 0;
620 } else {
621 len = index2;
623 tmp = xmlNewTextLen(content, len);
625 /* single sub text node selection */
626 if (list == NULL)
627 return(tmp);
628 /* prune and return full set */
629 if (last != NULL)
630 xmlAddNextSibling(last, tmp);
631 else
632 xmlAddChild(parent, tmp);
633 return(list);
634 } else {
635 tmp = xmlDocCopyNode(cur, target, 0);
636 if (list == NULL)
637 list = tmp;
638 else {
639 if (last != NULL)
640 xmlAddNextSibling(last, tmp);
641 else
642 xmlAddChild(parent, tmp);
644 last = NULL;
645 parent = tmp;
647 if (index2 > 1) {
648 end = xmlXIncludeGetNthChild(cur, index2 - 1);
649 index2 = 0;
651 if ((cur == start) && (index1 > 1)) {
652 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
653 index1 = 0;
654 } else {
655 cur = cur->children;
658 * Now gather the remaining nodes from cur to end
660 continue; /* while */
662 } else if ((cur == start) &&
663 (list == NULL) /* looks superfluous but ... */ ) {
664 if ((cur->type == XML_TEXT_NODE) ||
665 (cur->type == XML_CDATA_SECTION_NODE)) {
666 const xmlChar *content = cur->content;
668 if (content == NULL) {
669 tmp = xmlNewTextLen(NULL, 0);
670 } else {
671 if (index1 > 1) {
672 content += (index1 - 1);
674 tmp = xmlNewText(content);
676 last = list = tmp;
677 } else {
678 if ((cur == start) && (index1 > 1)) {
679 tmp = xmlDocCopyNode(cur, target, 0);
680 list = tmp;
681 parent = tmp;
682 last = NULL;
683 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
684 index1 = 0;
686 * Now gather the remaining nodes from cur to end
688 continue; /* while */
690 tmp = xmlDocCopyNode(cur, target, 1);
691 list = tmp;
692 parent = NULL;
693 last = tmp;
695 } else {
696 tmp = NULL;
697 switch (cur->type) {
698 case XML_DTD_NODE:
699 case XML_ELEMENT_DECL:
700 case XML_ATTRIBUTE_DECL:
701 case XML_ENTITY_NODE:
702 /* Do not copy DTD informations */
703 break;
704 case XML_ENTITY_DECL:
705 /* handle crossing entities -> stack needed */
706 break;
707 case XML_XINCLUDE_START:
708 case XML_XINCLUDE_END:
709 /* don't consider it part of the tree content */
710 break;
711 case XML_ATTRIBUTE_NODE:
712 /* Humm, should not happen ! */
713 break;
714 default:
715 tmp = xmlDocCopyNode(cur, target, 1);
716 break;
718 if (tmp != NULL) {
719 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
720 return(NULL);
722 if (last != NULL)
723 xmlAddNextSibling(last, tmp);
724 else {
725 xmlAddChild(parent, tmp);
726 last = tmp;
731 * Skip to next node in document order
733 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
734 return(NULL);
736 cur = xmlXPtrAdvanceNode(cur);
738 return(list);
742 * xmlXIncludeBuildNodeList:
743 * @ctxt: the XInclude context
744 * @target: the document target
745 * @source: the document source
746 * @obj: the XPointer result from the evaluation.
748 * Build a node list tree copy of the XPointer result.
749 * This will drop Attributes and Namespace declarations.
751 * Returns an xmlNodePtr list or NULL.
752 * the caller has to free the node tree.
754 static xmlNodePtr
755 xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
756 xmlDocPtr source, xmlXPathObjectPtr obj) {
757 xmlNodePtr list = NULL, last = NULL;
758 int i;
760 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
761 (obj == NULL))
762 return(NULL);
763 switch (obj->type) {
764 case XPATH_NODESET: {
765 xmlNodeSetPtr set = obj->nodesetval;
766 if (set == NULL)
767 return(NULL);
768 for (i = 0;i < set->nodeNr;i++) {
769 if (set->nodeTab[i] == NULL)
770 continue;
771 switch (set->nodeTab[i]->type) {
772 case XML_TEXT_NODE:
773 case XML_CDATA_SECTION_NODE:
774 case XML_ELEMENT_NODE:
775 case XML_ENTITY_REF_NODE:
776 case XML_ENTITY_NODE:
777 case XML_PI_NODE:
778 case XML_COMMENT_NODE:
779 case XML_DOCUMENT_NODE:
780 case XML_HTML_DOCUMENT_NODE:
781 #ifdef LIBXML_DOCB_ENABLED
782 case XML_DOCB_DOCUMENT_NODE:
783 #endif
784 case XML_XINCLUDE_START:
785 case XML_XINCLUDE_END:
786 break;
787 case XML_ATTRIBUTE_NODE:
788 case XML_NAMESPACE_DECL:
789 case XML_DOCUMENT_TYPE_NODE:
790 case XML_DOCUMENT_FRAG_NODE:
791 case XML_NOTATION_NODE:
792 case XML_DTD_NODE:
793 case XML_ELEMENT_DECL:
794 case XML_ATTRIBUTE_DECL:
795 case XML_ENTITY_DECL:
796 continue; /* for */
798 if (last == NULL)
799 list = last = xmlXIncludeCopyNode(ctxt, target, source,
800 set->nodeTab[i]);
801 else {
802 xmlAddNextSibling(last,
803 xmlXIncludeCopyNode(ctxt, target, source,
804 set->nodeTab[i]));
805 if (last->next != NULL)
806 last = last->next;
809 break;
811 case XPATH_LOCATIONSET: {
812 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
813 if (set == NULL)
814 return(NULL);
815 for (i = 0;i < set->locNr;i++) {
816 if (last == NULL)
817 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
818 set->locTab[i]);
819 else
820 xmlAddNextSibling(last,
821 xmlXIncludeCopyXPointer(ctxt, target, source,
822 set->locTab[i]));
823 if (last != NULL) {
824 while (last->next != NULL)
825 last = last->next;
828 break;
830 case XPATH_RANGE:
831 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
832 case XPATH_POINT:
833 /* points are ignored in XInclude */
834 break;
835 default:
836 break;
838 return(list);
840 /************************************************************************
842 * XInclude I/O handling *
844 ************************************************************************/
847 * xmlXIncludeLoadDoc:
848 * @ctxt: the XInclude context
849 * @url: the associated URL
850 * @nr: the xinclude node number
852 * Load the document, and store the result in the XInclude context
854 * Returns 0 in case of success, -1 in case of failure
856 static int
857 xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
858 xmlDocPtr doc;
859 xmlURIPtr uri;
860 xmlChar *URL;
861 xmlChar *fragment = NULL;
862 int i = 0;
864 #ifdef DEBUG_XINCLUDE
865 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
866 #endif
868 * Check the URL and remove any fragment identifier
870 uri = xmlParseURI((const char *)url);
871 if (uri == NULL) {
872 xmlGenericError(xmlGenericErrorContext,
873 "XInclude: invalid value URI %s\n", url);
874 return(-1);
876 if (uri->fragment != NULL) {
877 fragment = (xmlChar *) uri->fragment;
878 uri->fragment = NULL;
880 URL = xmlSaveUri(uri);
881 xmlFreeURI(uri);
882 if (URL == NULL) {
883 xmlGenericError(xmlGenericErrorContext,
884 "XInclude: invalid value URI %s\n", url);
885 if (fragment != NULL)
886 xmlFree(fragment);
887 return(-1);
891 * Handling of references to the local document are done
892 * directly through ctxt->doc.
894 if ((URL[0] == 0) || (URL[0] == '#')) {
895 doc = NULL;
896 goto loaded;
900 * Prevent reloading twice the document.
902 for (i = 0; i < ctxt->incNr; i++) {
903 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
904 (ctxt->incTab[i]->doc != NULL)) {
905 doc = ctxt->incTab[i]->doc;
906 #ifdef DEBUG_XINCLUDE
907 printf("Already loaded %s\n", URL);
908 #endif
909 goto loaded;
914 * Load it.
916 #ifdef DEBUG_XINCLUDE
917 printf("loading %s\n", URL);
918 #endif
919 doc = xmlParseFile((const char *)URL);
920 if (doc == NULL) {
921 xmlFree(URL);
922 if (fragment != NULL)
923 xmlFree(fragment);
924 return(-1);
926 ctxt->incTab[nr]->doc = doc;
929 * TODO: Make sure we have all entities fixed up
933 * We don't need the DTD anymore, free up space
934 if (doc->intSubset != NULL) {
935 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
936 xmlFreeNode((xmlNodePtr) doc->intSubset);
937 doc->intSubset = NULL;
939 if (doc->extSubset != NULL) {
940 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
941 xmlFreeNode((xmlNodePtr) doc->extSubset);
942 doc->extSubset = NULL;
945 xmlXIncludeRecurseDoc(ctxt, doc, URL);
947 loaded:
948 if (fragment == NULL) {
950 * Add the top children list as the replacement copy.
952 if (doc == NULL)
954 /* Hopefully a DTD declaration won't be copied from
955 * the same document */
956 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
957 } else {
958 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
959 doc, doc->children);
961 } else {
963 * Computes the XPointer expression and make a copy used
964 * as the replacement copy.
966 xmlXPathObjectPtr xptr;
967 xmlXPathContextPtr xptrctxt;
968 xmlNodeSetPtr set;
970 if (doc == NULL) {
971 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
972 NULL);
973 } else {
974 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
976 if (xptrctxt == NULL) {
977 xmlGenericError(xmlGenericErrorContext,
978 "XInclude: could create XPointer context\n");
979 xmlFree(URL);
980 xmlFree(fragment);
981 return(-1);
983 xptr = xmlXPtrEval(fragment, xptrctxt);
984 if (xptr == NULL) {
985 xmlGenericError(xmlGenericErrorContext,
986 "XInclude: XPointer evaluation failed: #%s\n",
987 fragment);
988 xmlXPathFreeContext(xptrctxt);
989 xmlFree(URL);
990 xmlFree(fragment);
991 return(-1);
993 switch (xptr->type) {
994 case XPATH_UNDEFINED:
995 case XPATH_BOOLEAN:
996 case XPATH_NUMBER:
997 case XPATH_STRING:
998 case XPATH_POINT:
999 case XPATH_USERS:
1000 case XPATH_XSLT_TREE:
1001 xmlGenericError(xmlGenericErrorContext,
1002 "XInclude: XPointer is not a range: #%s\n",
1003 fragment);
1004 xmlXPathFreeContext(xptrctxt);
1005 xmlFree(URL);
1006 xmlFree(fragment);
1007 return(-1);
1008 case XPATH_NODESET:
1009 case XPATH_RANGE:
1010 case XPATH_LOCATIONSET:
1011 break;
1013 set = xptr->nodesetval;
1014 if (set != NULL) {
1015 for (i = 0;i < set->nodeNr;i++) {
1016 if (set->nodeTab[i] == NULL)
1017 continue;
1018 switch (set->nodeTab[i]->type) {
1019 case XML_TEXT_NODE:
1020 case XML_CDATA_SECTION_NODE:
1021 case XML_ELEMENT_NODE:
1022 case XML_ENTITY_REF_NODE:
1023 case XML_ENTITY_NODE:
1024 case XML_PI_NODE:
1025 case XML_COMMENT_NODE:
1026 case XML_DOCUMENT_NODE:
1027 case XML_HTML_DOCUMENT_NODE:
1028 #ifdef LIBXML_DOCB_ENABLED
1029 case XML_DOCB_DOCUMENT_NODE:
1030 #endif
1031 continue;
1032 case XML_ATTRIBUTE_NODE:
1033 xmlGenericError(xmlGenericErrorContext,
1034 "XInclude: XPointer selects an attribute: #%s\n",
1035 fragment);
1036 set->nodeTab[i] = NULL;
1037 continue;
1038 case XML_NAMESPACE_DECL:
1039 xmlGenericError(xmlGenericErrorContext,
1040 "XInclude: XPointer selects a namespace: #%s\n",
1041 fragment);
1042 set->nodeTab[i] = NULL;
1043 continue;
1044 case XML_DOCUMENT_TYPE_NODE:
1045 case XML_DOCUMENT_FRAG_NODE:
1046 case XML_NOTATION_NODE:
1047 case XML_DTD_NODE:
1048 case XML_ELEMENT_DECL:
1049 case XML_ATTRIBUTE_DECL:
1050 case XML_ENTITY_DECL:
1051 case XML_XINCLUDE_START:
1052 case XML_XINCLUDE_END:
1053 xmlGenericError(xmlGenericErrorContext,
1054 "XInclude: XPointer selects unexpected nodes: #%s\n",
1055 fragment);
1056 set->nodeTab[i] = NULL;
1057 set->nodeTab[i] = NULL;
1058 continue; /* for */
1062 ctxt->incTab[nr]->inc =
1063 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1064 xmlXPathFreeObject(xptr);
1065 xmlXPathFreeContext(xptrctxt);
1066 xmlFree(fragment);
1070 * Do the xml:base fixup if needed
1072 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1073 xmlNodePtr node;
1075 node = ctxt->incTab[nr]->inc;
1076 while (node != NULL) {
1077 if (node->type == XML_ELEMENT_NODE)
1078 xmlNodeSetBase(node, URL);
1079 node = node->next;
1082 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1083 (ctxt->incTab[nr]->count <= 1)) {
1084 #ifdef DEBUG_XINCLUDE
1085 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1086 #endif
1087 xmlFreeDoc(ctxt->incTab[nr]->doc);
1088 ctxt->incTab[nr]->doc = NULL;
1090 xmlFree(URL);
1091 return(0);
1095 * xmlXIncludeLoadTxt:
1096 * @ctxt: the XInclude context
1097 * @url: the associated URL
1098 * @nr: the xinclude node number
1100 * Load the content, and store the result in the XInclude context
1102 * Returns 0 in case of success, -1 in case of failure
1104 static int
1105 xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1106 xmlParserInputBufferPtr buf;
1107 xmlNodePtr node;
1108 xmlURIPtr uri;
1109 xmlChar *URL;
1110 int i;
1111 xmlChar *encoding = NULL;
1112 xmlCharEncoding enc = 0;
1115 * Check the URL and remove any fragment identifier
1117 uri = xmlParseURI((const char *)url);
1118 if (uri == NULL) {
1119 xmlGenericError(xmlGenericErrorContext,
1120 "XInclude: invalid value URI %s\n", url);
1121 return(-1);
1123 if (uri->fragment != NULL) {
1124 xmlGenericError(xmlGenericErrorContext,
1125 "XInclude: fragment identifier forbidden for text: %s\n",
1126 uri->fragment);
1127 xmlFreeURI(uri);
1128 return(-1);
1130 URL = xmlSaveUri(uri);
1131 xmlFreeURI(uri);
1132 if (URL == NULL) {
1133 xmlGenericError(xmlGenericErrorContext,
1134 "XInclude: invalid value URI %s\n", url);
1135 return(-1);
1139 * Handling of references to the local document are done
1140 * directly through ctxt->doc.
1142 if (URL[0] == 0) {
1143 xmlGenericError(xmlGenericErrorContext,
1144 "XInclude: text serialization of document not available\n");
1145 xmlFree(URL);
1146 return(-1);
1150 * Prevent reloading twice the document.
1152 for (i = 0; i < ctxt->txtNr; i++) {
1153 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1154 node = xmlCopyNode(ctxt->txtTab[i], 1);
1155 goto loaded;
1159 * Try to get the encoding if available
1161 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1162 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1164 if (encoding != NULL) {
1166 * TODO: we should not have to remap to the xmlCharEncoding
1167 * predefined set, a better interface than
1168 * xmlParserInputBufferCreateFilename should allow any
1169 * encoding supported by iconv
1171 enc = xmlParseCharEncoding((const char *) encoding);
1172 if (enc == XML_CHAR_ENCODING_ERROR) {
1173 xmlGenericError(xmlGenericErrorContext,
1174 "XInclude: encoding %s not supported\n", encoding);
1175 xmlFree(encoding);
1176 xmlFree(URL);
1177 return(-1);
1179 xmlFree(encoding);
1183 * Load it.
1185 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
1186 if (buf == NULL) {
1187 xmlFree(URL);
1188 return(-1);
1190 node = xmlNewText(NULL);
1193 * Scan all chars from the resource and add the to the node
1195 while (xmlParserInputBufferRead(buf, 128) > 0) {
1196 int len;
1197 const xmlChar *content;
1199 content = xmlBufferContent(buf->buffer);
1200 len = xmlBufferLength(buf->buffer);
1201 for (i = 0;i < len;) {
1202 int cur;
1203 int l;
1205 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1206 if (!IS_CHAR(cur)) {
1207 xmlGenericError(xmlGenericErrorContext,
1208 "XInclude: %s contains invalid char %d\n", URL, cur);
1209 } else {
1210 xmlNodeAddContentLen(node, &content[i], l);
1212 i += l;
1214 xmlBufferShrink(buf->buffer, len);
1216 xmlFreeParserInputBuffer(buf);
1217 xmlXIncludeAddTxt(ctxt, node, URL);
1219 loaded:
1221 * Add the element as the replacement copy.
1223 ctxt->incTab[nr]->inc = node;
1224 xmlFree(URL);
1225 return(0);
1229 * xmlXIncludeLoadFallback:
1230 * @ctxt: the XInclude context
1231 * @fallback: the fallback node
1232 * @nr: the xinclude node number
1234 * Load the content of the fallback node, and store the result
1235 * in the XInclude context
1237 * Returns 0 in case of success, -1 in case of failure
1239 static int
1240 xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1241 if ((fallback == NULL) || (ctxt == NULL))
1242 return(-1);
1244 ctxt->incTab[nr]->inc = xmlCopyNode(fallback->children, 1);
1245 return(0);
1248 /************************************************************************
1250 * XInclude Processing *
1252 ************************************************************************/
1255 * xmlXIncludePreProcessNode:
1256 * @ctxt: an XInclude context
1257 * @node: an XInclude node
1259 * Implement the XInclude preprocessing, currently just adding the element
1260 * for further processing.
1262 * Returns the result list or NULL in case of error
1264 static xmlNodePtr
1265 xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1266 xmlXIncludeAddNode(ctxt, node);
1267 return(0);
1270 #if 0
1272 * xmlXIncludePreloadNode:
1273 * @ctxt: an XInclude context
1274 * @nr: the node number
1276 * Do some precomputations and preload shared documents
1278 * Returns 0 if substitution succeeded, -1 if some processing failed
1280 static int
1281 xmlXIncludePreloadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1282 xmlNodePtr cur;
1283 xmlChar *href;
1284 xmlChar *parse;
1285 xmlChar *base;
1286 xmlChar *URI;
1287 int xml = 1; /* default Issue 64 */
1288 xmlURIPtr uri;
1289 xmlChar *URL;
1290 xmlChar *fragment = NULL;
1291 int i;
1294 if (ctxt == NULL)
1295 return(-1);
1296 if ((nr < 0) || (nr >= ctxt->incNr))
1297 return(-1);
1298 cur = ctxt->incTab[nr]->ref;
1299 if (cur == NULL)
1300 return(-1);
1303 * read the attributes
1305 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1306 if (href == NULL) {
1307 href = xmlGetProp(cur, XINCLUDE_HREF);
1308 if (href == NULL) {
1309 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1310 return(-1);
1313 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1314 if (parse == NULL) {
1315 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1317 if (parse != NULL) {
1318 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1319 xml = 1;
1320 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1321 xml = 0;
1322 else {
1323 xmlGenericError(xmlGenericErrorContext,
1324 "XInclude: invalid value %s for %s\n",
1325 parse, XINCLUDE_PARSE);
1326 if (href != NULL)
1327 xmlFree(href);
1328 if (parse != NULL)
1329 xmlFree(parse);
1330 return(-1);
1335 * compute the URI
1337 base = xmlNodeGetBase(ctxt->doc, cur);
1338 if (base == NULL) {
1339 URI = xmlBuildURI(href, ctxt->doc->URL);
1340 } else {
1341 URI = xmlBuildURI(href, base);
1343 if (URI == NULL) {
1344 xmlChar *escbase;
1345 xmlChar *eschref;
1347 * Some escaping may be needed
1349 escbase = xmlURIEscape(base);
1350 eschref = xmlURIEscape(href);
1351 URI = xmlBuildURI(eschref, escbase);
1352 if (escbase != NULL)
1353 xmlFree(escbase);
1354 if (eschref != NULL)
1355 xmlFree(eschref);
1357 if (parse != NULL)
1358 xmlFree(parse);
1359 if (href != NULL)
1360 xmlFree(href);
1361 if (base != NULL)
1362 xmlFree(base);
1363 if (URI == NULL) {
1364 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1365 return(-1);
1369 * Check the URL and remove any fragment identifier
1371 uri = xmlParseURI((const char *)URI);
1372 if (uri == NULL) {
1373 xmlGenericError(xmlGenericErrorContext,
1374 "XInclude: invalid value URI %s\n", URI);
1375 xmlFree(URI);
1376 return(-1);
1378 if (uri->fragment != NULL) {
1379 fragment = (xmlChar *) uri->fragment;
1380 uri->fragment = NULL;
1382 URL = xmlSaveUri(uri);
1383 xmlFreeURI(uri);
1384 if (URL == NULL) {
1385 xmlGenericError(xmlGenericErrorContext,
1386 "XInclude: invalid value URI %s\n", URI);
1387 if (fragment != NULL)
1388 xmlFree(fragment);
1389 xmlFree(URI);
1390 return(-1);
1392 xmlFree(URI);
1393 if (fragment != NULL)
1394 xmlFree(fragment);
1396 for (i = 0; i < nr; i++) {
1397 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1398 #ifdef DEBUG_XINCLUDE
1399 printf("Incrementing count for %d : %s\n", i, ctxt->incTab[i]->URI);
1400 #endif
1401 ctxt->incTab[i]->count++;
1402 break;
1405 xmlFree(URL);
1406 return(0);
1408 #endif
1411 * xmlXIncludeLoadNode:
1412 * @ctxt: an XInclude context
1413 * @nr: the node number
1415 * Find and load the infoset replacement for the given node.
1417 * Returns 0 if substitution succeeded, -1 if some processing failed
1419 static int
1420 xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1421 xmlNodePtr cur;
1422 xmlChar *href;
1423 xmlChar *parse;
1424 xmlChar *base;
1425 xmlChar *URI;
1426 int xml = 1; /* default Issue 64 */
1427 int ret;
1429 if (ctxt == NULL)
1430 return(-1);
1431 if ((nr < 0) || (nr >= ctxt->incNr))
1432 return(-1);
1433 cur = ctxt->incTab[nr]->ref;
1434 if (cur == NULL)
1435 return(-1);
1438 * read the attributes
1440 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1441 if (href == NULL) {
1442 href = xmlGetProp(cur, XINCLUDE_HREF);
1443 if (href == NULL) {
1444 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1445 return(-1);
1448 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1449 if (parse == NULL) {
1450 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1452 if (parse != NULL) {
1453 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1454 xml = 1;
1455 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1456 xml = 0;
1457 else {
1458 xmlGenericError(xmlGenericErrorContext,
1459 "XInclude: invalid value %s for %s\n",
1460 parse, XINCLUDE_PARSE);
1461 if (href != NULL)
1462 xmlFree(href);
1463 if (parse != NULL)
1464 xmlFree(parse);
1465 return(-1);
1470 * compute the URI
1472 base = xmlNodeGetBase(ctxt->doc, cur);
1473 if (base == NULL) {
1474 URI = xmlBuildURI(href, ctxt->doc->URL);
1475 } else {
1476 URI = xmlBuildURI(href, base);
1478 if (URI == NULL) {
1479 xmlChar *escbase;
1480 xmlChar *eschref;
1482 * Some escaping may be needed
1484 escbase = xmlURIEscape(base);
1485 eschref = xmlURIEscape(href);
1486 URI = xmlBuildURI(eschref, escbase);
1487 if (escbase != NULL)
1488 xmlFree(escbase);
1489 if (eschref != NULL)
1490 xmlFree(eschref);
1492 if (URI == NULL) {
1493 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1494 if (parse != NULL)
1495 xmlFree(parse);
1496 if (href != NULL)
1497 xmlFree(href);
1498 if (base != NULL)
1499 xmlFree(base);
1500 return(-1);
1502 #ifdef DEBUG_XINCLUDE
1503 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1504 xml ? "xml": "text");
1505 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1506 #endif
1509 * Cleanup
1511 if (xml) {
1512 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
1513 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1514 } else {
1515 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1517 if (ret < 0) {
1518 xmlNodePtr children;
1521 * Time to try a fallback if availble
1523 #ifdef DEBUG_XINCLUDE
1524 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1525 #endif
1526 children = cur->children;
1527 while (children != NULL) {
1528 if ((children->type == XML_ELEMENT_NODE) &&
1529 (children->ns != NULL) &&
1530 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1531 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1532 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1533 if (ret == 0)
1534 break;
1536 children = children->next;
1539 if (ret < 0) {
1540 xmlGenericError(xmlGenericErrorContext,
1541 "XInclude: could not load %s, and no fallback was found\n",
1542 URI);
1546 * Cleanup
1548 if (URI != NULL)
1549 xmlFree(URI);
1550 if (parse != NULL)
1551 xmlFree(parse);
1552 if (href != NULL)
1553 xmlFree(href);
1554 if (base != NULL)
1555 xmlFree(base);
1556 return(0);
1560 * xmlXIncludeIncludeNode:
1561 * @ctxt: an XInclude context
1562 * @nr: the node number
1564 * Inplement the infoset replacement for the given node
1566 * Returns 0 if substitution succeeded, -1 if some processing failed
1568 static int
1569 xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1570 xmlNodePtr cur, end, list;
1572 if (ctxt == NULL)
1573 return(-1);
1574 if ((nr < 0) || (nr >= ctxt->incNr))
1575 return(-1);
1576 cur = ctxt->incTab[nr]->ref;
1577 if (cur == NULL)
1578 return(-1);
1581 * Change the current node as an XInclude start one, and add an
1582 * entity end one
1584 cur->type = XML_XINCLUDE_START;
1585 end = xmlNewNode(cur->ns, cur->name);
1586 if (end == NULL) {
1587 xmlGenericError(xmlGenericErrorContext,
1588 "XInclude: failed to build node\n");
1589 return(-1);
1591 end->type = XML_XINCLUDE_END;
1592 xmlAddNextSibling(cur, end);
1595 * Add the list of nodes
1597 list = ctxt->incTab[nr]->inc;
1598 ctxt->incTab[nr]->inc = NULL;
1599 while (list != NULL) {
1600 cur = list;
1601 list = list->next;
1603 xmlAddPrevSibling(end, cur);
1607 return(0);
1611 * xmlXIncludeTestNode:
1612 * @node: an XInclude node
1614 * test if the node is an XInclude node
1616 * Returns 1 true, 0 otherwise
1618 static int
1619 xmlXIncludeTestNode(xmlNodePtr node) {
1620 if (node == NULL)
1621 return(0);
1622 if (node->ns == NULL)
1623 return(0);
1624 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
1625 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
1626 return(0);
1630 * xmlXIncludeDoProcess:
1631 * @ctxt:
1632 * @doc: an XML document
1634 * Implement the XInclude substitution on the XML document @doc
1636 * Returns 0 if no substitution were done, -1 if some processing failed
1637 * or the number of substitutions done.
1639 static int
1640 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
1641 xmlNodePtr cur;
1642 int ret = 0;
1643 int i;
1645 if (doc == NULL)
1646 return(-1);
1647 if (ctxt == NULL)
1648 return(-1);
1651 * First phase: lookup the elements in the document
1653 cur = xmlDocGetRootElement(doc);
1654 if (xmlXIncludeTestNode(cur))
1655 xmlXIncludePreProcessNode(ctxt, cur);
1656 while (cur != NULL) {
1657 /* TODO: need to work on entities -> stack */
1658 if ((cur->children != NULL) &&
1659 (cur->children->type != XML_ENTITY_DECL)) {
1660 cur = cur->children;
1661 if (xmlXIncludeTestNode(cur))
1662 xmlXIncludePreProcessNode(ctxt, cur);
1663 } else if (cur->next != NULL) {
1664 cur = cur->next;
1665 if (xmlXIncludeTestNode(cur))
1666 xmlXIncludePreProcessNode(ctxt, cur);
1667 } else {
1668 do {
1669 cur = cur->parent;
1670 if (cur == NULL) break; /* do */
1671 if (cur->next != NULL) {
1672 cur = cur->next;
1673 if (xmlXIncludeTestNode(cur))
1674 xmlXIncludePreProcessNode(ctxt, cur);
1675 break; /* do */
1677 } while (cur != NULL);
1682 * Second Phase : collect the infosets fragments
1685 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
1686 xmlXIncludePreloadNode(ctxt, i);
1689 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
1690 xmlXIncludeLoadNode(ctxt, i);
1694 * Third phase: extend the original document infoset.
1696 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
1697 xmlXIncludeIncludeNode(ctxt, i);
1700 return(ret);
1704 * xmlXIncludeProcess:
1705 * @doc: an XML document
1707 * Implement the XInclude substitution on the XML document @doc
1709 * Returns 0 if no substitution were done, -1 if some processing failed
1710 * or the number of substitutions done.
1713 xmlXIncludeProcess(xmlDocPtr doc) {
1714 xmlXIncludeCtxtPtr ctxt;
1715 int ret = 0;
1717 if (doc == NULL)
1718 return(-1);
1719 ctxt = xmlXIncludeNewContext(doc);
1720 if (ctxt == NULL)
1721 return(-1);
1722 ret = xmlXIncludeDoProcess(ctxt, doc);
1724 xmlXIncludeFreeContext(ctxt);
1725 return(ret);
1728 #else /* !LIBXML_XINCLUDE_ENABLED */
1729 #endif