aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--HTMLtree.c6
-rw-r--r--Makefile.am1
-rw-r--r--configure.in13
-rw-r--r--debugXML.c11
-rw-r--r--hash.c1
-rw-r--r--include/libxml/tree.h6
-rw-r--r--include/libxml/uri.h1
-rw-r--r--include/libxml/xinclude.h26
-rw-r--r--include/libxml/xmlversion.h.in9
-rw-r--r--testXPath.c1
-rw-r--r--tree.c218
-rw-r--r--tree.h6
-rw-r--r--uri.c353
-rw-r--r--uri.h1
-rw-r--r--valid.c3
-rw-r--r--xinclude.c737
-rw-r--r--xinclude.h26
-rw-r--r--xmllint.c24
-rw-r--r--xmlversion.h.in9
-rw-r--r--xpath.c150
-rw-r--r--xpointer.c46
22 files changed, 1453 insertions, 206 deletions
diff --git a/ChangeLog b/ChangeLog
index 44038b06..05507ac9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/HTMLtree.c b/HTMLtree.c
index 0a259c55..82687aca 100644
--- a/HTMLtree.c
+++ b/HTMLtree.c
@@ -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
diff --git a/debugXML.c b/debugXML.c
index 4a1ce5b4..9764885f 100644
--- a/debugXML.c
+++ b/debugXML.c
@@ -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;
}
diff --git a/hash.c b/hash.c
index a5c2770e..24e524c0 100644
--- a/hash.c
+++ b/hash.c
@@ -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>
diff --git a/tree.c b/tree.c
index ff7d7685..5fd26b5b 100644
--- a/tree.c
+++ b/tree.c
@@ -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;
diff --git a/tree.h b/tree.h
index 8c4f7088..2168d4fc 100644
--- a/tree.h
+++ b/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/uri.c b/uri.c
index a6d9f006..1ef6687a 100644
--- a/uri.c
+++ b/uri.c
@@ -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:
diff --git a/uri.h b/uri.h
index 705e3851..e7aeda41 100644
--- a/uri.h
+++ b/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/valid.c b/valid.c
index 8cbfd536..7e6e12ac 100644
--- a/valid.c
+++ b/valid.c
@@ -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__ */
diff --git a/xmllint.c b/xmllint.c
index 5ce88e17..e443a86f 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -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@
diff --git a/xpath.c b/xpath.c
index dbffba65..6b95b5a5 100644
--- a/xpath.c
+++ b/xpath.c
@@ -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;
}
diff --git a/xpointer.c b/xpointer.c
index aa4b8e07..08d00b92 100644
--- a/xpointer.c
+++ b/xpointer.c
@@ -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));