summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Veillard <veillard@src.gnome.org>2002-02-04 14:07:26 +0000
committerDaniel Veillard <veillard@src.gnome.org>2002-02-04 14:07:26 +0000
commit33caa0b8307eccf22010400747830b1967edb292 (patch)
tree9e432644d38b1e00e23f8de3cadd7692dde22a6b
parent36eea2d2ee84132e66552f84724e9b377d687681 (diff)
downloadlibxml2-33caa0b8307eccf22010400747830b1967edb292.tar.gz
started adding SAX interfaces added a basic SAX test Daniel
* python/TODO python/libxml.c: started adding SAX interfaces * python/tests/Makefile.am python/tests/pushSAX.py: added a basic SAX test Daniel
-rw-r--r--ChangeLog6
-rw-r--r--python/TODO13
-rw-r--r--python/libxml.c495
-rw-r--r--python/tests/Makefile.am1
-rwxr-xr-xpython/tests/pushSAX.py64
5 files changed, 561 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index c9c4810d..1cedd8e0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Mon Feb 4 15:05:55 CET 2002 Daniel Veillard <daniel@veillard.com>
+
+ * python/TODO python/libxml.c: started adding SAX interfaces
+ * python/tests/Makefile.am python/tests/pushSAX.py: added a basic
+ SAX test
+
Mon Feb 4 01:12:42 CET 2002 Daniel Veillard <daniel@veillard.com>
* tree.c: hardened the addChild function
diff --git a/python/TODO b/python/TODO
index 24f94d1c..a19dfe4e 100644
--- a/python/TODO
+++ b/python/TODO
@@ -6,14 +6,18 @@ Things to do:
-------------
- SAX interfaces
+ - push is done but no generic interface
+ - elementDecl need some work
+ - need more testing and check full callbacks for xmllib/sgmlop replacement
- enums -> libxml.py
- access to XPath variables
- xmlBuffer exposure
- xpathContext, being able to set/get info and clean it up
- add regression tests
- - build tree
- - saving
- SAX flow
+- DTD element and attributes content accesses
+ - attribute handled in SAX
+ - element needed in both
Done:
@@ -28,6 +32,8 @@ Done:
- xpath queries
- xpath extension
- check memory
+ - build tree
+ - saving
- extensions based on a python.xml description of the new specific
interfaces
file libxml2-python-api.xml , first entry is xmlRegisterXPathFunction
@@ -42,5 +48,8 @@ Done:
- wrappers
- decent interface for setting/getting behaviour
- memory debug interfaces
+- SAX interfaces
+ - basic stuff with push is available
+ - basic xmllib replacement
Daniel Veillard
diff --git a/python/libxml.c b/python/libxml.c
index e167fcf6..6b4d4fe0 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -115,10 +115,475 @@ libxml_xmlDumpMemory(PyObject *self, PyObject *args) {
* *
************************************************************************/
-typedef struct pySAXhandler {
- PyObject *startDocument;
- /* TODO !!! */
-} pySAXhandler, *pySAXhandlerPtr;
+static void
+pythonStartElement(void *user_data, const xmlChar * name,
+ const xmlChar ** attrs)
+{
+ int i;
+ PyObject *handler;
+ PyObject *dict;
+ PyObject *attrname;
+ PyObject *attrvalue;
+ PyObject *result;
+ int type = 0;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "startElement"))
+ type = 1;
+ else if (PyObject_HasAttrString(handler, "start"))
+ type = 2;
+ if (type != 0) {
+ /*
+ * the xmllib interface always generate a dictionnary,
+ * possibly empty
+ */
+ if ((attrs == NULL) && (type == 1)) {
+ Py_XINCREF(Py_None);
+ dict = Py_None;
+ } else {
+ dict = PyDict_New();
+ for (i = 0; attrs[i] != NULL; i++) {
+ attrname = PyString_FromString(attrs[i]);
+ i++;
+ if (attrs[i] != NULL) {
+ attrvalue = PyString_FromString(attrs[i]);
+ } else {
+ Py_XINCREF(Py_None);
+ attrvalue = Py_None;
+ }
+ PyDict_SetItem(dict, attrname, attrvalue);
+ }
+ }
+
+ if (type == 1)
+ result = PyObject_CallMethod(handler, "startElement",
+ "sO", name, dict);
+ else if (type == 2)
+ result = PyObject_CallMethod(handler, "start",
+ "sO", name, dict);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(dict);
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonStartDocument(void *user_data)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "startDocument")) {
+ result = PyObject_CallMethod(handler, "startDocument", NULL);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonEndDocument(void *user_data)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "endDocument")) {
+ result = PyObject_CallMethod(handler, "endDocument", NULL);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+ /*
+ * The reference to the handler is released there
+ */
+ Py_XDECREF(handler);
+}
+
+static void
+pythonEndElement(void *user_data, const xmlChar * name)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "endElement")) {
+ result = PyObject_CallMethod(handler, "endElement", "s", name);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonReference(void *user_data, const xmlChar * name)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "reference")) {
+ result = PyObject_CallMethod(handler, "reference", "s", name);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonCharacters(void *user_data, const xmlChar * ch, int len)
+{
+ PyObject *handler;
+ PyObject *result;
+ int type = 0;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "characters"))
+ type = 1;
+ else if (PyObject_HasAttrString(handler, "data"))
+ type = 2;
+ if (type != 0) {
+ if (type == 1)
+ result = PyObject_CallMethod(handler, "characters", "s#", ch, len);
+ else if (type == 2)
+ result = PyObject_CallMethod(handler, "data", "s#", ch, len);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonIgnorableWhitespace(void *user_data, const xmlChar * ch, int len)
+{
+ PyObject *handler;
+ PyObject *result;
+ int type = 0;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "ignorableWhitespace"))
+ type = 1;
+ else if (PyObject_HasAttrString(handler, "data"))
+ type = 2;
+ if (type != 0) {
+ if (type == 1)
+ result =
+ PyObject_CallMethod(handler, "ignorableWhitespace", "s#",
+ ch, len);
+ else if (type == 2)
+ result = PyObject_CallMethod(handler, "data", "s#", ch, len);
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonProcessingInstruction(void *user_data,
+ const xmlChar * target, const xmlChar * data)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "processingInstruction")) {
+ result =
+ PyObject_CallMethod(handler,
+ "ignorableWhitespace", "ss", target, data);
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonComment(void *user_data, const xmlChar * value)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "comment")) {
+ result = PyObject_CallMethod(handler, "comment", "s", value);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonWarning(void *user_data, const char *msg, ...)
+{
+ PyObject *handler;
+ PyObject *result;
+ va_list args;
+ char buf[1024];
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "warning")) {
+ va_start(args, msg);
+ vsnprintf(buf, 1023, msg, args);
+ va_end(args);
+ buf[1023] = 0;
+ result = PyObject_CallMethod(handler, "warning", "s", buf);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonError(void *user_data, const char *msg, ...)
+{
+ PyObject *handler;
+ PyObject *result;
+ va_list args;
+ char buf[1024];
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "error")) {
+ va_start(args, msg);
+ vsnprintf(buf, 1023, msg, args);
+ va_end(args);
+ buf[1023] = 0;
+ result = PyObject_CallMethod(handler, "error", "s", buf);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonFatalError(void *user_data, const char *msg, ...)
+{
+ PyObject *handler;
+ PyObject *result;
+ va_list args;
+ char buf[1024];
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "fatalError")) {
+ va_start(args, msg);
+ vsnprintf(buf, 1023, msg, args);
+ va_end(args);
+ buf[1023] = 0;
+ result = PyObject_CallMethod(handler, "fatalError", "s", buf);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonCdataBlock(void *user_data, const xmlChar * ch, int len)
+{
+ PyObject *handler;
+ PyObject *result;
+ int type = 0;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "cdataBlock"))
+ type = 1;
+ else if (PyObject_HasAttrString(handler, "cdata"))
+ type = 2;
+ if (type != 0) {
+ if (type == 1)
+ result = PyObject_CallMethod(handler, "cdataBlock", "s#", ch, len);
+ else if (type == 2)
+ result = PyObject_CallMethod(handler, "cdata", "s#", ch, len);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonExternalSubset(void *user_data,
+ const xmlChar * name,
+ const xmlChar * externalID, const xmlChar * systemID)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "externalSubset")) {
+ result =
+ PyObject_CallMethod(handler, "externalSubset",
+ "sss", name, externalID, systemID);
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonEntityDecl(void *user_data,
+ const xmlChar * name,
+ int type,
+ const xmlChar * publicId,
+ const xmlChar * systemId, xmlChar * content)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "entityDecl")) {
+ result = PyObject_CallMethod(handler, "entityDecl",
+ "sisss", name, type, publicId,
+ systemId, content);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+
+
+static void
+
+pythonNotationDecl(void *user_data,
+ const xmlChar * name,
+ const xmlChar * publicId, const xmlChar * systemId)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "notationDecl")) {
+ result = PyObject_CallMethod(handler, "notationDecl",
+ "sss", name, publicId, systemId);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonAttributeDecl(void *user_data,
+ const xmlChar * elem,
+ const xmlChar * name,
+ int type,
+ int def,
+ const xmlChar * defaultValue,
+ xmlEnumerationPtr tree)
+{
+ PyObject *handler;
+ PyObject *nameList;
+ PyObject *newName;
+ xmlEnumerationPtr node;
+ PyObject *result;
+ int count;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "attributeDecl")) {
+ count = 0;
+ for (node = tree; node != NULL; node = node->next) {
+ count++;
+ }
+ nameList = PyList_New(count);
+ count = 0;
+ for (node = tree; node != NULL; node = node->next) {
+ newName = PyString_FromString(node->name);
+ PyList_SetItem(nameList, count, newName);
+ count++;
+ }
+ result = PyObject_CallMethod(handler, "attributeDecl",
+ "ssiisO", elem, name, type, def,
+ defaultValue, nameList);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(nameList);
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonElementDecl(void *user_data,
+ const xmlChar * name,
+ int type, xmlElementContentPtr content)
+{
+ PyObject *handler;
+ PyObject *obj;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "elementDecl")) {
+ /* TODO: wrap in an elementContent object */
+ printf("pythonElementDecl: xmlElementContentPtr wrapper missing !\n");
+ obj = Py_None;
+ /* Py_XINCREF(Py_None); isn't the reference just borrowed ??? */
+ result = PyObject_CallMethod(handler, "elementDecl",
+ "siO", name, type, obj);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonUnparsedEntityDecl(void *user_data,
+ const xmlChar * name,
+ const xmlChar * publicId,
+ const xmlChar * systemId,
+ const xmlChar * notationName)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "unparsedEntityDecl")) {
+ result = PyObject_CallMethod(handler, "unparsedEntityDecl",
+ "ssss", name, publicId, systemId,
+ notationName);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static void
+pythonInternalSubset(void *user_data, const xmlChar * name,
+ const xmlChar * ExternalID, const xmlChar * SystemID)
+{
+ PyObject *handler;
+ PyObject *result;
+
+ handler = (PyObject *) user_data;
+ if (PyObject_HasAttrString(handler, "internalSubset")) {
+ result = PyObject_CallMethod(handler, "internalSubset",
+ "sss", name, ExternalID, SystemID);
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_XDECREF(result);
+ }
+}
+
+static xmlSAXHandler pythonSaxHandler = {
+ pythonInternalSubset,
+ NULL, /* TODO pythonIsStandalone, */
+ NULL, /* TODO pythonHasInternalSubset, */
+ NULL, /* TODO pythonHasExternalSubset, */
+ NULL, /* TODO pythonResolveEntity, */
+ NULL, /* TODO pythonGetEntity, */
+ pythonEntityDecl,
+ pythonNotationDecl,
+ pythonAttributeDecl,
+ pythonElementDecl,
+ pythonUnparsedEntityDecl,
+ NULL, /* OBSOLETED pythonSetDocumentLocator, */
+ pythonStartDocument,
+ pythonEndDocument,
+ pythonStartElement,
+ pythonEndElement,
+ pythonReference,
+ pythonCharacters,
+ pythonIgnorableWhitespace,
+ pythonProcessingInstruction,
+ pythonComment,
+ pythonWarning,
+ pythonError,
+ pythonFatalError,
+ NULL, /* TODO pythonGetParameterEntity, */
+ pythonCdataBlock,
+ pythonExternalSubset,
+ 1
+};
/************************************************************************
* *
@@ -131,9 +596,8 @@ libxml_xmlCreatePushParser(PyObject *self, PyObject *args) {
xmlChar *chunk;
int size;
xmlChar *URI;
- PyObject *pyobj_SAX;
+ PyObject *pyobj_SAX = NULL;
xmlSAXHandlerPtr SAX = NULL;
- pySAXhandlerPtr SAXdata = NULL;
xmlParserCtxtPtr ret;
PyObject *pyret;
@@ -146,11 +610,11 @@ libxml_xmlCreatePushParser(PyObject *self, PyObject *args) {
pyobj_SAX, chunk, size, URI);
#endif
if (pyobj_SAX != Py_None) {
- printf("xmlCreatePushParser: event interface not supported yet !\n");
- Py_INCREF(Py_None);
- return(Py_None);
+ SAX = &pythonSaxHandler;
+ Py_INCREF(pyobj_SAX);
+ /* The reference is released in pythonEndDocument() */
}
- ret = xmlCreatePushParserCtxt(SAX, SAXdata, chunk, size, URI);
+ ret = xmlCreatePushParserCtxt(SAX, pyobj_SAX, chunk, size, URI);
pyret = libxml_xmlParserCtxtPtrWrap(ret);
return(pyret);
}
@@ -160,9 +624,8 @@ libxml_htmlCreatePushParser(PyObject *self, PyObject *args) {
xmlChar *chunk;
int size;
xmlChar *URI;
- PyObject *pyobj_SAX;
+ PyObject *pyobj_SAX = NULL;
xmlSAXHandlerPtr SAX = NULL;
- pySAXhandlerPtr SAXdata = NULL;
xmlParserCtxtPtr ret;
PyObject *pyret;
@@ -175,11 +638,11 @@ libxml_htmlCreatePushParser(PyObject *self, PyObject *args) {
pyobj_SAX, chunk, size, URI);
#endif
if (pyobj_SAX != Py_None) {
- printf("htmlCreatePushParser: event interface not supported yet !\n");
- Py_INCREF(Py_None);
- return(Py_None);
+ SAX = &pythonSaxHandler;
+ Py_INCREF(pyobj_SAX);
+ /* The reference is released in pythonEndDocument() */
}
- ret = htmlCreatePushParserCtxt(SAX, SAXdata, chunk, size, URI,
+ ret = htmlCreatePushParserCtxt(SAX, pyobj_SAX, chunk, size, URI,
XML_CHAR_ENCODING_NONE);
pyret = libxml_xmlParserCtxtPtrWrap(ret);
return(pyret);
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
index e468e6c7..c73f0c67 100644
--- a/python/tests/Makefile.am
+++ b/python/tests/Makefile.am
@@ -6,6 +6,7 @@ TESTS= \
tstxpath.py \
xpathext.py \
push.py \
+ pushSAX.py \
error.py \
validate.py \
xpath.py
diff --git a/python/tests/pushSAX.py b/python/tests/pushSAX.py
new file mode 100755
index 00000000..1c1e7866
--- /dev/null
+++ b/python/tests/pushSAX.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python -u
+import sys
+import libxml2
+
+# Memory debug specific
+libxml2.debugMemory(1)
+
+log = ""
+
+class callback:
+ def startDocument(self):
+ global log
+ log = log + "startDocument:"
+
+ def endDocument(self):
+ global log
+ log = log + "endDocument:"
+
+ def startElement(self, tag, attrs):
+ global log
+ log = log + "startElement %s %s:" % (tag, attrs)
+
+ def endElement(self, tag):
+ global log
+ log = log + "endElement %s:" % (tag)
+
+ def characters(self, data):
+ global log
+ log = log + "characters: %s:" % (data)
+
+ def warning(self, msg):
+ global log
+ log = log + "warning: %s:" % (msg)
+
+ def error(self, msg):
+ global log
+ log = log + "error: %s:" % (msg)
+
+ def fatalError(self, msg):
+ global log
+ log = log + "fatalError: %s:" % (msg)
+
+handler = callback()
+
+ctxt = libxml2.createPushParser(handler, "<foo", 4, "test.xml")
+chunk = " url='tst'>b"
+ctxt.parseChunk(chunk, len(chunk), 0)
+chunk = "ar</foo>"
+ctxt.parseChunk(chunk, len(chunk), 1)
+ctxt=None
+
+reference = "startDocument:startElement foo {'url': 'tst'}:characters: bar:endElement foo:endDocument:"
+if log != reference:
+ print "Error got: %s" % log
+ print "Exprected: %s" % reference
+ sys.exit(1)
+
+# Memory debug specific
+libxml2.cleanupParser()
+if libxml2.debugMemory(1) == 0:
+ print "OK"
+else:
+ print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+ libxml2.dumpMemory()