diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | HTMLtree.c | 6 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | configure.in | 13 | ||||
-rw-r--r-- | debugXML.c | 11 | ||||
-rw-r--r-- | hash.c | 1 | ||||
-rw-r--r-- | include/libxml/tree.h | 6 | ||||
-rw-r--r-- | include/libxml/uri.h | 1 | ||||
-rw-r--r-- | include/libxml/xinclude.h | 26 | ||||
-rw-r--r-- | include/libxml/xmlversion.h.in | 9 | ||||
-rw-r--r-- | testXPath.c | 1 | ||||
-rw-r--r-- | tree.c | 218 | ||||
-rw-r--r-- | tree.h | 6 | ||||
-rw-r--r-- | uri.c | 353 | ||||
-rw-r--r-- | uri.h | 1 | ||||
-rw-r--r-- | valid.c | 3 | ||||
-rw-r--r-- | xinclude.c | 737 | ||||
-rw-r--r-- | xinclude.h | 26 | ||||
-rw-r--r-- | xmllint.c | 24 | ||||
-rw-r--r-- | xmlversion.h.in | 9 | ||||
-rw-r--r-- | xpath.c | 150 | ||||
-rw-r--r-- | xpointer.c | 46 |
22 files changed, 1453 insertions, 206 deletions
@@ -1,3 +1,14 @@ +Mon Nov 6 17:22:46 CET 2000 Daniel Veillard <Daniel.Veillard@w3.org> + + * tree.[ch] xinclude.[ch] xmllint.c configure.in valid.c + debugXML.c xmlversion.h.in: Started adding XInclude support, + this is a new xmllint option + * tree.c xpath.c: applied TOM patches for XPath + * xpointer.c: fixed a couple of errors. + * uri.c: added an escaping function needed for xinclude + * testXPath.c hash.c HTMLtree.c: minor cleanups raised by + new warning from RH70 gcc's version + Tue Oct 31 14:14:13 CET 2000 Daniel Veillard <Daniel.Veillard@w3.org> * HTMLparser.c: fixed loop on invalid char in scripts @@ -818,7 +818,8 @@ htmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, const #ifndef XML_USE_BUFFER_CONTENT xmlOutputBufferWriteString(buf, (const char *)cur->content); #else - xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content)); + xmlOutputBufferWriteString(buf, (const char *) + xmlBufferContent(cur->content)); #endif xmlOutputBufferWriteString(buf, "-->"); } @@ -835,7 +836,8 @@ htmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, const #ifndef XML_USE_BUFFER_CONTENT xmlOutputBufferWriteString(buf, (const char *)cur->content); #else - xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content)); + xmlOutputBufferWriteString(buf, (const char *) + xmlBufferContent(cur->content)); #endif } return; diff --git a/Makefile.am b/Makefile.am index e8cd50e5..56aa3ff2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ libxml_la_SOURCES = \ debugXML.c \ xpath.c \ xpointer.c \ + xinclude.c \ nanohttp.c \ nanoftp.c diff --git a/configure.in b/configure.in index df3b7e30..dde419b8 100644 --- a/configure.in +++ b/configure.in @@ -286,6 +286,19 @@ fi AC_SUBST(WITH_XPTR) AC_SUBST(XPTR_OBJ) +AC_ARG_WITH(xinclude, [ --with-xinclude Add the XInclude support (on)]) +if test "$with_xinclude" = "no" ; then + echo Disabling XInclude support + WITH_XINCLUDE=0 + XINCLUDE_OBJ= + with_xinclude="no" +else + WITH_XINCLUDE=1 + XINCLUDE_OBJ=xinclude.o +fi +AC_SUBST(WITH_XINCLUDE) +AC_SUBST(XINCLUDE_OBJ) + AC_ARG_WITH(iconv, [ --with-iconv Add the ICONV support (on)]) if test "$with_iconv" = "no" ; then echo Disabling ICONV support @@ -559,6 +559,7 @@ void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) { fprintf(output, "DOCUMENT_FRAG\n"); break; case XML_NOTATION_NODE: + fprintf(output, shift); fprintf(output, "NOTATION\n"); break; case XML_DTD_NODE: @@ -576,6 +577,14 @@ void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) { case XML_NAMESPACE_DECL: xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth); return; + case XML_XINCLUDE_START: + fprintf(output, shift); + fprintf(output, "INCLUDE START\n"); + return; + case XML_XINCLUDE_END: + fprintf(output, shift); + fprintf(output, "INCLUDE END\n"); + return; default: fprintf(output, shift); fprintf(output, "NODE_%d !!!\n", node->type); @@ -917,6 +926,8 @@ static int xmlLsCountNode(xmlNodePtr node) { case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: ret = 1; break; } @@ -17,6 +17,7 @@ * Author: bjorn.reese@systematic.dk */ +#include <string.h> #include <libxml/hash.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> diff --git a/include/libxml/tree.h b/include/libxml/tree.h index 8c4f7088..2168d4fc 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -41,9 +41,11 @@ typedef enum { XML_ELEMENT_DECL= 15, XML_ATTRIBUTE_DECL= 16, XML_ENTITY_DECL= 17, - XML_NAMESPACE_DECL= 18 + XML_NAMESPACE_DECL= 18, + XML_XINCLUDE_START= 19, + XML_XINCLUDE_END= 20 #ifdef LIBXML_SGML_ENABLED - ,XML_SGML_DOCUMENT_NODE= 19 + ,XML_SGML_DOCUMENT_NODE= 21 #endif } xmlElementType; diff --git a/include/libxml/uri.h b/include/libxml/uri.h index 705e3851..e7aeda41 100644 --- a/include/libxml/uri.h +++ b/include/libxml/uri.h @@ -52,6 +52,7 @@ char * xmlURIUnescapeString (const char *str, int len, char *target); int xmlNormalizeURIPath (char *path); +xmlChar * xmlURIEscape (const xmlChar *str); void xmlFreeURI (xmlURIPtr uri); #ifdef __cplusplus diff --git a/include/libxml/xinclude.h b/include/libxml/xinclude.h new file mode 100644 index 00000000..eca4588c --- /dev/null +++ b/include/libxml/xinclude.h @@ -0,0 +1,26 @@ +/* + * xinclude.c : API to handle 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 + */ + +#ifndef __XML_XINCLUDE_H__ +#define __XML_XINCLUDE_H__ + +#include <libxml/tree.h> + +#ifdef __cplusplus +extern "C" { +#endif + +int xmlXIncludeProcess (xmlDocPtr doc); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_XINCLUDE_H__ */ diff --git a/include/libxml/xmlversion.h.in b/include/libxml/xmlversion.h.in index 01b1ea17..4d21762c 100644 --- a/include/libxml/xmlversion.h.in +++ b/include/libxml/xmlversion.h.in @@ -78,6 +78,15 @@ extern void xmlCheckVersion(int version); #endif /* + * Whether XInclude is configured in + */ +#if @WITH_XINCLUDE@ +#define LIBXML_XINCLUDE_ENABLED +#else +#define LIBXML_XINCLUDE_DISABLED +#endif + +/* * Whether iconv support is available */ #if @WITH_ICONV@ diff --git a/testXPath.c b/testXPath.c index be862ca3..bca7173c 100644 --- a/testXPath.c +++ b/testXPath.c @@ -41,6 +41,7 @@ #include <libxml/debugXML.h> #include <libxml/xmlmemory.h> #include <libxml/parserInternals.h> +#include <libxml/xpathInternals.h> #include <libxml/xmlerror.h> #if defined(LIBXML_XPTR_ENABLED) #include <libxml/xpointer.h> @@ -45,12 +45,16 @@ int xmlSaveNoEmptyTags = 0; #define IS_BLANK(c) \ (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' ')) -#define UPDATE_LAST_CHILD(n) if ((n) != NULL) { \ +#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \ xmlNodePtr ulccur = (n)->children; \ if (ulccur == NULL) { \ (n)->last = NULL; \ } else { \ - while (ulccur->next != NULL) ulccur = ulccur->next; \ + while (ulccur->next != NULL) { \ + ulccur->parent = (n); \ + ulccur = ulccur->next; \ + } \ + ulccur->parent = (n); \ (n)->last = ulccur; \ }} @@ -892,6 +896,7 @@ xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { buffer = xmlEncodeEntitiesReentrant(node->doc, value); cur->children = xmlStringGetNodeList(node->doc, buffer); + cur->last = NULL; tmp = cur->children; while (tmp != NULL) { tmp->parent = (xmlNodePtr) cur; @@ -965,6 +970,7 @@ xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, buffer = xmlEncodeEntitiesReentrant(node->doc, value); cur->children = xmlStringGetNodeList(node->doc, buffer); + cur->last = NULL; tmp = cur->children; while (tmp != NULL) { tmp->parent = (xmlNodePtr) cur; @@ -1027,8 +1033,20 @@ xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { cur->name = xmlStrdup(name); cur->doc = doc; - if (value != NULL) + if (value != NULL) { + xmlNodePtr tmp; + cur->children = xmlStringGetNodeList(doc, value); + cur->last = NULL; + + tmp = cur->children; + while (tmp != NULL) { + tmp->parent = (xmlNodePtr) cur; + if (tmp->next == NULL) + cur->last = tmp; + tmp = tmp->next; + } + } return(cur); } @@ -1239,7 +1257,7 @@ xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, cur->doc = doc; if (content != NULL) { cur->children = xmlStringGetNodeList(doc, content); - UPDATE_LAST_CHILD(cur) + UPDATE_LAST_CHILD_AND_PARENT(cur) } } return(cur); @@ -1268,7 +1286,7 @@ xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, cur->doc = doc; if (content != NULL) { cur->children = xmlNewDocText(doc, content); - UPDATE_LAST_CHILD(cur) + UPDATE_LAST_CHILD_AND_PARENT(cur) } } return(cur); @@ -1491,7 +1509,13 @@ xmlNewReference(xmlDocPtr doc, const xmlChar *name) { if (ent->content != NULL) xmlBufferAdd(cur->content, ent->content, -1); #endif + /* + * The parent pointer in entity is a Dtd pointer and thus is NOT + * updated. Not sure if this is 100% correct. + * -George + */ cur->children = (xmlNodePtr) ent; + cur->last = (xmlNodePtr) ent; } return(cur); } @@ -1662,6 +1686,47 @@ xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { return(cur); } +/** + * xmlSetTreeDoc: + * @tree: the top element + * @doc: the document + * + * update all nodes under the tree to point to the right document + */ +void +xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) { + if (tree == NULL) + return; + if (tree->type == XML_ENTITY_DECL) + return; + if (tree->doc != doc) { + if (tree->children != NULL) + xmlSetListDoc(tree->children, doc); + tree->doc = doc; + } +} + +/** + * xmlSetListDoc: + * @tree: the first element + * @doc: the document + * + * update all nodes in the list to point to the right document + */ +void +xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) { + xmlNodePtr cur; + + if (list == NULL) + return; + cur = list; + while (cur != NULL) { + if (cur->doc != doc) + xmlSetTreeDoc(cur, doc); + cur = cur->next; + } +} + /** * xmlNewChild: @@ -1779,7 +1844,8 @@ xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) { xmlNodeSetContent(cur->next, tmp); xmlFree(tmp); #else - xmlBufferAddHead(cur->next, xmlBufferContent(elem->content), + xmlBufferAddHead(cur->next->content, + xmlBufferContent(elem->content), xmlBufferLength(elem->content)); #endif xmlFreeNode(elem); @@ -1787,7 +1853,9 @@ xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) { } } - elem->doc = cur->doc; + if (elem->doc != cur->doc) { + xmlSetTreeDoc(elem, cur->doc); + } elem->parent = cur->parent; elem->prev = cur; elem->next = cur->next; @@ -1857,7 +1925,9 @@ xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) { } } - elem->doc = cur->doc; + if (elem->doc != cur->doc) { + xmlSetTreeDoc(elem, cur->doc); + } elem->parent = cur->parent; elem->next = cur; elem->prev = cur->prev; @@ -1926,9 +1996,9 @@ xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { return(cur); } - if (elem->doc == NULL) - elem->doc = cur->doc; /* the parent may not be linked to a doc ! */ - + if (elem->doc != cur->doc) { + xmlSetTreeDoc(elem, cur->doc); + } parent = cur->parent; elem->prev = cur; elem->next = NULL; @@ -2011,7 +2081,9 @@ xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { } while (cur->next != NULL) { cur->parent = parent; - cur->doc = parent->doc; /* the parent may not be linked to a doc ! */ + if (cur->doc != parent->doc) { + xmlSetTreeDoc(cur, parent->doc); + } cur = cur->next; } cur->parent = parent; @@ -2090,7 +2162,9 @@ xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) { * add the new element at the end of the children list. */ cur->parent = parent; - cur->doc = parent->doc; /* the parent may not be linked to a doc ! */ + if (cur->doc != parent->doc) { + xmlSetTreeDoc(cur, parent->doc); + } /* * Handle the case where parent->content != NULL, in that case it will @@ -2110,7 +2184,7 @@ xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) { if (text->next != NULL) text->next->prev = text; parent->children = text; - UPDATE_LAST_CHILD(parent) + UPDATE_LAST_CHILD_AND_PARENT(parent) #ifndef XML_USE_BUFFER_CONTENT xmlFree(parent->content); #else @@ -2264,6 +2338,9 @@ xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { xmlUnlinkNode(old); return(old); } + if (cur == old) { + return(old); + } xmlUnlinkNode(cur); cur->doc = old->doc; cur->parent = old->parent; @@ -2374,8 +2451,19 @@ xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { } else ret->ns = NULL; - if (cur->children != NULL) + if (cur->children != NULL) { + xmlNodePtr tmp; + ret->children = xmlCopyNodeList(cur->children); + ret->last = NULL; + tmp = ret->children; + while (tmp != NULL) { + tmp->parent = (xmlNodePtr)ret; + if (tmp->next == NULL) + ret->last = tmp; + tmp = tmp->next; + } + } return(ret); } @@ -2494,7 +2582,7 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, ret->properties = xmlCopyPropList(ret, node->properties); if (node->children != NULL) ret->children = xmlStaticCopyNodeList(node->children, doc, ret); - UPDATE_LAST_CHILD(ret) + UPDATE_LAST_CHILD_AND_PARENT(ret) return(ret); } @@ -2633,9 +2721,18 @@ xmlCopyDoc(xmlDocPtr doc, int recursive) { ret->intSubset = xmlCopyDtd(doc->intSubset); if (doc->oldNs != NULL) ret->oldNs = xmlCopyNamespaceList(doc->oldNs); - if (doc->children != NULL) + if (doc->children != NULL) { + xmlNodePtr tmp; ret->children = xmlStaticCopyNodeList(doc->children, ret, (xmlNodePtr)ret); + ret->last = NULL; + tmp = ret->children; + while (tmp != NULL) { + if (tmp->next == NULL) + ret->last = tmp; + tmp = tmp->next; + } + } return(ret); } @@ -2692,6 +2789,7 @@ xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { if (old == NULL) { if (doc->children == NULL) { doc->children = root; + doc->last = root; } else { xmlAddSibling(doc->children, root); } @@ -2732,6 +2830,8 @@ xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { #ifdef LIBXML_SGML_ENABLED case XML_SGML_DOCUMENT_NODE: #endif + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: @@ -2792,6 +2892,8 @@ xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: #ifdef LIBXML_SGML_ENABLED case XML_SGML_DOCUMENT_NODE: #endif @@ -2863,6 +2965,8 @@ xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { case XML_NOTATION_NODE: case XML_HTML_DOCUMENT_NODE: case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: #ifdef LIBXML_SGML_ENABLED case XML_SGML_DOCUMENT_NODE: #endif @@ -2911,6 +3015,8 @@ xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) { case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: #ifdef LIBXML_SGML_ENABLED case XML_SGML_DOCUMENT_NODE: #endif @@ -2923,12 +3029,46 @@ xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) { } /** + * xmlDocumentGetBase: + * @doc: the document + * + * Searches for the Document BASE URL. The code should work on both XML + * and HTML document. + * It returns the base as defined in RFC 2396 section + * 5.1.3. Base URI from the Retrieval URI + * However it does not return the computed base (5.1.1 and 5.1.2), use + * xmlNodeGetBase() for this + * + * Returns a pointer to the base URL, or NULL if not found + * It's up to the caller to free the memory. + */ +xmlChar * +xmlDocumentGetBase(xmlDocPtr doc) { + if (doc == NULL) + return(NULL); + if (doc->type == XML_HTML_DOCUMENT_NODE) { + if (doc->URL != NULL) + return(xmlStrdup(doc->URL)); + return(NULL); + } + if (doc->URL != NULL) + return(xmlStrdup(doc->URL)); + return(NULL); +} + +/** * xmlNodeGetBase: * @doc: the document the node pertains to * @cur: the node being checked * * Searches for the BASE URL. The code should work on both XML * and HTML document even if base mechanisms are completely different. + * It returns the base as defined in RFC 2396 sections + * 5.1.1. Base URI within Document Content + * and + * 5.1.2. Base URI from the Encapsulating Entity + * However it does not return the document base (5.1.3), use + * xmlDocumentGetBase() for this * * Returns a pointer to the base URL, or NULL if not found * It's up to the caller to free the memory. @@ -2943,9 +3083,6 @@ xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) { if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { cur = doc->children; while ((cur != NULL) && (cur->name != NULL)) { - if (cur->type == XML_ENTITY_DECL) { - /* TODO: we are crossing entity boundaries */ - } if (cur->type != XML_ELEMENT_NODE) { cur = cur->next; continue; @@ -2963,18 +3100,18 @@ xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) { } cur = cur->next; } - if ((doc != NULL) && (doc->URL != NULL)) - return(xmlStrdup(doc->URL)); return(NULL); } while (cur != NULL) { + if (cur->type == XML_ENTITY_DECL) { + xmlEntityPtr ent = (xmlEntityPtr) cur; + return(xmlStrdup(ent->URI)); + } base = xmlGetProp(cur, BAD_CAST "xml:base"); if (base != NULL) return(base); cur = cur->parent; } - if ((doc != NULL) && (doc->URL != NULL)) - return(xmlStrdup(doc->URL)); return(NULL); } @@ -3026,13 +3163,14 @@ xmlNodeGetContent(xmlNodePtr cur) { case XML_DOCUMENT_TYPE_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: #ifdef LIBXML_SGML_ENABLED case XML_SGML_DOCUMENT_NODE: #endif return(NULL); case XML_NAMESPACE_DECL: - /* TODO !!! */ - return(NULL); + return(xmlStrdup(((xmlNsPtr)cur)->href)); case XML_ELEMENT_DECL: /* TODO !!! */ return(NULL); @@ -3084,7 +3222,7 @@ xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { } if (cur->children != NULL) xmlFreeNodeList(cur->children); cur->children = xmlStringGetNodeList(cur->doc, content); - UPDATE_LAST_CHILD(cur) + UPDATE_LAST_CHILD_AND_PARENT(cur) break; case XML_ATTRIBUTE_NODE: break; @@ -3118,6 +3256,8 @@ xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: #ifdef LIBXML_SGML_ENABLED case XML_SGML_DOCUMENT_NODE: #endif @@ -3170,7 +3310,7 @@ xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { } if (cur->children != NULL) xmlFreeNodeList(cur->children); cur->children = xmlStringLenGetNodeList(cur->doc, content, len); - UPDATE_LAST_CHILD(cur) + UPDATE_LAST_CHILD_AND_PARENT(cur) break; case XML_ATTRIBUTE_NODE: break; @@ -3207,6 +3347,8 @@ xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: #ifdef LIBXML_SGML_ENABLED case XML_SGML_DOCUMENT_NODE: #endif @@ -3256,7 +3398,7 @@ xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { cur->children = xmlStringGetNodeList(cur->doc, xmlBufferContent(cur->content)); #endif - UPDATE_LAST_CHILD(cur) + UPDATE_LAST_CHILD_AND_PARENT(cur) #ifndef XML_USE_BUFFER_CONTENT xmlFree(cur->content); #else @@ -3296,6 +3438,8 @@ xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: #ifdef LIBXML_SGML_ENABLED case XML_SGML_DOCUMENT_NODE: #endif @@ -3944,12 +4088,14 @@ xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { if (prop->children != NULL) xmlFreeNodeList(prop->children); prop->children = NULL; + prop->last = NULL; if (value != NULL) { xmlChar *buffer; xmlNodePtr tmp; buffer = xmlEncodeEntitiesReentrant(node->doc, value); prop->children = xmlStringGetNodeList(node->doc, buffer); + prop->last = NULL; tmp = prop->children; while (tmp != NULL) { tmp->parent = (xmlNodePtr) prop; @@ -3993,12 +4139,16 @@ xmlNodeIsText(xmlNodePtr node) { */ int xmlIsBlankNode(xmlNodePtr node) { - xmlChar *cur; + const xmlChar *cur; if (node == NULL) return(0); if (node->type != XML_TEXT_NODE) return(0); if (node->content == NULL) return(1); +#ifndef XML_USE_BUFFER_CONTENT cur = node->content; +#else + cur = xmlBufferContent(node->content); +#endif while (*cur != 0) { if (!IS_BLANK(*cur)) return(0); cur++; @@ -4749,6 +4899,10 @@ xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, #endif return; } + if (cur->type == XML_XINCLUDE_START) + return; + if (cur->type == XML_XINCLUDE_END) + return; if (cur->type == XML_DTD_NODE) { xmlDtdDump(buf, (xmlDtdPtr) cur); return; @@ -5201,6 +5355,10 @@ xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, #endif return; } + if (cur->type == XML_XINCLUDE_START) + return; + if (cur->type == XML_XINCLUDE_END) + return; if (cur->type == XML_DTD_NODE) { xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding); return; @@ -41,9 +41,11 @@ typedef enum { XML_ELEMENT_DECL= 15, XML_ATTRIBUTE_DECL= 16, XML_ENTITY_DECL= 17, - XML_NAMESPACE_DECL= 18 + XML_NAMESPACE_DECL= 18, + XML_XINCLUDE_START= 19, + XML_XINCLUDE_END= 20 #ifdef LIBXML_SGML_ENABLED - ,XML_SGML_DOCUMENT_NODE= 19 + ,XML_SGML_DOCUMENT_NODE= 21 #endif } xmlElementType; @@ -22,6 +22,13 @@ #include <libxml/uri.h> #include <libxml/xmlerror.h> +/************************************************************************ + * * + * Macros to differenciate various character type * + * directly extracted from RFC 2396 * + * * + ************************************************************************/ + /* * alpha = lowalpha | upalpha */ @@ -169,6 +176,12 @@ * path = [ abs_path | opaque_part ] */ +/************************************************************************ + * * + * Generic URI structure functions * + * * + ************************************************************************/ + /** * xmlCreateURI: * @@ -587,6 +600,143 @@ xmlFreeURI(xmlURIPtr uri) { xmlFree(uri); } +/************************************************************************ + * * + * Helper functions * + * * + ************************************************************************/ + +/** + * xmlNormalizeURIPath: + * @path: pointer to the path string + * + * applies the 5 normalization steps to a path string + * Normalization occurs directly on the string, no new allocation is done + * + * Returns 0 or an error code + */ +int +xmlNormalizeURIPath(char *path) { + int cur, out; + + if (path == NULL) + return(-1); + cur = 0; + out = 0; + while ((path[cur] != 0) && (path[cur] != '/')) cur++; + if (path[cur] == 0) + return(0); + + /* we are positionned at the beginning of the first segment */ + cur++; + out = cur; + + /* + * Analyze each segment in sequence. + */ + while (path[cur] != 0) { + /* + * c) All occurrences of "./", where "." is a complete path segment, + * are removed from the buffer string. + */ + if ((path[cur] == '.') && (path[cur + 1] == '/')) { + cur += 2; + continue; + } + + /* + * d) If the buffer string ends with "." as a complete path segment, + * that "." is removed. + */ + if ((path[cur] == '.') && (path[cur + 1] == 0)) { + path[out] = 0; + break; + } + + /* read the segment */ + while ((path[cur] != 0) && (path[cur] != '/')) { + path[out++] = path[cur++]; + } + path[out++] = path[cur]; + if (path[cur] != 0) { + cur++; + } + } + + cur = 0; + out = 0; + while ((path[cur] != 0) && (path[cur] != '/')) cur++; + if (path[cur] == 0) + return(0); + /* we are positionned at the beginning of the first segment */ + cur++; + out = cur; + /* + * Analyze each segment in sequence. + */ + while (path[cur] != 0) { + /* + * e) All occurrences of "<segment>/../", where <segment> is a + * complete path segment not equal to "..", are removed from the + * buffer string. Removal of these path segments is performed + * iteratively, removing the leftmost matching pattern on each + * iteration, until no matching pattern remains. + */ + if ((cur > 1) && (out > 1) && + (path[cur] == '/') && (path[cur + 1] == '.') && + (path[cur + 2] == '.') && (path[cur + 3] == '/') && + ((path[out] != '.') || (path[out - 1] != '.') || + (path[out - 2] != '/'))) { + cur += 3; + out --; + while ((out > 0) && (path[out] != '/')) { out --; } + path[out] = 0; + continue; + } + + /* + * f) If the buffer string ends with "<segment>/..", where <segment> + * is a complete path segment not equal to "..", that + * "<segment>/.." is removed. + */ + if ((path[cur] == '/') && (path[cur + 1] == '.') && + (path[cur + 2] == '.') && (path[cur + 3] == 0) && + ((path[out] != '.') || (path[out - 1] != '.') || + (path[out - 2] != '/'))) { + cur += 4; + out --; + while ((out > 0) && (path[out - 1] != '/')) { out --; } + path[out] = 0; + continue; + } + + path[out++] = path[cur++]; /* / or 0 */ + } + path[out] = 0; + + /* + * g) If the resulting buffer string still begins with one or more + * complete path segments of "..", then the reference is + * considered to be in error. Implementations may handle this + * error by retaining these components in the resolved path (i.e., + * treating them as part of the final URI), by removing them from + * the resolved path (i.e., discarding relative levels above the + * root), or by avoiding traversal of the reference. + * + * We discard them from the final path. + */ + cur = 0; + while ((path[cur] == '/') && (path[cur + 1] == '.') && + (path[cur + 2] == '.')) + cur += 3; + if (cur != 0) { + out = 0; + while (path[cur] != 0) path[out++] = path[cur++]; + path[out] = 0; + } + return(0); +} + /** * xmlURIUnescapeString: * @str: the string to unescape @@ -647,6 +797,74 @@ xmlURIUnescapeString(const char *str, int len, char *target) { return(ret); } +/** + * xmlURIEscape: + * @str: the string of the URI to escape + * + * Escaping routine, does not do validity checks ! + * It will try to escape the chars needing this, but this is heuristic + * based it's impossible to be sure. + * + * Returns an copy of the string, but escaped + */ +xmlChar * +xmlURIEscape(const xmlChar *str) { + xmlChar *ret; + const xmlChar *in; + unsigned int len, out; + + if (str == NULL) + return(NULL); + len = xmlStrlen(str); + if (len <= 0) return(NULL); + + len += 20; + ret = (xmlChar *) xmlMalloc(len); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlURIEscape: out of memory\n"); + return(NULL); + } + in = (const xmlChar *) str; + out = 0; + while(*in != 0) { + if (len - out <= 3) { + len += 20; + ret = (xmlChar *) xmlRealloc(ret, len); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlURIEscape: out of memory\n"); + return(NULL); + } + } + if ((!IS_UNRESERVED(*in)) && (*in != ':') && (*in != '/') && + (*in != '?') && (*in != '#')) { + unsigned char val; + ret[out++] = '%'; + val = *in >> 4; + if (val <= 9) + ret[out++] = '0' + val; + else + ret[out++] = 'A' + val - 0xA; + val = *in & 0xF; + if (val <= 9) + ret[out++] = '0' + val; + else + ret[out++] = 'A' + val - 0xA; + in++; + } else { + ret[out++] = *in++; + } + } + ret[out] = 0; + return(ret); +} + +/************************************************************************ + * * + * Escaped URI parsing * + * * + ************************************************************************/ /** * xmlParseURIFragment: @@ -1284,136 +1502,11 @@ xmlParseURI(const char *str) { return(uri); } -/** - * xmlNormalizeURIPath: - * @path: pointer to the path string - * - * applies the 5 normalization steps to a path string - * Normalization occurs directly on the string, no new allocation is done - * - * Returns 0 or an error code - */ -int -xmlNormalizeURIPath(char *path) { - int cur, out; - - if (path == NULL) - return(-1); - cur = 0; - out = 0; - while ((path[cur] != 0) && (path[cur] != '/')) cur++; - if (path[cur] == 0) - return(0); - - /* we are positionned at the beginning of the first segment */ - cur++; - out = cur; - - /* - * Analyze each segment in sequence. - */ - while (path[cur] != 0) { - /* - * c) All occurrences of "./", where "." is a complete path segment, - * are removed from the buffer string. - */ - if ((path[cur] == '.') && (path[cur + 1] == '/')) { - cur += 2; - continue; - } - - /* - * d) If the buffer string ends with "." as a complete path segment, - * that "." is removed. - */ - if ((path[cur] == '.') && (path[cur + 1] == 0)) { - path[out] = 0; - break; - } - - /* read the segment */ - while ((path[cur] != 0) && (path[cur] != '/')) { - path[out++] = path[cur++]; - } - path[out++] = path[cur]; - if (path[cur] != 0) { - cur++; - } - } - - cur = 0; - out = 0; - while ((path[cur] != 0) && (path[cur] != '/')) cur++; - if (path[cur] == 0) - return(0); - /* we are positionned at the beginning of the first segment */ - cur++; - out = cur; - /* - * Analyze each segment in sequence. - */ - while (path[cur] != 0) { - /* - * e) All occurrences of "<segment>/../", where <segment> is a - * complete path segment not equal to "..", are removed from the - * buffer string. Removal of these path segments is performed - * iteratively, removing the leftmost matching pattern on each - * iteration, until no matching pattern remains. - */ - if ((cur > 1) && (out > 1) && - (path[cur] == '/') && (path[cur + 1] == '.') && - (path[cur + 2] == '.') && (path[cur + 3] == '/') && - ((path[out] != '.') || (path[out - 1] != '.') || - (path[out - 2] != '/'))) { - cur += 3; - out --; - while ((out > 0) && (path[out] != '/')) { out --; } - path[out] = 0; - continue; - } - - /* - * f) If the buffer string ends with "<segment>/..", where <segment> - * is a complete path segment not equal to "..", that - * "<segment>/.." is removed. - */ - if ((path[cur] == '/') && (path[cur + 1] == '.') && - (path[cur + 2] == '.') && (path[cur + 3] == 0) && - ((path[out] != '.') || (path[out - 1] != '.') || - (path[out - 2] != '/'))) { - cur += 4; - out --; - while ((out > 0) && (path[out - 1] != '/')) { out --; } - path[out] = 0; - continue; - } - - path[out++] = path[cur++]; /* / or 0 */ - } - path[out] = 0; - - /* - * g) If the resulting buffer string still begins with one or more - * complete path segments of "..", then the reference is - * considered to be in error. Implementations may handle this - * error by retaining these components in the resolved path (i.e., - * treating them as part of the final URI), by removing them from - * the resolved path (i.e., discarding relative levels above the - * root), or by avoiding traversal of the reference. - * - * We discard them from the final path. - */ - cur = 0; - while ((path[cur] == '/') && (path[cur + 1] == '.') && - (path[cur + 2] == '.')) - cur += 3; - if (cur != 0) { - out = 0; - while (path[cur] != 0) path[out++] = path[cur++]; - path[out] = 0; - } - return(0); -} +/************************************************************************ + * * + * Public functions * + * * + ************************************************************************/ /** * xmlBuildURI: @@ -52,6 +52,7 @@ char * xmlURIUnescapeString (const char *str, int len, char *target); int xmlNormalizeURIPath (char *path); +xmlChar * xmlURIEscape (const xmlChar *str); void xmlFreeURI (xmlURIPtr uri); #ifdef __cplusplus @@ -3212,6 +3212,7 @@ xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) { case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: + case XML_NAMESPACE_DECL: strcat(buf, "???"); if (cur->next != NULL) strcat(buf, " "); @@ -3223,6 +3224,8 @@ xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) { case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: break; } cur = cur->next; diff --git a/xinclude.c b/xinclude.c new file mode 100644 index 00000000..3a3bf67d --- /dev/null +++ b/xinclude.c @@ -0,0 +1,737 @@ +/* + * 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: compute XPointers nodesets + */ + +#ifdef WIN32 +#include "win32config.h" +#else +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <libxml/xmlmemory.h> +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/uri.h> +#include <libxml/xpointer.h> +#include <libxml/parserInternals.h> +#ifdef LIBXML_DEBUG_ENABLED +#include <libxml/debugXML.h> +#endif +#include <libxml/xmlerror.h> + +#ifdef LIBXML_XINCLUDE_ENABLED +#include <libxml/xinclude.h> + +#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 XINCLUDE_PARSE_XML (const xmlChar *) "xml" +#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text" + +/* #define DEBUG_XINCLUDE */ + +/************************************************************************ + * * + * XInclude contexts handling * + * * + ************************************************************************/ + +/* + * 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 parsed documents */ + int docMax; /* size of parsed documents tab */ + xmlDocPtr *docTab; /* array of parsed documents */ + URL *urlTab; /* array of parsed documents URLs */ + int txtNr; /* number of unparsed documents */ + int txtMax; /* size of unparsed documents tab */ + xmlNodePtr *txtTab; /* array of unparsed text nodes */ + URL *txturlTab; /* array of unparsed txtuments 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->repTab[ctxt->incNr] = NULL; + 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++; +} + +/** + * xmlXIncludeAddTxt: + * @ctxt: the XInclude context + * @txt: the new text node + * @url: the associated URL + * + * Add a new txtument to the list + */ +void +xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const URL url) { + if (ctxt->txtMax == 0) { + ctxt->txtMax = 4; + ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax * + sizeof(ctxt->txtTab[0])); + if (ctxt->txtTab == NULL) { + xmlGenericError(xmlGenericErrorContext, + "malloc failed !\n"); + return; + } + ctxt->txturlTab = (URL *) xmlMalloc(ctxt->txtMax * + sizeof(ctxt->txturlTab[0])); + if (ctxt->txturlTab == NULL) { + xmlGenericError(xmlGenericErrorContext, + "malloc failed !\n"); + return; + } + } + if (ctxt->txtNr >= ctxt->txtMax) { + ctxt->txtMax *= 2; + ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab, + ctxt->txtMax * sizeof(ctxt->txtTab[0])); + if (ctxt->txtTab == NULL) { + xmlGenericError(xmlGenericErrorContext, + "realloc failed !\n"); + return; + } + ctxt->txturlTab = (URL *) xmlRealloc(ctxt->txturlTab, + ctxt->txtMax * sizeof(ctxt->urlTab[0])); + if (ctxt->txturlTab == NULL) { + xmlGenericError(xmlGenericErrorContext, + "realloc failed !\n"); + return; + } + } + ctxt->txtTab[ctxt->txtNr] = txt; + ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url); + ctxt->txtNr++; +} + +/** + * 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); +} + +/************************************************************************ + * * + * XInclude I/O handling * + * * + ************************************************************************/ + +/** + * xmlXIncludeLoadDoc: + * @ctxt: the XInclude context + * @url: the associated URL + * @nr: the xinclude node number + * + * Load the document, and store the result in the XInclude context + */ +void +xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { + xmlDocPtr doc; + xmlURIPtr uri; + xmlChar *URL; + int i; + /* + * Check the URL and remove any fragment identifier + */ + uri = xmlParseURI((const char *)url); + if (uri == NULL) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: invalid value URI %s\n", url); + return; + } + if (uri->fragment != NULL) { + xmlFree(uri->fragment); + uri->fragment = NULL; /* TODO: kkep it for later processing */ + } + URL = xmlSaveUri(uri); + xmlFreeURI(uri); + if (URL == NULL) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: invalid value URI %s\n", url); + return; + } + + /* + * Handling of references to the local document are done + * directly through ctxt->doc. + */ + if (URL[0] == 0) { + xmlFree(URL); + return; + } + + /* + * Prevent reloading twice the document. + */ + for (i = 0; i < ctxt->docNr; i++) { + if (xmlStrEqual(URL, ctxt->urlTab[i])) { + doc = ctxt->docTab[i]; + goto loaded; + } + } + /* + * Load it. + */ + doc = xmlParseFile((const char *)URL); + if (doc == NULL) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: could not load %s\n", URL); + xmlFree(URL); + return; + } + xmlXIncludeAddDoc(ctxt, doc, URL); + +loaded: + /* + * Add the top children list as the replacement copy. + */ + ctxt->repTab[nr] = xmlCopyNodeList(doc->children); + xmlFree(URL); +} + +/** + * xmlXIncludeLoadTxt: + * @ctxt: the XInclude context + * @url: the associated URL + * @nr: the xinclude node number + * + * Load the content, and store the result in the XInclude context + */ +void +xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { + xmlParserInputBufferPtr buf; + xmlNodePtr node; + xmlURIPtr uri; + xmlChar *URL; + int i; + /* + * Check the URL and remove any fragment identifier + */ + uri = xmlParseURI((const char *)url); + if (uri == NULL) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: invalid value URI %s\n", url); + return; + } + if (uri->fragment != NULL) { + xmlFreeURI(uri); + xmlGenericError(xmlGenericErrorContext, + "XInclude: fragment identifier forbidden for text\n"); + return; + } + URL = xmlSaveUri(uri); + xmlFreeURI(uri); + if (URL == NULL) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: invalid value URI %s\n", url); + return; + } + + /* + * Handling of references to the local document are done + * directly through ctxt->doc. + */ + if (URL[0] == 0) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: text serialization of document not available\n"); + xmlFree(URL); + return; + } + + /* + * Prevent reloading twice the document. + */ + for (i = 0; i < ctxt->txtNr; i++) { + if (xmlStrEqual(URL, ctxt->txturlTab[i])) { + node = xmlCopyNode(ctxt->txtTab[i], 1); + goto loaded; + } + } + /* + * Load it. + * Issue 62: how to detect the encoding + */ + buf = xmlParserInputBufferCreateFilename((const char *)URL, 0); + if (buf == NULL) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: could not load %s\n", URL); + xmlFree(URL); + return; + } + node = xmlNewText(NULL); + + /* + * Scan all chars from the resource and add the to the node + */ + while (xmlParserInputBufferRead(buf, 128) > 0) { + int len; + const xmlChar *content; + + content = xmlBufferContent(buf->buffer); + len = xmlBufferLength(buf->buffer); + for (i = 0;i < len; i++) { + /* + * TODO: if the encoding issue is solved, scan UTF8 chars instead + */ + if (!IS_CHAR(content[i])) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: %s contains invalid char %d\n", URL, content[i]); + } else { + xmlNodeAddContentLen(node, &content[i], 1); + } + } + xmlBufferShrink(buf->buffer, len); + } + xmlFreeParserInputBuffer(buf); + xmlXIncludeAddTxt(ctxt, node, URL); + +loaded: + /* + * Add the element as the replacement copy. + */ + ctxt->repTab[nr] = node; + xmlFree(URL); +} + +/************************************************************************ + * * + * XInclude Processing * + * * + ************************************************************************/ + +/** + * 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 +xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) { + xmlNodePtr cur; + 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 + /* + * read the attributes + */ + href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF); + if (href == NULL) { + href = xmlGetProp(cur, XINCLUDE_HREF); + if (href == NULL) { + xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n"); + return(-1); + } + } + parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE); + if (parse == NULL) { + parse = xmlGetProp(cur, XINCLUDE_PARSE); + } + if (parse != NULL) { + if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) + xml = 1; + else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT)) + xml = 0; + else { + xmlGenericError(xmlGenericErrorContext, + "XInclude: invalid value %s for %s\n", + parse, XINCLUDE_PARSE); + if (href != NULL) + xmlFree(href); + if (parse != NULL) + xmlFree(parse); + return(-1); + } + } + + /* + * compute the URI + */ + base = xmlNodeGetBase(ctxt->doc, cur); + URI = xmlBuildURI(href, base); + if (URI == NULL) { + xmlChar *escbase; + xmlChar *eschref; + /* + * Some escapeing may be needed + */ + escbase = xmlURIEscape(base); + eschref = xmlURIEscape(href); + URI = xmlBuildURI(eschref, escbase); + if (escbase != NULL) + xmlFree(escbase); + if (eschref != NULL) + xmlFree(eschref); + } + if (URI == NULL) { + xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n"); + if (parse != NULL) + xmlFree(parse); + if (href != NULL) + xmlFree(href); + if (base != NULL) + xmlFree(base); + return(-1); + } +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "parse: %s\n", + xml ? "xml": "text"); + xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI); +#endif + + /* + * Cleanup + */ + if (xml) { + xmlXIncludeLoadDoc(ctxt, URI, nr); + /* xmlXIncludeGetFragment(ctxt, cur, URI); */ + } else { + xmlXIncludeLoadTxt(ctxt, URI, nr); + } + + /* + * Cleanup + */ + if (URI != NULL) + xmlFree(URI); + if (parse != NULL) + xmlFree(parse); + if (href != NULL) + xmlFree(href); + if (base != NULL) + xmlFree(base); + return(0); +} + +/** + * xmlXIncludeIncludeNode: + * @ctxt: an XInclude context + * @nr: the node number + * + * Inplement the infoset replacement for the given node + * + * Returns 0 if substition succeeded, -1 if some processing failed + */ +int +xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { + xmlNodePtr cur, end, list; + + if (ctxt == NULL) + return(-1); + if ((nr < 0) || (nr >= ctxt->incNr)) + return(-1); + cur = ctxt->incTab[nr]; + if (cur == NULL) + return(-1); + + /* + * Change the current node as an XInclude start one, and add an + * entity end one + */ + cur->type = XML_XINCLUDE_START; + end = xmlNewNode(cur->ns, cur->name); + if (end == NULL) { + xmlGenericError(xmlGenericErrorContext, + "XInclude: failed to build node\n"); + return(-1); + } + end->type = XML_XINCLUDE_END; + xmlAddNextSibling(cur, end); + + /* + * Add the list of nodes + */ + list = ctxt->repTab[nr]; + ctxt->repTab[nr] = NULL; + while (list != NULL) { + cur = list; + list = list->next; + + xmlAddPrevSibling(end, cur); + } + 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) { + /* TODO: need to work on entities -> stack */ + if ((cur->children != NULL) && + (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++) { + xmlXIncludeLoadNode(ctxt, i); + } + + /* + * Third phase: extend the original document infoset. + */ + for (i = 0;i < ctxt->incNr; i++) { + xmlXIncludeIncludeNode(ctxt, i); + } + + /* + * Cleanup + */ + xmlXIncludeFreeContext(ctxt); + return(ret); +} + +#else /* !LIBXML_XINCLUDE_ENABLED */ +#endif diff --git a/xinclude.h b/xinclude.h new file mode 100644 index 00000000..eca4588c --- /dev/null +++ b/xinclude.h @@ -0,0 +1,26 @@ +/* + * xinclude.c : API to handle 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 + */ + +#ifndef __XML_XINCLUDE_H__ +#define __XML_XINCLUDE_H__ + +#include <libxml/tree.h> + +#ifdef __cplusplus +extern "C" { +#endif + +int xmlXIncludeProcess (xmlDocPtr doc); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_XINCLUDE_H__ */ @@ -55,6 +55,9 @@ #include <libxml/xpath.h> #include <libxml/debugXML.h> #include <libxml/xmlerror.h> +#ifdef LIBXML_XINCLUDE_ENABLED +#include <libxml/xinclude.h> +#endif #ifdef LIBXML_DEBUG_ENABLED static int debug = 0; @@ -81,6 +84,9 @@ static int memory = 0; static int noblanks = 0; static int testIO = 0; static char *encoding = NULL; +#ifdef LIBXML_XINCLUDE_ENABLED +static int xinclude = 0; +#endif extern int xmlDoValidityCheckingDefaultValue; extern int xmlGetWarningsDefaultValue; @@ -497,10 +503,14 @@ void parseAndPrintFile(char *filename) { /* * If we don't have a document we might as well give up. Do we * want an error message here? <sven@zen.org> */ - if (doc == NULL) - { + if (doc == NULL) { return; - } + } + +#ifdef LIBXML_XINCLUDE_ENABLED + if (xinclude) + xmlXIncludeProcess(doc); +#endif #ifdef LIBXML_DEBUG_ENABLED /* @@ -667,6 +677,11 @@ int main(int argc, char **argv) { else if ((!strcmp(argv[i], "-testIO")) || (!strcmp(argv[i], "--testIO"))) testIO++; +#ifdef LIBXML_XINCLUDE_ENABLED + else if ((!strcmp(argv[i], "-xinclude")) || + (!strcmp(argv[i], "--xinclude"))) + xinclude++; +#endif else if ((!strcmp(argv[i], "-compress")) || (!strcmp(argv[i], "--compress"))) { compress++; @@ -773,6 +788,9 @@ int main(int argc, char **argv) { printf("\t--noblanks : drop (ignorable?) blanks spaces\n"); printf("\t--testIO : test user I/O support\n"); printf("\t--encode encoding : output in the given encoding\n"); +#ifdef LIBXML_XINCLUDE_ENABLED + printf("\t--xinclude : do XInclude processing\n"); +#endif } xmlCleanupParser(); xmlMemoryDump(); diff --git a/xmlversion.h.in b/xmlversion.h.in index 01b1ea17..4d21762c 100644 --- a/xmlversion.h.in +++ b/xmlversion.h.in @@ -78,6 +78,15 @@ extern void xmlCheckVersion(int version); #endif /* + * Whether XInclude is configured in + */ +#if @WITH_XINCLUDE@ +#define LIBXML_XINCLUDE_ENABLED +#else +#define LIBXML_XINCLUDE_DISABLED +#endif + +/* * Whether iconv support is available */ #if @WITH_ICONV@ @@ -597,20 +597,51 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { */ xmlNodeSetPtr xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { - int i; + int i, j, initNr; if (val2 == NULL) return(val1); if (val1 == NULL) { val1 = xmlXPathNodeSetCreate(NULL); } - /* - * !!!!! this can be optimized a lot, knowing that both - * val1 and val2 already have unicity of their values. - */ + initNr = val1->nodeNr; - for (i = 0;i < val2->nodeNr;i++) - xmlXPathNodeSetAdd(val1, val2->nodeTab[i]); + for (i = 0;i < val2->nodeNr;i++) { + /* + * check against doublons + */ + for (j = 0; j < initNr; j++) + if (val1->nodeTab[j] == val2->nodeTab[i]) continue; + + /* + * grow the nodeTab if needed + */ + if (val1->nodeMax == 0) { + val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * + sizeof(xmlNodePtr)); + if (val1->nodeTab == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathNodeSetMerge: out of memory\n"); + return(NULL); + } + memset(val1->nodeTab, 0 , + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + val1->nodeMax = XML_NODESET_DEFAULT; + } else if (val1->nodeNr == val1->nodeMax) { + xmlNodePtr *temp; + + val1->nodeMax *= 2; + temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathNodeSetMerge: out of memory\n"); + return(NULL); + } + val1->nodeTab = temp; + } + val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; + } return(val1); } @@ -1922,12 +1953,12 @@ typedef xmlNodePtr (*xmlXPathTraversalFunction) (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); /** - * mlXPathNextSelf: + * xmlXPathNextSelf: * @ctxt: the XPath Parser context * @cur: the current node in the traversal * * Traversal function for the "self" direction - * he self axis contains just the context node itself + * The self axis contains just the context node itself * * Returns the next element following that axis */ @@ -1939,7 +1970,7 @@ xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { } /** - * mlXPathNextChild: + * xmlXPathNextChild: * @ctxt: the XPath Parser context * @cur: the current node in the traversal * @@ -1976,6 +2007,8 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { case XML_ENTITY_DECL: case XML_ATTRIBUTE_NODE: case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: return(NULL); } return(NULL); @@ -1987,7 +2020,7 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { } /** - * mlXPathNextDescendant: + * xmlXPathNextDescendant: * @ctxt: the XPath Parser context * @cur: the current node in the traversal * @@ -2002,7 +2035,8 @@ xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { if (cur == NULL) { if (ctxt->context->node == NULL) return(NULL); - if (ctxt->context->node->type == XML_ATTRIBUTE_NODE) + if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || + (ctxt->context->node->type == XML_NAMESPACE_DECL)) return(NULL); if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) @@ -2030,7 +2064,7 @@ xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { } /** - * mlXPathNextDescendantOrSelf: + * xmlXPathNextDescendantOrSelf: * @ctxt: the XPath Parser context * @cur: the current node in the traversal * @@ -2047,7 +2081,8 @@ xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { if (cur == NULL) { if (ctxt->context->node == NULL) return(NULL); - if (ctxt->context->node->type == XML_ATTRIBUTE_NODE) + if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || + (ctxt->context->node->type == XML_NAMESPACE_DECL)) return(NULL); return(ctxt->context->node); } @@ -2086,6 +2121,8 @@ xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: case XML_ENTITY_DECL: if (ctxt->context->node->parent == NULL) return((xmlNodePtr) ctxt->context->doc); @@ -2151,6 +2188,8 @@ xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_NOTATION_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: if (ctxt->context->node->parent == NULL) return((xmlNodePtr) ctxt->context->doc); return(ctxt->context->node->parent); @@ -2194,6 +2233,8 @@ xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: return(cur->parent); case XML_ATTRIBUTE_NODE: { xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; @@ -2252,6 +2293,9 @@ xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || + (ctxt->context->node->type == XML_NAMESPACE_DECL)) + return(NULL); if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); if (cur == NULL) @@ -2273,6 +2317,9 @@ xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || + (ctxt->context->node->type == XML_NAMESPACE_DECL)) + return(NULL); if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); if (cur == NULL) @@ -2303,7 +2350,7 @@ xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { do { cur = cur->parent; if (cur == NULL) return(NULL); - if (cur == ctxt->context->doc->children) return(NULL); /* !!!!!?!? */ + if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); if (cur->next != NULL) return(cur->next); } while (cur != NULL); return(cur); @@ -2320,13 +2367,18 @@ xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ static int xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { - xmlNodePtr tmp ; - if (ancestor == NULL || node == NULL) return 0 ; - for (tmp = node ; tmp->parent != NULL ; tmp = tmp->parent) { - if (tmp->parent == ancestor) - return 1 ; + if ((ancestor == NULL) || (node == NULL)) return(0); + /* nodes need to be in the same document */ + if (ancestor->doc != node->doc) return(0); + /* avoid searching if ancestor or node is the root node */ + if (ancestor == (xmlNodePtr) node->doc) return(1); + if (node == (xmlNodePtr) ancestor->doc) return(0); + while (node->parent != NULL) { + if (node->parent == ancestor) + return(1); + node = node->parent; } - return 0 ; + return(0); } /** @@ -2372,8 +2424,9 @@ xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { * * Returns the next element following that axis */ -xmlNsPtr -xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) { +xmlNodePtr +xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); if ((cur == NULL) || (ctxt->context->namespaces == NULL)) { if (ctxt->context->namespaces != NULL) xmlFree(ctxt->context->namespaces); @@ -2382,7 +2435,7 @@ xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) { if (ctxt->context->namespaces == NULL) return(NULL); ctxt->context->nsNr = 0; } - return(ctxt->context->namespaces[ctxt->context->nsNr++]); + return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]); } /** @@ -2395,14 +2448,15 @@ xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) { * * Returns the next element following that axis */ -xmlAttrPtr -xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) { +xmlNodePtr +xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); if (cur == NULL) { if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) return(NULL); - return(ctxt->context->node->properties); + return((xmlNodePtr)ctxt->context->node->properties); } - return(cur->next); + return((xmlNodePtr)cur->next); } /************************************************************************ @@ -2483,7 +2537,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis, xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); #endif - next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break; + next = xmlXPathNextAttribute; break; break; case AXIS_CHILD: #ifdef DEBUG_STEP @@ -2637,17 +2691,33 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis, } break; case NODE_TEST_ALL: - if ((cur->type == XML_ELEMENT_NODE) || - (cur->type == XML_DOCUMENT_NODE) || - (cur->type == XML_HTML_DOCUMENT_NODE)) { + if (axis == AXIS_ATTRIBUTE) { + if (cur->type == XML_ATTRIBUTE_NODE) { #ifdef DEBUG_STEP - n++; + n++; #endif - xmlXPathNodeSetAdd(ret, cur); + xmlXPathNodeSetAdd(ret, cur); + } + } else if (axis == AXIS_NAMESPACE) { + if (cur->type == XML_NAMESPACE_DECL) { +#ifdef DEBUG_STEP + n++; +#endif + xmlXPathNodeSetAdd(ret, cur); + } + } else { + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { +#ifdef DEBUG_STEP + n++; +#endif + xmlXPathNodeSetAdd(ret, cur); + } } break; case NODE_TEST_NS: { - TODO /* namespace search */ + TODO; break; } case NODE_TEST_NAME: @@ -2673,6 +2743,10 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis, } break; } + case XML_NAMESPACE_DECL: { + TODO; + break; + } default: break; } @@ -2720,6 +2794,7 @@ xmlXPathRoot(xmlXPathParserContextPtr ctxt) { * @ctxt: the XPath Parser context * * Implement the last() XPath function + * number last() * The last function returns the number of nodes in the context node list. */ void @@ -2913,6 +2988,10 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name)); break; + case XML_NAMESPACE_DECL: + valuePush(ctxt, xmlXPathNewString( + ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); + break; default: valuePush(ctxt, xmlXPathNewCString("")); } @@ -4572,6 +4651,7 @@ xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) { obj2 = valuePop(ctxt); obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval, obj2->nodesetval); + valuePush(ctxt, obj1); xmlXPathFreeObject(obj2); SKIP_BLANKS; } @@ -25,6 +25,7 @@ */ #include <stdio.h> +#include <string.h> #include <libxml/xpointer.h> #include <libxml/xmlmemory.h> #include <libxml/parserInternals.h> @@ -1711,8 +1712,13 @@ xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { if (node->content == NULL) { return(xmlXPtrNewRange(node, 0, node, 0)); } else { +#ifndef XML_USE_BUFFER_CONTENT return(xmlXPtrNewRange(node, 0, node, xmlStrlen(node->content))); +#else + return(xmlXPtrNewRange(node, 0, node, + xmlBufferLength(node->content))); +#endif } } case XML_ATTRIBUTE_NODE: @@ -1743,8 +1749,13 @@ xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { if (node->content == NULL) { return(xmlXPtrNewRange(node, 0, node, 0)); } else { +#ifndef XML_USE_BUFFER_CONTENT return(xmlXPtrNewRange(node, 0, node, xmlStrlen(node->content))); +#else + return(xmlXPtrNewRange(node, 0, node, + xmlBufferLength(node->content))); +#endif } } case XML_ATTRIBUTE_NODE: @@ -2010,7 +2021,11 @@ xmlXPtrAdvanceChar(xmlNodePtr *node, int *index, int bytes) { */ len = 0; if (cur->content != NULL) { +#ifndef XML_USE_BUFFER_CONTENT len = xmlStrlen(cur->content); +#else + len = xmlBufferLength(cur->content); +#endif } if (pos > len) { /* Strange, the index in the text node is greater than it's len */ @@ -2072,9 +2087,18 @@ xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex, if ((cur == *end) && (pos + stringlen > *endindex)) return(0); if (cur->content != NULL) { +#ifndef XML_USE_BUFFER_CONTENT len = xmlStrlen(cur->content); +#else + len = xmlBufferLength(cur->content); +#endif if (len >= pos + stringlen) { +#ifndef XML_USE_BUFFER_CONTENT match = (!xmlStrncmp(&cur->content[pos], string, stringlen)); +#else + len = (!xmlStrncmp(&xmlBufferContent(cur->content)[pos], + string, stringlen)); +#endif if (match) { #ifdef DEBUG_RANGES xmlGenericError(xmlGenericErrorContext, @@ -2091,7 +2115,12 @@ xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex, } } else { int sub = len - pos; +#ifndef XML_USE_BUFFER_CONTENT match = (!xmlStrncmp(&cur->content[pos], string, sub)); +#else + len = (!xmlStrncmp(&xmlBufferContent(cur->content)[pos], + string, sub)); +#endif if (match) { #ifdef DEBUG_RANGES xmlGenericError(xmlGenericErrorContext, @@ -2156,12 +2185,21 @@ xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex, while (cur != NULL) { if (cur->content != NULL) { +#ifndef XML_USE_BUFFER_CONTENT len = xmlStrlen(cur->content); +#else + len = xmlBufferLength(cur->content); +#endif while (pos <= len) { if (first != 0) { +#ifndef XML_USE_BUFFER_CONTENT str = xmlStrchr(&cur->content[pos], first); +#else + str = xmlStrchr(&xmlBufferContent(cur->content)[pos], + first); +#endif if (str != NULL) { - pos = (str - cur->content); + pos = (str - (xmlChar *)(cur->content)); #ifdef DEBUG_RANGES xmlGenericError(xmlGenericErrorContext, "found '%c' at index %d of ->", @@ -2244,7 +2282,11 @@ xmlXPtrGetLastChar(xmlNodePtr *node, int *index) { if (cur->last != NULL) cur = cur->last; else if (cur->content != NULL) { +#ifndef XML_USE_BUFFER_CONTENT len = xmlStrlen(cur->content); +#else + len = xmlBufferLength(cur->content); +#endif break; } } @@ -2459,7 +2501,7 @@ xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPtrNewRange(start, startindex, rend, rindex)); } - } else if (num <= 0) { + } else if ((number != NULL) && (num <= 0)) { xmlXPtrLocationSetAdd(newset, xmlXPtrNewRange(start, startindex, start, startindex)); |