/* * xinclude.c : Code to implement XInclude processing * * World Wide Web Consortium Working Draft 26 October 2000 * http://www.w3.org/TR/2000/WD-xinclude-20001026 * * See Copyright for the status of this software. * * Daniel.Veillard@w3.org */ /* * TODO: xmlXIncludeCtxt with document caches, stack of nodes to handle * and their associated infoset. */ #ifdef WIN32 #include "win32config.h" #else #include "config.h" #endif #include #include #include #include #include #include #include #ifdef LIBXML_DEBUG_ENABLED #include #endif #include #ifdef LIBXML_XINCLUDE_ENABLED #include #define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/1999/XML/xinclude" #define XINCLUDE_NODE (const xmlChar *) "include" #define XINCLUDE_HREF (const xmlChar *) "href" #define XINCLUDE_PARSE (const xmlChar *) "parse" #define DEBUG_XINCLUDE /* * An XInclude context */ typedef xmlChar *URL; typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt; typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr; struct _xmlXIncludeCtxt { xmlDocPtr doc; /* the source document */ int incNr; /* number of includes */ int incMax; /* size of includes tab */ xmlNodePtr *incTab; /* array of include nodes */ xmlNodePtr *repTab; /* array of replacement node lists */ int docNr; /* number of documents */ int docMax; /* size of documents tab */ xmlDocPtr *docTab; /* array of documents */ URL *urlTab; /* array of documents URLs */ }; /** * xmlXIncludeAddNode: * @ctxt: the XInclude context * @node: the new node * * Add a new node to process to an XInclude context */ void xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { if (ctxt->incMax == 0) { ctxt->incMax = 4; ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax * sizeof(ctxt->incTab[0])); if (ctxt->incTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return; } ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax * sizeof(ctxt->repTab[0])); if (ctxt->repTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return; } } if (ctxt->incNr >= ctxt->incMax) { ctxt->incMax *= 2; ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab, ctxt->incMax * sizeof(ctxt->incTab[0])); if (ctxt->incTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return; } ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab, ctxt->incMax * sizeof(ctxt->repTab[0])); if (ctxt->repTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return; } } ctxt->incTab[ctxt->incNr] = node; ctxt->incNr++; } /** * xmlXIncludeAddDoc: * @ctxt: the XInclude context * @doc: the new document * @url: the associated URL * * Add a new document to the list */ void xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const URL url) { if (ctxt->docMax == 0) { ctxt->docMax = 4; ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax * sizeof(ctxt->docTab[0])); if (ctxt->docTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return; } ctxt->urlTab = (URL *) xmlMalloc(ctxt->docMax * sizeof(ctxt->urlTab[0])); if (ctxt->urlTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return; } } if (ctxt->docNr >= ctxt->docMax) { ctxt->docMax *= 2; ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab, ctxt->docMax * sizeof(ctxt->docTab[0])); if (ctxt->docTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return; } ctxt->urlTab = (URL *) xmlRealloc(ctxt->urlTab, ctxt->docMax * sizeof(ctxt->urlTab[0])); if (ctxt->urlTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return; } } ctxt->docTab[ctxt->docNr] = doc; ctxt->urlTab[ctxt->docNr] = xmlStrdup(url); ctxt->docNr++; } /** * xmlXIncludeNewContext: * @doc: an XML Document * * Creates a new XInclude context * * Returns the new set */ xmlXIncludeCtxtPtr xmlXIncludeNewContext(xmlDocPtr doc) { xmlXIncludeCtxtPtr ret; if (doc == NULL) return(NULL); ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt)); if (ret == NULL) return(NULL); memset(ret, 0, sizeof(xmlXIncludeCtxt)); ret->doc = doc; ret->incNr = 0; ret->incMax = 0; ret->incTab = NULL; ret->repTab = NULL; ret->docNr = 0; ret->docMax = 0; ret->docTab = NULL; ret->urlTab = NULL; return(ret); } /** * xmlXIncludeFreeContext: * @ctxt: the XInclude context * * Free an XInclude context */ void xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { if (ctxt == NULL) return; if (ctxt->incTab != NULL) xmlFree(ctxt->incTab); if (ctxt->repTab != NULL) xmlFree(ctxt->repTab); memset(ctxt, 0xeb, sizeof(xmlXIncludeCtxt)); xmlFree(ctxt); } /** * xmlXIncludePreProcessNode: * @ctxt: an XInclude context * @node: an XInclude node * * Implement the infoset replacement lookup on the XML element @node * * Returns the result list or NULL in case of error */ xmlNodePtr xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { xmlXIncludeAddNode(ctxt, node); return(0); } /** * xmlXIncludeLoadNode: * @ctxt: an XInclude context * @nr: the node number * * Find and load the infoset replacement for the given node. * * Returns 0 if substition succeeded, -1 if some processing failed */ int xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, int nr) { xmlNodePtr cur; xmlURIPtr uri; xmlChar *href; xmlChar *parse; xmlChar *base; xmlChar *URI; int xml = 1; /* default Issue 64 */ if (ctxt == NULL) return(-1); if ((nr < 0) || (nr >= ctxt->incNr)) return(-1); cur = ctxt->incTab[nr]; if (cur == NULL) return(-1); #ifdef DEBUG_XINCLUDE xmlDebugDumpNode(stdout, cur, 0); #endif /* * Get and compute the URI */ href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF); if (href == NULL) { xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n"); return(-1); } base = xmlNodeGetBase(ctxt->doc, cur); parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE); if (parse != NULL) { } return(0); } /** * xmlXIncludeTestNode: * @doc: an XML document * @node: an XInclude node * * test if the node is an XInclude node * * Returns 1 true, 0 otherwise */ int xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) { if (node == NULL) return(0); if (node->ns == NULL) return(0); if ((xmlStrEqual(node->name, XINCLUDE_NODE)) && (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1); return(0); } /** * xmlXIncludeProcess: * @doc: an XML document * * Implement the XInclude substitution on the XML document @doc * * Returns 0 if no substition were done, -1 if some processing failed * or the number of substitutions done. */ int xmlXIncludeProcess(xmlDocPtr doc) { xmlXIncludeCtxtPtr ctxt; xmlNodePtr cur; int ret = 0; int i; if (doc == NULL) return(-1); ctxt = xmlXIncludeNewContext(doc); if (ctxt == NULL) return(-1); /* * First phase: lookup the elements in the document */ cur = xmlDocGetRootElement(doc); if (xmlXIncludeTestNode(doc, cur)) xmlXIncludePreProcessNode(ctxt, cur); while (cur != NULL) { if (cur->children != NULL) { if (cur->children->type != XML_ENTITY_DECL) { cur = cur->children; if (xmlXIncludeTestNode(doc, cur)) xmlXIncludePreProcessNode(ctxt, cur); } } else if (cur->next != NULL) { cur = cur->next; if (xmlXIncludeTestNode(doc, cur)) xmlXIncludePreProcessNode(ctxt, cur); } else { do { cur = cur->parent; if (cur == NULL) break; /* do */ if (cur->next != NULL) { cur = cur->next; if (xmlXIncludeTestNode(doc, cur)) xmlXIncludePreProcessNode(ctxt, cur); break; /* do */ } } while (cur != NULL); } } /* * Second Phase : collect the infosets fragments */ for (i = 0;i < ctxt->incNr; i++) { xmlXIncludeProcessNode(ctxt, i); } /* * Third phase: extend the original document infoset. */ /* * Cleanup */ xmlXIncludeFreeContext(ctxt); return(ret); } #else /* !LIBXML_XINCLUDE_ENABLED */ #endif