From 0eb38c7259b04de809f7bc880688f468ac7a15bf Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Sat, 14 Dec 2002 23:00:35 +0000 Subject: [PATCH] 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 --- ChangeLog | 10 +++ doc/libxml2-api.xml | 28 +++++++ include/libxml/xmlreader.h | 12 +++ parser.c | 9 ++- python/generator.py | 6 ++ python/libxml2class.txt | 30 +++++++ python/libxml_wrap.h | 29 +++++++ python/tests/Makefile.am | 3 +- python/tests/reader.py | 94 ++++++++++++++++++++++ python/types.c | 18 +++++ xmlreader.c | 160 ++++++++++++++++++++++++++++++++++++- 11 files changed, 394 insertions(+), 5 deletions(-) create mode 100755 python/tests/reader.py diff --git a/ChangeLog b/ChangeLog index 23be7c16..4d1f1b27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Sat Dec 14 23:57:39 CET 2002 Daniel Veillard + + * 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 * xinclude.c: fallback was only copying the first child not the diff --git a/doc/libxml2-api.xml b/doc/libxml2-api.xml index 0028b5c8..7909b8e7 100644 --- a/doc/libxml2-api.xml +++ b/doc/libxml2-api.xml @@ -1093,7 +1093,11 @@ + + + + @@ -7876,11 +7880,35 @@ actually an xmlCharEncoding'/> + + This method releases any resources allocated by the current instance changes the state to Closed and close any underlying input. + + + The depth of the node in the tree. + + Provides the value of the attribute with the specified qualified name. + + + + + + Provides the value of the attribute with the specified index relative to the containing element. + + + + + + Provides the value of the specified attribute + + + + + Whether the node has attributes. diff --git a/include/libxml/xmlreader.h b/include/libxml/xmlreader.h index 8e4b0578..15937a12 100644 --- a/include/libxml/xmlreader.h +++ b/include/libxml/xmlreader.h @@ -49,6 +49,18 @@ xmlChar * xmlTextReaderPrefix (xmlTextReaderPtr reader); 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 66908264..f68c4242 100644 --- a/parser.c +++ b/parser.c @@ -1769,7 +1769,8 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { 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 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { 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 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { 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 9c757133..b42630b9 100755 --- a/python/generator.py +++ b/python/generator.py @@ -271,6 +271,7 @@ py_types = { '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 @@ classes_type = { "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 @@ classes_destructors = { # "outputBuffer": "xmlOutputBufferClose", "inputBuffer": "xmlFreeParserInputBuffer", "xmlReg": "xmlRegFreeRegexp", + "xmlTextReader": "xmlFreeTextReader", } functions_noexcept = { @@ -676,6 +679,9 @@ def nameFixup(name, classe, type, file): 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 e15f5999..6127f7b3 100644 --- a/python/libxml2class.txt +++ b/python/libxml2class.txt @@ -165,6 +165,9 @@ registerDefaultInputCallbacks() registerDefaultOutputCallbacks() registerHTTPPostCallbacks() +# functions from module xmlreader +newTextReaderFilename() + # functions from module xmlregexp regexpCompile() @@ -556,6 +559,30 @@ Class xmlAttr(xmlNode) 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 @@ Class inputBuffer(ioReadWrapper) push() read() + # functions from module xmlreader + newTextReader() + Class outputBuffer(ioWriteWrapper) diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h index efa79d04..7a38f54c 100644 --- a/python/libxml_wrap.h +++ b/python/libxml_wrap.h @@ -17,6 +17,26 @@ #include #include #include +#include + +/** + * 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 +#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 @@ typedef struct { 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_xmlURIPtrWrap(xmlURIPtr uri); 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 96cb0333..c6bef2c5 100644 --- a/python/tests/Makefile.am +++ b/python/tests/Makefile.am @@ -19,7 +19,8 @@ PYTESTS= \ 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 00000000..1817fe92 --- /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("""content of c""") +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("""""") +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 3f490284..2c5a13ec 100644 --- a/python/types.c +++ b/python/types.c @@ -547,3 +547,21 @@ libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp) (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 65ca8e8a..0b6b13a9 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 { @@ -473,6 +474,163 @@ xmlFreeTextReader(xmlTextReaderPtr reader) { xmlFree(reader); } +/************************************************************************ + * * + * 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 *