added the close and getattribute methods of XmlTextReader. added the
* xmlreader.c doc/libxml2-api.xml: added the close and getattribute
methods of XmlTextReader.
* python/generator.py python/libxml_wrap.h python/types.c
python/libxml2class.txt: added the reader to the Python bindings
* python/tests/Makefile.am python/tests/reader.py: added a specific
test for the Python bindings of the Reader APIs
* parser.c: small cleanup.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 23be7c1..4d1f1b2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Sat Dec 14 23:57:39 CET 2002 Daniel Veillard <daniel@veillard.com>
+
+ * xmlreader.c doc/libxml2-api.xml: added the close and getattribute
+ methods of XmlTextReader.
+ * python/generator.py python/libxml_wrap.h python/types.c
+ python/libxml2class.txt: added the reader to the Python bindings
+ * python/tests/Makefile.am python/tests/reader.py: added a specific
+ test for the Python bindings of the Reader APIs
+ * parser.c: small cleanup.
+
Fri Dec 13 11:39:44 CET 2002 Daniel Veillard <daniel@veillard.com>
* xinclude.c: fallback was only copying the first child not the
diff --git a/doc/libxml2-api.xml b/doc/libxml2-api.xml
index 0028b5c..7909b8e 100644
--- a/doc/libxml2-api.xml
+++ b/doc/libxml2-api.xml
@@ -1093,7 +1093,11 @@
<exports symbol='xmlTextReader'/>
<exports symbol='xmlTextReaderAttributeCount'/>
<exports symbol='xmlTextReaderBaseUri'/>
+ <exports symbol='xmlTextReaderClose'/>
<exports symbol='xmlTextReaderDepth'/>
+ <exports symbol='xmlTextReaderGetAttribute'/>
+ <exports symbol='xmlTextReaderGetAttributeNo'/>
+ <exports symbol='xmlTextReaderGetAttributeNs'/>
<exports symbol='xmlTextReaderHasAttributes'/>
<exports symbol='xmlTextReaderHasValue'/>
<exports symbol='xmlTextReaderIsDefault'/>
@@ -7876,11 +7880,35 @@
<return type='xmlChar *' info='the base URI or NULL if not available'/>
<arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
</function>
+ <function name='xmlTextReaderClose' file='xmlreader'>
+ <info>This method releases any resources allocated by the current instance changes the state to Closed and close any underlying input.</info>
+ <return type='int' info='0 or -1 in case of error'/>
+ <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
+ </function>
<function name='xmlTextReaderDepth' file='xmlreader'>
<info>The depth of the node in the tree.</info>
<return type='int' info='the depth or -1 in case of error'/>
<arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
</function>
+ <function name='xmlTextReaderGetAttribute' file='xmlreader'>
+ <info>Provides the value of the attribute with the specified qualified name.</info>
+ <return type='xmlChar *' info='a string containing the value of the specified attribute, or NULL in case of error. The string must be deallocated by the caller.'/>
+ <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
+ <arg name='name' type='const xmlChar *' info='the qualified name of the attribute.'/>
+ </function>
+ <function name='xmlTextReaderGetAttributeNo' file='xmlreader'>
+ <info>Provides the value of the attribute with the specified index relative to the containing element.</info>
+ <return type='xmlChar *' info='a string containing the value of the specified attribute, or NULL in case of error. The string must be deallocated by the caller.'/>
+ <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
+ <arg name='no' type='int' info='the zero-based index of the attribute relative to the containing element'/>
+ </function>
+ <function name='xmlTextReaderGetAttributeNs' file='xmlreader'>
+ <info>Provides the value of the specified attribute</info>
+ <return type='xmlChar *' info='a string containing the value of the specified attribute, or NULL in case of error. The string must be deallocated by the caller.'/>
+ <arg name='reader' type='xmlTextReaderPtr' info='the xmlTextReaderPtr used'/>
+ <arg name='localName' type='const xmlChar *' info='the local name of the attribute.'/>
+ <arg name='namespaceURI' type='const xmlChar *' info='the namespace URI of the attribute.'/>
+ </function>
<function name='xmlTextReaderHasAttributes' file='xmlreader'>
<info>Whether the node has attributes.</info>
<return type='int' info='1 if true, 0 if false, and -1 in case or error'/>
diff --git a/include/libxml/xmlreader.h b/include/libxml/xmlreader.h
index 8e4b057..15937a1 100644
--- a/include/libxml/xmlreader.h
+++ b/include/libxml/xmlreader.h
@@ -49,6 +49,18 @@
int xmlTextReaderQuoteChar (xmlTextReaderPtr reader);
xmlChar * xmlTextReaderValue (xmlTextReaderPtr reader);
xmlChar * xmlTextReaderXmlLang (xmlTextReaderPtr reader);
+
+/*
+ * Methods of the XmlTextReader
+ */
+int xmlTextReaderClose (xmlTextReaderPtr reader);
+xmlChar * xmlTextReaderGetAttributeNo (xmlTextReaderPtr reader,
+ int no);
+xmlChar * xmlTextReaderGetAttribute (xmlTextReaderPtr reader,
+ const xmlChar *name);
+xmlChar * xmlTextReaderGetAttributeNs (xmlTextReaderPtr reader,
+ const xmlChar *localName,
+ const xmlChar *namespaceURI);
#ifdef __cplusplus
}
#endif
diff --git a/parser.c b/parser.c
index 6690826..f68c424 100644
--- a/parser.c
+++ b/parser.c
@@ -1769,7 +1769,8 @@
int first = CUR_SCHAR(cur, l);
if (!IS_LETTER(first) && (first != '_')) {
- if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ if ((ctxt != NULL) && (ctxt->sax != NULL) &&
+ (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"Name %s is not XML Namespace compliant\n",
name);
@@ -1790,7 +1791,8 @@
buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
if (buffer == NULL) {
- if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ if ((ctxt != NULL) && (ctxt->sax != NULL) &&
+ (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"xmlSplitQName: out of memory\n");
return(NULL);
@@ -1802,7 +1804,8 @@
buffer = (xmlChar *) xmlRealloc(buffer,
max * sizeof(xmlChar));
if (buffer == NULL) {
- if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ if ((ctxt != NULL) && (ctxt->sax != NULL) &&
+ (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"xmlSplitQName: out of memory\n");
return(NULL);
diff --git a/python/generator.py b/python/generator.py
index 9c75713..b42630b 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -271,6 +271,7 @@
'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"),
'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"),
'xmlRegexpPtr': ('O', "xmlReg", "xmlRegexpPtr", "xmlRegexpPtr"),
+ 'xmlTextReaderPtr': ('O', "xmlTextReader", "xmlTextReaderPtr", "xmlTextReaderPtr"),
}
py_return_types = {
@@ -597,6 +598,7 @@
"xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"),
"xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"),
"xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"),
+ "xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"),
}
converter_type = {
@@ -624,6 +626,7 @@
# "outputBuffer": "xmlOutputBufferClose",
"inputBuffer": "xmlFreeParserInputBuffer",
"xmlReg": "xmlRegFreeRegexp",
+ "xmlTextReader": "xmlFreeTextReader",
}
functions_noexcept = {
@@ -676,6 +679,9 @@
func = "regexp" + name[9:]
elif name[0:6] == "xmlReg" and file == "xmlregexp":
func = "regexp" + name[6:]
+ elif name[0:13] == "xmlTextReader" and file == "xmlreader":
+ func = name[13:]
+ func = string.lower(func[0:1]) + func[1:]
elif name[0:11] == "xmlACatalog":
func = name[11:]
func = string.lower(func[0:1]) + func[1:]
diff --git a/python/libxml2class.txt b/python/libxml2class.txt
index e15f599..6127f7b 100644
--- a/python/libxml2class.txt
+++ b/python/libxml2class.txt
@@ -165,6 +165,9 @@
registerDefaultOutputCallbacks()
registerHTTPPostCallbacks()
+# functions from module xmlreader
+newTextReaderFilename()
+
# functions from module xmlregexp
regexpCompile()
@@ -556,6 +559,30 @@
freeProp()
freePropList()
removeProp()
+Class xmlTextReader()
+
+ # functions from module xmlreader
+ attributeCount()
+ baseUri()
+ close()
+ depth()
+ freeTextReader()
+ getAttribute()
+ getAttributeNo()
+ getAttributeNs()
+ hasAttributes()
+ hasValue()
+ isDefault()
+ isEmptyElement()
+ localName()
+ name()
+ namespaceUri()
+ nodeType()
+ prefix()
+ quoteChar()
+ read()
+ value()
+ xmlLang()
Class xmlReg()
# functions from module xmlregexp
@@ -731,6 +758,9 @@
push()
read()
+ # functions from module xmlreader
+ newTextReader()
+
Class outputBuffer(ioWriteWrapper)
diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h
index efa79d0..7a38f54 100644
--- a/python/libxml_wrap.h
+++ b/python/libxml_wrap.h
@@ -17,6 +17,26 @@
#include <libxml/xmlunicode.h>
#include <libxml/xmlregexp.h>
#include <libxml/xmlautomata.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * ATTRIBUTE_UNUSED:
+ *
+ * Macro used to signal to GCC unused function parameters
+ * Repeated here since the definition is not available when
+ * compiled outside the libxml2 build tree.
+ */
+#ifdef __GNUC__
+#ifdef ATTRIBUTE_UNUSED
+#undef ATTRIBUTE_UNUSED
+#endif
+#include <ansidecl.h>
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED
+#endif
+#else
+#define ATTRIBUTE_UNUSED
+#endif
#define PyxmlNode_Get(v) (((v) == Py_None) ? NULL : \
(((PyxmlNode_Object *)(v))->obj))
@@ -66,6 +86,14 @@
xmlRegexpPtr obj;
} PyxmlReg_Object;
+#define PyxmlTextReader_Get(v) (((v) == Py_None) ? NULL : \
+ (((PyxmlTextReader_Object *)(v))->obj))
+
+typedef struct {
+ PyObject_HEAD
+ xmlTextReaderPtr obj;
+} PyxmlTextReader_Object;
+
#define PyURI_Get(v) (((v) == Py_None) ? NULL : \
(((PyURI_Object *)(v))->obj))
@@ -119,5 +147,6 @@
PyObject * libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer);
PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer);
PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp);
+PyObject * libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader);
xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj);
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
index 96cb033..c6bef2c 100644
--- a/python/tests/Makefile.am
+++ b/python/tests/Makefile.am
@@ -19,7 +19,8 @@
outbuf.py \
inbuf.py \
resolver.py \
- regexp.py
+ regexp.py \
+ reader.py
XMLS= \
tst.xml \
diff --git a/python/tests/reader.py b/python/tests/reader.py
new file mode 100755
index 0000000..1817fe9
--- /dev/null
+++ b/python/tests/reader.py
@@ -0,0 +1,94 @@
+#!/usr/bin/python -u
+import libxml2
+import StringIO
+import sys
+
+# Memory debug specific
+libxml2.debugMemory(1)
+
+f = StringIO.StringIO("""<a><b b1="b1"/><c>content of c</c></a>""")
+input = libxml2.inputBuffer(f)
+reader = input.newTextReader()
+ret = reader.read()
+if ret != 1:
+ print "Error reading to first element"
+ sys.exit(1)
+if reader.name() != "a" or reader.isEmptyElement() != 0 or \
+ reader.nodeType() != 1 or reader.hasAttributes() != 0:
+ print "Error reading the first element"
+ sys.exit(1)
+ret = reader.read()
+if ret != 1:
+ print "Error reading to second element"
+ sys.exit(1)
+if reader.name() != "b" or reader.isEmptyElement() != 1 or \
+ reader.nodeType() != 1 or reader.hasAttributes() != 1:
+ print "Error reading the second element"
+ sys.exit(1)
+ret = reader.read()
+if ret != 1:
+ print "Error reading to third element"
+ sys.exit(1)
+if reader.name() != "c" or reader.isEmptyElement() != 0 or \
+ reader.nodeType() != 1 or reader.hasAttributes() != 0:
+ print "Error reading the third element"
+ sys.exit(1)
+ret = reader.read()
+if ret != 1:
+ print "Error reading to text node"
+ sys.exit(1)
+if reader.name() != "#text" or reader.isEmptyElement() != 0 or \
+ reader.nodeType() != 3 or reader.hasAttributes() != 0 or \
+ reader.value() != "content of c":
+ print "Error reading the text node"
+ sys.exit(1)
+ret = reader.read()
+if ret != 1:
+ print "Error reading to end of third element"
+ sys.exit(1)
+if reader.name() != "c" or reader.isEmptyElement() != 0 or \
+ reader.nodeType() != 15 or reader.hasAttributes() != 0:
+ print "Error reading the end of third element"
+ sys.exit(1)
+ret = reader.read()
+if ret != 1:
+ print "Error reading to end of first element"
+ sys.exit(1)
+if reader.name() != "a" or reader.isEmptyElement() != 0 or \
+ reader.nodeType() != 15 or reader.hasAttributes() != 0:
+ print "Error reading the end of first element"
+ sys.exit(1)
+ret = reader.read()
+if ret != 0:
+ print "Error reading to end of document"
+ sys.exit(1)
+
+#
+# example from the XmlTextReader docs
+#
+f = StringIO.StringIO("""<test xmlns:dt="urn:datatypes" dt:type="int"/>""")
+input = libxml2.inputBuffer(f)
+reader = input.newTextReader()
+
+ret = reader.read()
+if ret != 1:
+ print "Error reading test element"
+ sys.exit(1)
+if reader.getAttributeNo(0) != "urn:datatypes" or \
+ reader.getAttributeNo(1) != "int" or \
+ reader.getAttributeNs("type", "urn:datatypes") != "int" or \
+ reader.getAttribute("dt:type") != "int":
+ print "error reading test attributes"
+ sys.exit(1)
+
+del f
+del input
+del reader
+
+# Memory debug specific
+libxml2.cleanupParser()
+if libxml2.debugMemory(1) == 0:
+ print "OK"
+else:
+ print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+ libxml2.dumpMemory()
diff --git a/python/types.c b/python/types.c
index 3f49028..2c5a13e 100644
--- a/python/types.c
+++ b/python/types.c
@@ -547,3 +547,21 @@
(char *) "xmlRegexpPtr", NULL);
return (ret);
}
+
+PyObject *
+libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader)
+{
+ PyObject *ret;
+
+#ifdef DEBUG
+ printf("libxml_xmlTextReaderPtrWrap: reader = %p\n", reader);
+#endif
+ if (reader == NULL) {
+ Py_INCREF(Py_None);
+ return (Py_None);
+ }
+ ret =
+ PyCObject_FromVoidPtrAndDesc((void *) reader,
+ (char *) "xmlTextReaderPtr", NULL);
+ return (ret);
+}
diff --git a/xmlreader.c b/xmlreader.c
index 65ca8e8..0b6b13a 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -53,7 +53,8 @@
typedef enum {
XML_TEXTREADER_MODE_NORMAL = 0,
- XML_TEXTREADER_MODE_EOF = 1
+ XML_TEXTREADER_MODE_EOF = 1,
+ XML_TEXTREADER_MODE_CLOSED = 1
} xmlTextReaderMode;
typedef enum {
@@ -475,6 +476,163 @@
/************************************************************************
* *
+ * Methods for XmlTextReader *
+ * *
+ ************************************************************************/
+/**
+ * xmlTextReaderClose:
+ * @reader: the xmlTextReaderPtr used
+ *
+ * This method releases any resources allocated by the current instance
+ * changes the state to Closed and close any underlying input.
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlTextReaderClose(xmlTextReaderPtr reader) {
+ if (reader == NULL)
+ return(-1);
+ reader->node = NULL;
+ reader->mode = XML_TEXTREADER_MODE_CLOSED;
+ if (reader->ctxt != NULL) {
+ if (reader->ctxt->myDoc != NULL) {
+ xmlFreeDoc(reader->ctxt->myDoc);
+ reader->ctxt->myDoc = NULL;
+ }
+ if (reader->allocs & XML_TEXTREADER_CTXT) {
+ xmlFreeParserCtxt(reader->ctxt);
+ reader->allocs -= XML_TEXTREADER_CTXT;
+ }
+ }
+ if (reader->sax != NULL) {
+ xmlFree(reader->sax);
+ reader->sax = NULL;
+ }
+ if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
+ xmlFreeParserInputBuffer(reader->input);
+ reader->allocs -= XML_TEXTREADER_INPUT;
+ }
+ return(0);
+}
+
+/**
+ * xmlTextReaderGetAttributeNo:
+ * @reader: the xmlTextReaderPtr used
+ * @no: the zero-based index of the attribute relative to the containing element
+ *
+ * Provides the value of the attribute with the specified index relative
+ * to the containing element.
+ *
+ * Returns a string containing the value of the specified attribute, or NULL
+ * in case of error. The string must be deallocated by the caller.
+ */
+xmlChar *
+xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
+ xmlChar *ret;
+ int i;
+ xmlAttrPtr cur;
+ xmlNsPtr ns;
+
+ if (reader == NULL)
+ return(NULL);
+ if (reader->node == NULL)
+ return(NULL);
+ /* TODO: handle the xmlDecl */
+ if (reader->node->type != XML_ELEMENT_NODE)
+ return(NULL);
+
+ ns = reader->node->nsDef;
+ for (i = 0;(i < no) && (ns != NULL);i++) {
+ ns = ns->next;
+ }
+ if (ns != NULL)
+ return(xmlStrdup(ns->href));
+
+ cur = reader->node->properties;
+ if (cur == NULL)
+ return(NULL);
+ for (;i < no;i++) {
+ cur = cur->next;
+ if (cur == NULL)
+ return(NULL);
+ }
+ /* TODO walk the DTD if present */
+
+ ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
+ if (ret == NULL) return(xmlStrdup((xmlChar *)""));
+ return(ret);
+}
+
+/**
+ * xmlTextReaderGetAttribute:
+ * @reader: the xmlTextReaderPtr used
+ * @name: the qualified name of the attribute.
+ *
+ * Provides the value of the attribute with the specified qualified name.
+ *
+ * Returns a string containing the value of the specified attribute, or NULL
+ * in case of error. The string must be deallocated by the caller.
+ */
+xmlChar *
+xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
+ xmlChar *prefix = NULL;
+ xmlChar *localname;
+ xmlNsPtr ns;
+ xmlChar *ret = NULL;
+
+ if ((reader == NULL) || (name == NULL))
+ return(NULL);
+ if (reader->node == NULL)
+ return(NULL);
+
+ /* TODO: handle the xmlDecl */
+ if (reader->node->type != XML_ELEMENT_NODE)
+ return(NULL);
+
+ localname = xmlSplitQName2(name, &prefix);
+ if (localname == NULL)
+ return(xmlGetProp(reader->node, name));
+
+ ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
+ if (ns != NULL)
+ ret = xmlGetNsProp(reader->node, localname, ns->href);
+
+ if (localname != NULL)
+ xmlFree(localname);
+ if (prefix != NULL)
+ xmlFree(prefix);
+ return(ret);
+}
+
+
+/**
+ * xmlTextReaderGetAttributeNs:
+ * @reader: the xmlTextReaderPtr used
+ * @localName: the local name of the attribute.
+ * @namespaceURI: the namespace URI of the attribute.
+ *
+ * Provides the value of the specified attribute
+ *
+ * Returns a string containing the value of the specified attribute, or NULL
+ * in case of error. The string must be deallocated by the caller.
+ */
+xmlChar *
+xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
+ const xmlChar *namespaceURI) {
+ if ((reader == NULL) || (localName == NULL))
+ return(NULL);
+ if (reader->node == NULL)
+ return(NULL);
+
+ /* TODO: handle the xmlDecl */
+ if (reader->node->type != XML_ELEMENT_NODE)
+ return(NULL);
+
+ return(xmlGetNsProp(reader->node, localName, namespaceURI));
+}
+
+/************************************************************************
+ * *
* Acces API to the current node *
* *
************************************************************************/