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.
16 #include <libxml/xmlmemory.h>
17 #include <libxml/tree.h>
18 #include <libxml/parser.h>
19 #include <libxml/uri.h>
20 #include <libxml/xpointer.h>
21 #include <libxml/parserInternals.h>
22 #include <libxml/xmlerror.h>
23 #include <libxml/encoding.h>
24 #include <libxml/globals.h>
26 #ifdef LIBXML_XINCLUDE_ENABLED
27 #include <libxml/xinclude.h>
29 #define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
30 #define XINCLUDE_NODE (const xmlChar *) "include"
31 #define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
32 #define XINCLUDE_HREF (const xmlChar *) "href"
33 #define XINCLUDE_PARSE (const xmlChar *) "parse"
34 #define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
35 #define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
36 #define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
38 #define XINCLUDE_MAX_DEPTH 40
40 /* #define DEBUG_XINCLUDE */
42 #ifdef LIBXML_DEBUG_ENABLED
43 #include <libxml/debugXML.h>
47 /************************************************************************
49 * XInclude contexts handling *
51 ************************************************************************/
56 typedef xmlChar *xmlURL;
58 typedef struct _xmlXIncludeRef xmlXIncludeRef;
59 typedef xmlXIncludeRef *xmlXIncludeRefPtr;
60 struct _xmlXIncludeRef {
61 xmlChar *URI; /* the rully resolved resource URL */
62 xmlChar *fragment; /* the fragment in the URI */
63 xmlDocPtr doc; /* the parsed document */
64 xmlNodePtr ref; /* the node making the reference in the source */
65 xmlNodePtr inc; /* the included copy */
66 int xml; /* xml or txt */
67 int count; /* how many refs use that specific doc */
68 xmlXPathObjectPtr xptr; /* the xpointer if needed */
71 typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
72 typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
73 struct _xmlXIncludeCtxt {
74 xmlDocPtr doc; /* the source document */
75 int incBase; /* the first include for this document */
76 int incNr; /* number of includes */
77 int incMax; /* size of includes tab */
78 xmlXIncludeRefPtr *incTab; /* array of included references */
80 int txtNr; /* number of unparsed documents */
81 int txtMax; /* size of unparsed documents tab */
82 xmlNodePtr *txtTab; /* array of unparsed text nodes */
83 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
85 xmlChar * url; /* the current URL processed */
86 int urlNr; /* number of url stacked */
87 int urlMax; /* size of url stack */
88 xmlChar * *urlTab; /* url stack */
90 int nbErrors; /* the number of errors detected */
94 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
98 * xmlXIncludeErrorContext:
99 * @ctxt: the XInclude context
102 * Dump informations about the kocation of the error in the instance
105 xmlXIncludeErrorContext(xmlXIncludeCtxtPtr ctxt ATTRIBUTE_UNUSED,
109 const xmlChar *file = NULL;
110 const xmlChar *name = NULL;
111 const char *type = "error";
117 if ((node->type == XML_DOCUMENT_NODE) ||
118 (node->type == XML_HTML_DOCUMENT_NODE)) {
119 xmlDocPtr doc = (xmlDocPtr) node;
124 * Try to find contextual informations to report
126 if (node->type == XML_ELEMENT_NODE) {
127 line = (long) node->content;
128 } else if ((node->prev != NULL) &&
129 (node->prev->type == XML_ELEMENT_NODE)) {
130 line = (long) node->prev->content;
131 } else if ((node->parent != NULL) &&
132 (node->parent->type == XML_ELEMENT_NODE)) {
133 line = (long) node->parent->content;
135 if ((node->doc != NULL) && (node->doc->URL != NULL))
136 file = node->doc->URL;
137 if (node->name != NULL)
144 if ((file != NULL) && (line != 0) && (name != NULL))
145 xmlGenericError(xmlGenericErrorContext,
146 "%s: file %s line %d element %s\n", type, file,
148 else if ((file != NULL) && (name != NULL))
149 xmlGenericError(xmlGenericErrorContext, "%s: file %s element %s\n",
151 else if ((file != NULL) && (line != 0))
152 xmlGenericError(xmlGenericErrorContext, "%s: file %s line %d\n",
154 else if (file != NULL)
155 xmlGenericError(xmlGenericErrorContext, "%s: file %s\n", type,
157 else if (name != NULL)
158 xmlGenericError(xmlGenericErrorContext, "%s: element %s\n", type,
161 xmlGenericError(xmlGenericErrorContext, "%s\n", type);
165 * xmlXIncludeFreeRef:
166 * @ref: the XInclude reference
168 * Free an XInclude reference
171 xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
174 #ifdef DEBUG_XINCLUDE
175 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
177 if (ref->doc != NULL) {
178 #ifdef DEBUG_XINCLUDE
179 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
181 xmlFreeDoc(ref->doc);
183 if (ref->URI != NULL)
185 if (ref->fragment != NULL)
186 xmlFree(ref->fragment);
187 if (ref->xptr != NULL)
188 xmlXPathFreeObject(ref->xptr);
194 * @ctxt: the XInclude context
195 * @URI: the resource URI
197 * Creates a new reference within an XInclude context
199 * Returns the new set
201 static xmlXIncludeRefPtr
202 xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
204 xmlXIncludeRefPtr ret;
206 #ifdef DEBUG_XINCLUDE
207 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
209 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
212 memset(ret, 0, sizeof(xmlXIncludeRef));
216 ret->URI = xmlStrdup(URI);
217 ret->fragment = NULL;
223 if (ctxt->incMax == 0) {
225 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
226 sizeof(ctxt->incTab[0]));
227 if (ctxt->incTab == NULL) {
228 xmlXIncludeErrorContext(ctxt, NULL);
229 xmlGenericError(xmlGenericErrorContext,
230 "malloc failed !\n");
232 xmlXIncludeFreeRef(ret);
236 if (ctxt->incNr >= ctxt->incMax) {
238 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
239 ctxt->incMax * sizeof(ctxt->incTab[0]));
240 if (ctxt->incTab == NULL) {
241 xmlXIncludeErrorContext(ctxt, NULL);
242 xmlGenericError(xmlGenericErrorContext,
243 "realloc failed !\n");
244 xmlXIncludeFreeRef(ret);
248 ctxt->incTab[ctxt->incNr++] = ret;
253 * xmlXIncludeNewContext:
254 * @doc: an XML Document
256 * Creates a new XInclude context
258 * Returns the new set
260 static xmlXIncludeCtxtPtr
261 xmlXIncludeNewContext(xmlDocPtr doc) {
262 xmlXIncludeCtxtPtr ret;
264 #ifdef DEBUG_XINCLUDE
265 xmlGenericError(xmlGenericErrorContext, "New context\n");
269 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
272 memset(ret, 0, sizeof(xmlXIncludeCtxt));
283 * xmlXIncludeURLPush:
284 * @ctxt: the parser context
287 * Pushes a new url on top of the url stack
289 * Returns -1 in case of error, the index in the stack otherwise
292 xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
293 const xmlChar *value)
295 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
296 xmlXIncludeErrorContext(ctxt, NULL);
297 xmlGenericError(xmlGenericErrorContext,
298 "XInclude: detected a recursion in %s\n",
303 if (ctxt->urlTab == NULL) {
306 ctxt->urlTab = (xmlChar * *) xmlMalloc(
307 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
308 if (ctxt->urlTab == NULL) {
309 xmlXIncludeErrorContext(ctxt, NULL);
310 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
314 if (ctxt->urlNr >= ctxt->urlMax) {
317 (xmlChar * *) xmlRealloc(ctxt->urlTab,
319 sizeof(ctxt->urlTab[0]));
320 if (ctxt->urlTab == NULL) {
321 xmlXIncludeErrorContext(ctxt, NULL);
322 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
326 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
327 return (ctxt->urlNr++);
332 * @ctxt: the parser context
334 * Pops the top url from the url stack
337 xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
341 if (ctxt->urlNr <= 0)
345 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
348 ret = ctxt->urlTab[ctxt->urlNr];
349 ctxt->urlTab[ctxt->urlNr] = 0;
355 * xmlXIncludeFreeContext:
356 * @ctxt: the XInclude context
358 * Free an XInclude context
361 xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
364 #ifdef DEBUG_XINCLUDE
365 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
369 while (ctxt->urlNr > 0)
370 xmlXIncludeURLPop(ctxt);
371 if (ctxt->urlTab != NULL)
372 xmlFree(ctxt->urlTab);
373 for (i = 0;i < ctxt->incNr;i++) {
374 if (ctxt->incTab[i] != NULL)
375 xmlXIncludeFreeRef(ctxt->incTab[i]);
377 for (i = 0;i < ctxt->txtNr;i++) {
378 if (ctxt->txturlTab[i] != NULL)
379 xmlFree(ctxt->txturlTab[i]);
381 if (ctxt->incTab != NULL)
382 xmlFree(ctxt->incTab);
383 if (ctxt->txtTab != NULL)
384 xmlFree(ctxt->txtTab);
385 if (ctxt->txturlTab != NULL)
386 xmlFree(ctxt->txturlTab);
391 * xmlXIncludeParseFile:
392 * @ctxt: the XInclude context
393 * @URL: the URL or file path
395 * parse an document for XInclude
398 xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt ATTRIBUTE_UNUSED, const char *URL) {
400 xmlParserCtxtPtr pctxt;
401 char *directory = NULL;
405 pctxt = xmlCreateFileParserCtxt(URL);
410 if ((pctxt->directory == NULL) && (directory == NULL))
411 directory = xmlParserGetDirectory(URL);
412 if ((pctxt->directory == NULL) && (directory != NULL))
413 pctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
415 pctxt->loadsubset = XML_DETECT_IDS;
417 xmlParseDocument(pctxt);
419 if (pctxt->wellFormed)
423 xmlFreeDoc(pctxt->myDoc);
426 xmlFreeParserCtxt(pctxt);
432 * xmlXIncludeAddNode:
433 * @ctxt: the XInclude context
436 * Add a new node to process to an XInclude context
439 xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
440 xmlXIncludeRefPtr ref;
443 xmlChar *fragment = NULL;
448 int xml = 1, i; /* default Issue 64 */
457 #ifdef DEBUG_XINCLUDE
458 xmlGenericError(xmlGenericErrorContext, "Add node\n");
461 * read the attributes
463 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
465 href = xmlGetProp(cur, XINCLUDE_HREF);
467 xmlXIncludeErrorContext(ctxt, cur);
468 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
475 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
477 parse = xmlGetProp(cur, XINCLUDE_PARSE);
480 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
482 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
485 xmlXIncludeErrorContext(ctxt, cur);
486 xmlGenericError(xmlGenericErrorContext,
487 "XInclude: invalid value %s for %s\n",
488 parse, XINCLUDE_PARSE);
501 base = xmlNodeGetBase(ctxt->doc, cur);
503 URI = xmlBuildURI(href, ctxt->doc->URL);
505 URI = xmlBuildURI(href, base);
511 * Some escaping may be needed
513 escbase = xmlURIEscape(base);
514 eschref = xmlURIEscape(href);
515 URI = xmlBuildURI(eschref, escbase);
528 xmlXIncludeErrorContext(ctxt, cur);
529 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
535 * Check the URL and remove any fragment identifier
537 uri = xmlParseURI((const char *)URI);
539 xmlXIncludeErrorContext(ctxt, cur);
540 xmlGenericError(xmlGenericErrorContext,
541 "XInclude: invalid value URI %s\n", URI);
545 if (uri->fragment != NULL) {
546 fragment = (xmlChar *) uri->fragment;
547 uri->fragment = NULL;
549 URL = xmlSaveUri(uri);
553 xmlXIncludeErrorContext(ctxt, cur);
554 xmlGenericError(xmlGenericErrorContext,
555 "XInclude: invalid value URI %s\n", URI);
557 if (fragment != NULL)
563 * Check the URL against the stack for recursions
566 for (i = 0;i < ctxt->urlNr;i++) {
567 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
568 xmlXIncludeErrorContext(ctxt, cur);
569 xmlGenericError(xmlGenericErrorContext,
570 "XInclude: detected a recursion in %s\n",
578 ref = xmlXIncludeNewRef(ctxt, URL, cur);
582 ref->fragment = fragment;
591 * xmlXIncludeRecurseDoc:
592 * @ctxt: the XInclude context
593 * @doc: the new document
594 * @url: the associated URL
596 * The XInclude recursive nature is handled at this point.
599 xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
600 const xmlURL url ATTRIBUTE_UNUSED) {
601 xmlXIncludeCtxtPtr newctxt;
605 * Avoid recursion in already substitued resources
606 for (i = 0;i < ctxt->urlNr;i++) {
607 if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
612 #ifdef DEBUG_XINCLUDE
613 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
616 * Handle recursion here.
619 newctxt = xmlXIncludeNewContext(doc);
620 if (newctxt != NULL) {
622 * Copy the existing document set
624 newctxt->incMax = ctxt->incMax;
625 newctxt->incNr = ctxt->incNr;
626 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
627 sizeof(newctxt->incTab[0]));
628 if (newctxt->incTab == NULL) {
629 xmlXIncludeErrorContext(ctxt, NULL);
630 xmlGenericError(xmlGenericErrorContext,
631 "malloc failed !\n");
639 newctxt->urlMax = ctxt->urlMax;
640 newctxt->urlNr = ctxt->urlNr;
641 newctxt->urlTab = ctxt->urlTab;
644 * Inherit the documents already in use by others includes
646 newctxt->incBase = ctxt->incNr;
647 for (i = 0;i < ctxt->incNr;i++) {
648 newctxt->incTab[i] = ctxt->incTab[i];
649 newctxt->incTab[i]->count++; /* prevent the recursion from
652 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
653 for (i = 0;i < ctxt->incNr;i++) {
654 newctxt->incTab[i]->count--;
655 newctxt->incTab[i] = NULL;
658 /* urlTab may have been reallocated */
659 ctxt->urlTab = newctxt->urlTab;
660 ctxt->urlMax = newctxt->urlMax;
664 newctxt->urlTab = NULL;
666 xmlXIncludeFreeContext(newctxt);
668 #ifdef DEBUG_XINCLUDE
669 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
675 * @ctxt: the XInclude context
676 * @txt: the new text node
677 * @url: the associated URL
679 * Add a new txtument to the list
682 xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
683 #ifdef DEBUG_XINCLUDE
684 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
686 if (ctxt->txtMax == 0) {
688 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
689 sizeof(ctxt->txtTab[0]));
690 if (ctxt->txtTab == NULL) {
691 xmlXIncludeErrorContext(ctxt, NULL);
692 xmlGenericError(xmlGenericErrorContext,
693 "malloc failed !\n");
697 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
698 sizeof(ctxt->txturlTab[0]));
699 if (ctxt->txturlTab == NULL) {
700 xmlXIncludeErrorContext(ctxt, NULL);
701 xmlGenericError(xmlGenericErrorContext,
702 "malloc failed !\n");
707 if (ctxt->txtNr >= ctxt->txtMax) {
709 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
710 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
711 if (ctxt->txtTab == NULL) {
712 xmlXIncludeErrorContext(ctxt, NULL);
713 xmlGenericError(xmlGenericErrorContext,
714 "realloc failed !\n");
718 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
719 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
720 if (ctxt->txturlTab == NULL) {
721 xmlXIncludeErrorContext(ctxt, NULL);
722 xmlGenericError(xmlGenericErrorContext,
723 "realloc failed !\n");
728 ctxt->txtTab[ctxt->txtNr] = txt;
729 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
733 /************************************************************************
735 * Node copy with specific semantic *
737 ************************************************************************/
740 * xmlXIncludeCopyNode:
741 * @ctxt: the XInclude context
742 * @target: the document target
743 * @source: the document source
746 * Make a copy of the node while preserving the XInclude semantic
747 * of the Infoset copy
750 xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
751 xmlDocPtr source, xmlNodePtr elem) {
752 xmlNodePtr result = NULL;
754 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
757 if (elem->type == XML_DTD_NODE)
759 result = xmlDocCopyNode(elem, target, 1);
764 * xmlXIncludeCopyNodeList:
765 * @ctxt: the XInclude context
766 * @target: the document target
767 * @source: the document source
768 * @elem: the element list
770 * Make a copy of the node list while preserving the XInclude semantic
771 * of the Infoset copy
774 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
775 xmlDocPtr source, xmlNodePtr elem) {
776 xmlNodePtr cur, res, result = NULL, last = NULL;
778 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
782 while (cur != NULL) {
783 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
785 if (result == NULL) {
799 * xmlXInclueGetNthChild:
801 * @no: the child number
803 * Returns the @no'th element child of @cur or NULL
806 xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
811 for (i = 0;i <= no;cur = cur->next) {
814 if ((cur->type == XML_ELEMENT_NODE) ||
815 (cur->type == XML_DOCUMENT_NODE) ||
816 (cur->type == XML_HTML_DOCUMENT_NODE)) {
825 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
828 * xmlXIncludeCopyRange:
829 * @ctxt: the XInclude context
830 * @target: the document target
831 * @source: the document source
832 * @obj: the XPointer result from the evaluation.
834 * Build a node list tree copy of the XPointer result.
836 * Returns an xmlNodePtr list or NULL.
837 * the caller has to free the node tree.
840 xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
841 xmlDocPtr source, xmlXPathObjectPtr range) {
842 /* pointers to generated nodes */
843 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
844 /* pointers to traversal nodes */
845 xmlNodePtr start, cur, end;
848 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
851 if (range->type != XPATH_RANGE)
853 start = (xmlNodePtr) range->user;
859 return(xmlDocCopyNode(start, target, 1));
862 index1 = range->index;
863 index2 = range->index2;
864 while (cur != NULL) {
866 if (cur->type == XML_TEXT_NODE) {
867 const xmlChar *content = cur->content;
870 if (content == NULL) {
871 tmp = xmlNewTextLen(NULL, 0);
874 if ((cur == start) && (index1 > 1)) {
875 content += (index1 - 1);
881 tmp = xmlNewTextLen(content, len);
883 /* single sub text node selection */
886 /* prune and return full set */
888 xmlAddNextSibling(last, tmp);
890 xmlAddChild(parent, tmp);
893 tmp = xmlDocCopyNode(cur, target, 0);
898 xmlAddNextSibling(last, tmp);
900 xmlAddChild(parent, tmp);
906 end = xmlXIncludeGetNthChild(cur, index2 - 1);
909 if ((cur == start) && (index1 > 1)) {
910 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
916 * Now gather the remaining nodes from cur to end
918 continue; /* while */
920 } else if ((cur == start) &&
921 (list == NULL) /* looks superfluous but ... */ ) {
922 if ((cur->type == XML_TEXT_NODE) ||
923 (cur->type == XML_CDATA_SECTION_NODE)) {
924 const xmlChar *content = cur->content;
926 if (content == NULL) {
927 tmp = xmlNewTextLen(NULL, 0);
930 content += (index1 - 1);
932 tmp = xmlNewText(content);
936 if ((cur == start) && (index1 > 1)) {
937 tmp = xmlDocCopyNode(cur, target, 0);
941 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
944 * Now gather the remaining nodes from cur to end
946 continue; /* while */
948 tmp = xmlDocCopyNode(cur, target, 1);
957 case XML_ELEMENT_DECL:
958 case XML_ATTRIBUTE_DECL:
959 case XML_ENTITY_NODE:
960 /* Do not copy DTD informations */
962 case XML_ENTITY_DECL:
963 /* handle crossing entities -> stack needed */
965 case XML_XINCLUDE_START:
966 case XML_XINCLUDE_END:
967 /* don't consider it part of the tree content */
969 case XML_ATTRIBUTE_NODE:
970 /* Humm, should not happen ! */
973 tmp = xmlDocCopyNode(cur, target, 1);
977 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
981 xmlAddNextSibling(last, tmp);
983 xmlAddChild(parent, tmp);
989 * Skip to next node in document order
991 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
994 cur = xmlXPtrAdvanceNode(cur);
1000 * xmlXIncludeBuildNodeList:
1001 * @ctxt: the XInclude context
1002 * @target: the document target
1003 * @source: the document source
1004 * @obj: the XPointer result from the evaluation.
1006 * Build a node list tree copy of the XPointer result.
1007 * This will drop Attributes and Namespace declarations.
1009 * Returns an xmlNodePtr list or NULL.
1010 * the caller has to free the node tree.
1013 xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
1014 xmlDocPtr source, xmlXPathObjectPtr obj) {
1015 xmlNodePtr list = NULL, last = NULL;
1020 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
1023 switch (obj->type) {
1024 case XPATH_NODESET: {
1025 xmlNodeSetPtr set = obj->nodesetval;
1028 for (i = 0;i < set->nodeNr;i++) {
1029 if (set->nodeTab[i] == NULL)
1031 switch (set->nodeTab[i]->type) {
1033 case XML_CDATA_SECTION_NODE:
1034 case XML_ELEMENT_NODE:
1035 case XML_ENTITY_REF_NODE:
1036 case XML_ENTITY_NODE:
1038 case XML_COMMENT_NODE:
1039 case XML_DOCUMENT_NODE:
1040 case XML_HTML_DOCUMENT_NODE:
1041 #ifdef LIBXML_DOCB_ENABLED
1042 case XML_DOCB_DOCUMENT_NODE:
1044 case XML_XINCLUDE_END:
1046 case XML_XINCLUDE_START: {
1047 xmlNodePtr tmp, cur = set->nodeTab[i];
1050 while (cur != NULL) {
1053 case XML_CDATA_SECTION_NODE:
1054 case XML_ELEMENT_NODE:
1055 case XML_ENTITY_REF_NODE:
1056 case XML_ENTITY_NODE:
1058 case XML_COMMENT_NODE:
1059 tmp = xmlXIncludeCopyNode(ctxt, target,
1064 xmlAddNextSibling(last, tmp);
1076 case XML_ATTRIBUTE_NODE:
1077 case XML_NAMESPACE_DECL:
1078 case XML_DOCUMENT_TYPE_NODE:
1079 case XML_DOCUMENT_FRAG_NODE:
1080 case XML_NOTATION_NODE:
1082 case XML_ELEMENT_DECL:
1083 case XML_ATTRIBUTE_DECL:
1084 case XML_ENTITY_DECL:
1088 list = last = xmlXIncludeCopyNode(ctxt, target, source,
1091 xmlAddNextSibling(last,
1092 xmlXIncludeCopyNode(ctxt, target, source,
1094 if (last->next != NULL)
1100 case XPATH_LOCATIONSET: {
1101 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1104 for (i = 0;i < set->locNr;i++) {
1106 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
1109 xmlAddNextSibling(last,
1110 xmlXIncludeCopyXPointer(ctxt, target, source,
1113 while (last->next != NULL)
1120 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
1122 /* points are ignored in XInclude */
1129 /************************************************************************
1131 * XInclude I/O handling *
1133 ************************************************************************/
1135 typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1136 typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1137 struct _xmlXIncludeMergeData {
1139 xmlXIncludeCtxtPtr ctxt;
1143 * xmlXIncludeMergeOneEntity:
1145 * @doc: the including doc
1146 * @nr: the entity name
1148 * Inplements the merge of one entity
1151 xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
1152 xmlChar *name ATTRIBUTE_UNUSED) {
1153 xmlEntityPtr ret, prev;
1155 xmlXIncludeCtxtPtr ctxt;
1157 if ((ent == NULL) || (data == NULL))
1161 if ((ctxt == NULL) || (doc == NULL))
1163 switch (ent->etype) {
1164 case XML_INTERNAL_PARAMETER_ENTITY:
1165 case XML_EXTERNAL_PARAMETER_ENTITY:
1166 case XML_INTERNAL_PREDEFINED_ENTITY:
1168 case XML_INTERNAL_GENERAL_ENTITY:
1169 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1170 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1173 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1174 ent->SystemID, ent->content);
1176 if (ent->URI != NULL)
1177 ret->URI = xmlStrdup(ent->URI);
1179 prev = xmlGetDocEntity(doc, ent->name);
1181 if (ent->etype != prev->etype)
1184 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1185 if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1187 } else if ((ent->ExternalID != NULL) &&
1188 (prev->ExternalID != NULL)) {
1189 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1191 } else if ((ent->content != NULL) && (prev->content != NULL)) {
1192 if (!xmlStrEqual(ent->content, prev->content))
1202 switch (ent->etype) {
1203 case XML_INTERNAL_PARAMETER_ENTITY:
1204 case XML_EXTERNAL_PARAMETER_ENTITY:
1205 case XML_INTERNAL_PREDEFINED_ENTITY:
1206 case XML_INTERNAL_GENERAL_ENTITY:
1207 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1209 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1212 xmlXIncludeErrorContext(ctxt, (xmlNodePtr) ent);
1213 xmlGenericError(xmlGenericErrorContext,
1214 "XInclude: mismatch in redefinition of entity %s\n", ent->name);
1219 * xmlXIncludeMergeEntities:
1220 * @ctxt: an XInclude context
1221 * @doc: the including doc
1222 * @from: the included doc
1224 * Inplements the entity merge
1226 * Returns 0 if merge succeeded, -1 if some processing failed
1229 xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1232 xmlDtdPtr target, source;
1237 if ((from == NULL) || (from->intSubset == NULL))
1240 target = doc->intSubset;
1241 if (target == NULL) {
1242 cur = xmlDocGetRootElement(doc);
1245 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1250 source = from->intSubset;
1251 if ((source != NULL) && (source->entities != NULL)) {
1252 xmlXIncludeMergeData data;
1257 xmlHashScan((xmlHashTablePtr) source->entities,
1258 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
1260 source = from->extSubset;
1261 if ((source != NULL) && (source->entities != NULL)) {
1262 xmlXIncludeMergeData data;
1268 * don't duplicate existing stuff when external subsets are the same
1270 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1271 (!xmlStrEqual(target->SystemID, source->SystemID))) {
1272 xmlHashScan((xmlHashTablePtr) source->entities,
1273 (xmlHashScanner) xmlXIncludeMergeEntity, &data);
1280 * xmlXIncludeLoadDoc:
1281 * @ctxt: the XInclude context
1282 * @url: the associated URL
1283 * @nr: the xinclude node number
1285 * Load the document, and store the result in the XInclude context
1287 * Returns 0 in case of success, -1 in case of failure
1290 xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1294 xmlChar *fragment = NULL;
1297 #ifdef DEBUG_XINCLUDE
1298 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1301 * Check the URL and remove any fragment identifier
1303 uri = xmlParseURI((const char *)url);
1305 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1306 xmlGenericError(xmlGenericErrorContext,
1307 "XInclude: invalid value URI %s\n", url);
1311 if (uri->fragment != NULL) {
1312 fragment = (xmlChar *) uri->fragment;
1313 uri->fragment = NULL;
1315 URL = xmlSaveUri(uri);
1318 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1319 xmlGenericError(xmlGenericErrorContext,
1320 "XInclude: invalid value URI %s\n", url);
1322 if (fragment != NULL)
1328 * Handling of references to the local document are done
1329 * directly through ctxt->doc.
1331 if ((URL[0] == 0) || (URL[0] == '#') ||
1332 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
1338 * Prevent reloading twice the document.
1340 for (i = 0; i < ctxt->incNr; i++) {
1341 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1342 (ctxt->incTab[i]->doc != NULL)) {
1343 doc = ctxt->incTab[i]->doc;
1344 #ifdef DEBUG_XINCLUDE
1345 printf("Already loaded %s\n", URL);
1354 #ifdef DEBUG_XINCLUDE
1355 printf("loading %s\n", URL);
1357 doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
1360 if (fragment != NULL)
1364 ctxt->incTab[nr]->doc = doc;
1365 for (i = nr + 1; i < ctxt->incNr; i++) {
1366 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1367 ctxt->incTab[nr]->count++;
1368 #ifdef DEBUG_XINCLUDE
1369 printf("Increasing %s count since reused\n", URL);
1376 * Make sure we have all entities fixed up
1378 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
1381 * We don't need the DTD anymore, free up space
1382 if (doc->intSubset != NULL) {
1383 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1384 xmlFreeNode((xmlNodePtr) doc->intSubset);
1385 doc->intSubset = NULL;
1387 if (doc->extSubset != NULL) {
1388 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1389 xmlFreeNode((xmlNodePtr) doc->extSubset);
1390 doc->extSubset = NULL;
1393 xmlXIncludeRecurseDoc(ctxt, doc, URL);
1396 if (fragment == NULL) {
1398 * Add the top children list as the replacement copy.
1402 /* Hopefully a DTD declaration won't be copied from
1403 * the same document */
1404 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
1406 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
1407 doc, doc->children);
1411 * Computes the XPointer expression and make a copy used
1412 * as the replacement copy.
1414 xmlXPathObjectPtr xptr;
1415 xmlXPathContextPtr xptrctxt;
1419 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1422 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1424 if (xptrctxt == NULL) {
1425 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1426 xmlGenericError(xmlGenericErrorContext,
1427 "XInclude: could create XPointer context\n");
1433 xptr = xmlXPtrEval(fragment, xptrctxt);
1435 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1436 xmlGenericError(xmlGenericErrorContext,
1437 "XInclude: XPointer evaluation failed: #%s\n",
1440 xmlXPathFreeContext(xptrctxt);
1445 switch (xptr->type) {
1446 case XPATH_UNDEFINED:
1452 case XPATH_XSLT_TREE:
1453 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1454 xmlGenericError(xmlGenericErrorContext,
1455 "XInclude: XPointer is not a range: #%s\n",
1458 xmlXPathFreeContext(xptrctxt);
1464 case XPATH_LOCATIONSET:
1467 set = xptr->nodesetval;
1469 for (i = 0;i < set->nodeNr;i++) {
1470 if (set->nodeTab[i] == NULL)
1472 switch (set->nodeTab[i]->type) {
1474 case XML_CDATA_SECTION_NODE:
1475 case XML_ELEMENT_NODE:
1476 case XML_ENTITY_REF_NODE:
1477 case XML_ENTITY_NODE:
1479 case XML_COMMENT_NODE:
1480 case XML_DOCUMENT_NODE:
1481 case XML_HTML_DOCUMENT_NODE:
1482 #ifdef LIBXML_DOCB_ENABLED
1483 case XML_DOCB_DOCUMENT_NODE:
1486 case XML_ATTRIBUTE_NODE:
1487 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1488 xmlGenericError(xmlGenericErrorContext,
1489 "XInclude: XPointer selects an attribute: #%s\n",
1492 set->nodeTab[i] = NULL;
1494 case XML_NAMESPACE_DECL:
1495 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1496 xmlGenericError(xmlGenericErrorContext,
1497 "XInclude: XPointer selects a namespace: #%s\n",
1500 set->nodeTab[i] = NULL;
1502 case XML_DOCUMENT_TYPE_NODE:
1503 case XML_DOCUMENT_FRAG_NODE:
1504 case XML_NOTATION_NODE:
1506 case XML_ELEMENT_DECL:
1507 case XML_ATTRIBUTE_DECL:
1508 case XML_ENTITY_DECL:
1509 case XML_XINCLUDE_START:
1510 case XML_XINCLUDE_END:
1511 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1512 xmlGenericError(xmlGenericErrorContext,
1513 "XInclude: XPointer selects unexpected nodes: #%s\n",
1516 set->nodeTab[i] = NULL;
1517 set->nodeTab[i] = NULL;
1523 ctxt->incTab[nr]->xptr = xptr;
1524 ctxt->incTab[nr]->inc = NULL;
1526 ctxt->incTab[nr]->inc =
1527 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1528 xmlXPathFreeObject(xptr);
1530 xmlXPathFreeContext(xptrctxt);
1535 * Do the xml:base fixup if needed
1537 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1540 node = ctxt->incTab[nr]->inc;
1541 while (node != NULL) {
1542 if (node->type == XML_ELEMENT_NODE)
1543 xmlNodeSetBase(node, URL);
1547 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1548 (ctxt->incTab[nr]->count <= 1)) {
1549 #ifdef DEBUG_XINCLUDE
1550 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1552 xmlFreeDoc(ctxt->incTab[nr]->doc);
1553 ctxt->incTab[nr]->doc = NULL;
1560 * xmlXIncludeLoadTxt:
1561 * @ctxt: the XInclude context
1562 * @url: the associated URL
1563 * @nr: the xinclude node number
1565 * Load the content, and store the result in the XInclude context
1567 * Returns 0 in case of success, -1 in case of failure
1570 xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1571 xmlParserInputBufferPtr buf;
1576 xmlChar *encoding = NULL;
1577 xmlCharEncoding enc = (xmlCharEncoding) 0;
1580 * Check the URL and remove any fragment identifier
1582 uri = xmlParseURI((const char *)url);
1584 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1585 xmlGenericError(xmlGenericErrorContext,
1586 "XInclude: invalid value URI %s\n", url);
1590 if (uri->fragment != NULL) {
1591 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1592 xmlGenericError(xmlGenericErrorContext,
1593 "XInclude: fragment identifier forbidden for text: %s\n",
1599 URL = xmlSaveUri(uri);
1602 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1603 xmlGenericError(xmlGenericErrorContext,
1604 "XInclude: invalid value URI %s\n", url);
1610 * Handling of references to the local document are done
1611 * directly through ctxt->doc.
1614 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1615 xmlGenericError(xmlGenericErrorContext,
1616 "XInclude: text serialization of document not available\n");
1623 * Prevent reloading twice the document.
1625 for (i = 0; i < ctxt->txtNr; i++) {
1626 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1627 node = xmlCopyNode(ctxt->txtTab[i], 1);
1632 * Try to get the encoding if available
1634 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1635 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1637 if (encoding != NULL) {
1639 * TODO: we should not have to remap to the xmlCharEncoding
1640 * predefined set, a better interface than
1641 * xmlParserInputBufferCreateFilename should allow any
1642 * encoding supported by iconv
1644 enc = xmlParseCharEncoding((const char *) encoding);
1645 if (enc == XML_CHAR_ENCODING_ERROR) {
1646 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1647 xmlGenericError(xmlGenericErrorContext,
1648 "XInclude: encoding %s not supported\n", encoding);
1660 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
1665 node = xmlNewText(NULL);
1668 * Scan all chars from the resource and add the to the node
1670 while (xmlParserInputBufferRead(buf, 128) > 0) {
1672 const xmlChar *content;
1674 content = xmlBufferContent(buf->buffer);
1675 len = xmlBufferLength(buf->buffer);
1676 for (i = 0;i < len;) {
1680 cur = xmlStringCurrentChar(NULL, &content[i], &l);
1681 if (!IS_CHAR(cur)) {
1682 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1683 xmlGenericError(xmlGenericErrorContext,
1684 "XInclude: %s contains invalid char %d\n", URL, cur);
1687 xmlNodeAddContentLen(node, &content[i], l);
1691 xmlBufferShrink(buf->buffer, len);
1693 xmlFreeParserInputBuffer(buf);
1694 xmlXIncludeAddTxt(ctxt, node, URL);
1698 * Add the element as the replacement copy.
1700 ctxt->incTab[nr]->inc = node;
1706 * xmlXIncludeLoadFallback:
1707 * @ctxt: the XInclude context
1708 * @fallback: the fallback node
1709 * @nr: the xinclude node number
1711 * Load the content of the fallback node, and store the result
1712 * in the XInclude context
1714 * Returns 0 in case of success, -1 in case of failure
1717 xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1718 if ((fallback == NULL) || (ctxt == NULL))
1721 ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
1725 /************************************************************************
1727 * XInclude Processing *
1729 ************************************************************************/
1732 * xmlXIncludePreProcessNode:
1733 * @ctxt: an XInclude context
1734 * @node: an XInclude node
1736 * Implement the XInclude preprocessing, currently just adding the element
1737 * for further processing.
1739 * Returns the result list or NULL in case of error
1742 xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1743 xmlXIncludeAddNode(ctxt, node);
1748 * xmlXIncludeLoadNode:
1749 * @ctxt: an XInclude context
1750 * @nr: the node number
1752 * Find and load the infoset replacement for the given node.
1754 * Returns 0 if substitution succeeded, -1 if some processing failed
1757 xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1763 int xml = 1; /* default Issue 64 */
1768 if ((nr < 0) || (nr >= ctxt->incNr))
1770 cur = ctxt->incTab[nr]->ref;
1775 * read the attributes
1777 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1779 href = xmlGetProp(cur, XINCLUDE_HREF);
1781 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1782 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1787 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1788 if (parse == NULL) {
1789 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1791 if (parse != NULL) {
1792 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1794 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1797 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1798 xmlGenericError(xmlGenericErrorContext,
1799 "XInclude: invalid value %s for %s\n",
1800 parse, XINCLUDE_PARSE);
1813 base = xmlNodeGetBase(ctxt->doc, cur);
1815 URI = xmlBuildURI(href, ctxt->doc->URL);
1817 URI = xmlBuildURI(href, base);
1823 * Some escaping may be needed
1825 escbase = xmlURIEscape(base);
1826 eschref = xmlURIEscape(href);
1827 URI = xmlBuildURI(eschref, escbase);
1828 if (escbase != NULL)
1830 if (eschref != NULL)
1834 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1835 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1845 #ifdef DEBUG_XINCLUDE
1846 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1847 xml ? "xml": "text");
1848 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1855 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
1856 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1858 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1861 xmlNodePtr children;
1864 * Time to try a fallback if availble
1866 #ifdef DEBUG_XINCLUDE
1867 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1869 children = cur->children;
1870 while (children != NULL) {
1871 if ((children->type == XML_ELEMENT_NODE) &&
1872 (children->ns != NULL) &&
1873 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1874 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1875 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1879 children = children->next;
1883 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1884 xmlGenericError(xmlGenericErrorContext,
1885 "XInclude: could not load %s, and no fallback was found\n",
1905 * xmlXIncludeIncludeNode:
1906 * @ctxt: an XInclude context
1907 * @nr: the node number
1909 * Inplement the infoset replacement for the given node
1911 * Returns 0 if substitution succeeded, -1 if some processing failed
1914 xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1915 xmlNodePtr cur, end, list, tmp;
1919 if ((nr < 0) || (nr >= ctxt->incNr))
1921 cur = ctxt->incTab[nr]->ref;
1926 * If we stored an XPointer a late computation may be needed
1928 if ((ctxt->incTab[nr]->inc == NULL) &&
1929 (ctxt->incTab[nr]->xptr != NULL)) {
1930 ctxt->incTab[nr]->inc =
1931 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1932 ctxt->incTab[nr]->xptr);
1933 xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1934 ctxt->incTab[nr]->xptr = NULL;
1936 list = ctxt->incTab[nr]->inc;
1937 ctxt->incTab[nr]->inc = NULL;
1940 * Check against the risk of generating a multi-rooted document
1942 if ((cur->parent != NULL) &&
1943 (cur->parent->type != XML_ELEMENT_NODE)) {
1947 while (tmp != NULL) {
1948 if (tmp->type == XML_ELEMENT_NODE)
1953 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1954 xmlGenericError(xmlGenericErrorContext,
1955 "XInclude error: would result in multiple root nodes\n");
1962 * Change the current node as an XInclude start one, and add an
1965 cur->type = XML_XINCLUDE_START;
1966 end = xmlNewNode(cur->ns, cur->name);
1968 xmlXIncludeErrorContext(ctxt, ctxt->incTab[nr]->ref);
1969 xmlGenericError(xmlGenericErrorContext,
1970 "XInclude: failed to build node\n");
1974 end->type = XML_XINCLUDE_END;
1975 xmlAddNextSibling(cur, end);
1978 * Add the list of nodes
1980 while (list != NULL) {
1984 xmlAddPrevSibling(end, cur);
1992 * xmlXIncludeTestNode:
1993 * @ctxt: the XInclude processing context
1994 * @node: an XInclude node
1996 * test if the node is an XInclude node
1998 * Returns 1 true, 0 otherwise
2001 xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2004 if (node->type != XML_ELEMENT_NODE)
2006 if (node->ns == NULL)
2008 if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
2009 if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2010 xmlNodePtr child = node->children;
2011 int nb_fallback = 0;
2013 while (child != NULL) {
2014 if ((child->type == XML_ELEMENT_NODE) &&
2015 (child->ns != NULL) &&
2016 (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
2017 if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
2018 xmlXIncludeErrorContext(ctxt, node);
2019 xmlGenericError(xmlGenericErrorContext,
2020 "XInclude: %s has an %s child\n",
2021 XINCLUDE_NODE, XINCLUDE_NODE);
2025 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2029 child = child->next;
2031 if (nb_fallback > 1) {
2032 xmlXIncludeErrorContext(ctxt, node);
2033 xmlGenericError(xmlGenericErrorContext,
2034 "XInclude: %s has %d %s children\n",
2035 XINCLUDE_NODE, nb_fallback, XINCLUDE_FALLBACK);
2041 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2042 if ((node->parent == NULL) ||
2043 (node->parent->type != XML_ELEMENT_NODE) ||
2044 (node->parent->ns == NULL) ||
2045 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
2046 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
2047 xmlXIncludeErrorContext(ctxt, node);
2048 xmlGenericError(xmlGenericErrorContext,
2049 "XInclude: %s is not the child of an %s\n",
2050 XINCLUDE_FALLBACK, XINCLUDE_NODE);
2059 * xmlXIncludeDoProcess:
2060 * @ctxt: the XInclude processing context
2061 * @doc: an XML document
2062 * @tree: the top of the tree to process
2064 * Implement the XInclude substitution on the XML document @doc
2066 * Returns 0 if no substitution were done, -1 if some processing failed
2067 * or the number of substitutions done.
2070 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
2075 if ((doc == NULL) || (tree == NULL))
2080 if (doc->URL != NULL) {
2081 ret = xmlXIncludeURLPush(ctxt, doc->URL);
2087 * First phase: lookup the elements in the document
2090 if (xmlXIncludeTestNode(ctxt, cur) == 1)
2091 xmlXIncludePreProcessNode(ctxt, cur);
2092 while (cur != NULL) {
2093 /* TODO: need to work on entities -> stack */
2094 if ((cur->children != NULL) &&
2095 (cur->children->type != XML_ENTITY_DECL) &&
2096 (cur->children->type != XML_XINCLUDE_START) &&
2097 (cur->children->type != XML_XINCLUDE_END)) {
2098 cur = cur->children;
2099 if (xmlXIncludeTestNode(ctxt, cur))
2100 xmlXIncludePreProcessNode(ctxt, cur);
2101 } else if (cur->next != NULL) {
2103 if (xmlXIncludeTestNode(ctxt, cur))
2104 xmlXIncludePreProcessNode(ctxt, cur);
2108 if (cur == NULL) break; /* do */
2109 if (cur->next != NULL) {
2111 if (xmlXIncludeTestNode(ctxt, cur))
2112 xmlXIncludePreProcessNode(ctxt, cur);
2115 } while (cur != NULL);
2120 * Second Phase : collect the infosets fragments
2122 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2123 xmlXIncludeLoadNode(ctxt, i);
2128 * Third phase: extend the original document infoset.
2130 if (ctxt->nbErrors == 0) {
2131 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2132 xmlXIncludeIncludeNode(ctxt, i);
2136 if (doc->URL != NULL)
2137 xmlXIncludeURLPop(ctxt);
2142 * xmlXIncludeProcess:
2143 * @doc: an XML document
2145 * Implement the XInclude substitution on the XML document @doc
2147 * Returns 0 if no substitution were done, -1 if some processing failed
2148 * or the number of substitutions done.
2151 xmlXIncludeProcess(xmlDocPtr doc) {
2152 xmlXIncludeCtxtPtr ctxt;
2158 tree = xmlDocGetRootElement(doc);
2161 ctxt = xmlXIncludeNewContext(doc);
2164 ret = xmlXIncludeDoProcess(ctxt, doc, tree);
2165 if ((ret >= 0) && (ctxt->nbErrors > 0))
2168 xmlXIncludeFreeContext(ctxt);
2173 * xmlXIncludeProcessTree:
2174 * @tree: a node in an XML document
2176 * Implement the XInclude substitution for the given subtree
2178 * Returns 0 if no substitution were done, -1 if some processing failed
2179 * or the number of substitutions done.
2182 xmlXIncludeProcessTree(xmlNodePtr tree) {
2183 xmlXIncludeCtxtPtr ctxt;
2186 if ((tree == NULL) || (tree->doc == NULL))
2188 ctxt = xmlXIncludeNewContext(tree->doc);
2191 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
2192 if ((ret >= 0) && (ctxt->nbErrors > 0))
2195 xmlXIncludeFreeContext(ctxt);
2199 #else /* !LIBXML_XINCLUDE_ENABLED */