diff options
author | Jacek Konieczny <jajcus@jajcus.net> | 2003-06-06 12:40:52 +0400 |
---|---|---|
committer | Jacek Konieczny <jajcus@jajcus.net> | 2003-06-06 12:40:52 +0400 |
commit | 91bb36727648e0da04c7052fee4eacae9ab6ca49 (patch) | |
tree | ce1c2a5a82a970645a45f6c794561f105c1f7413 /ext | |
parent | 94d924aed12c054f5f48edecec2285e46051642e (diff) |
- no more ugly libxml2 hacks
Diffstat (limited to 'ext')
-rw-r--r-- | ext/Copyright-libxml2 | 30 | ||||
-rw-r--r-- | ext/xmlextra.c | 446 |
2 files changed, 476 insertions, 0 deletions
diff --git a/ext/Copyright-libxml2 b/ext/Copyright-libxml2 new file mode 100644 index 0000000..0fea134 --- /dev/null +++ b/ext/Copyright-libxml2 @@ -0,0 +1,30 @@ +Below is the original copyright notice from libxml2. Files in this directory +are highly-modified parts of libxml2 library and its python bindings. + + +Except where otherwise noted in the source code (trio files, hash.c and list.c) +covered by a similar licence but with different Copyright notices: + + Copyright (C) 1998-2002 Daniel Veillard. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Daniel Veillard shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from him. + diff --git a/ext/xmlextra.c b/ext/xmlextra.c new file mode 100644 index 0000000..1e0b5eb --- /dev/null +++ b/ext/xmlextra.c @@ -0,0 +1,446 @@ +#include <Python.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/SAX.h> +#include <libxml/xmlerror.h> + +static PyObject *MyError; + +/* + * Code borrowed from libxml2 python bindings + * Copyright (C) 1998-2002 Daniel Veillard. All Rights Reserved. + * (see Copyright-libxml2 for copyright details) + */ + +#define PyxmlNode_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlNode_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlNodePtr obj; +} PyxmlNode_Object; + +PyObject * libxml_xmlDocPtrWrap(xmlDocPtr doc) { + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlDocPtrWrap: doc = %p\n", doc); +#endif + if (doc == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + /* TODO: look at deallocation */ + ret = + PyCObject_FromVoidPtrAndDesc((void *) doc, (char *) "xmlDocPtr", + NULL); + return (ret); +} + +PyObject * libxml_xmlNodePtrWrap(xmlNodePtr node) { + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlNodePtrWrap: node = %p\n", node); +#endif + if (node == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) node, (char *) "xmlNodePtr", + NULL); + return (ret); +} + +/* + * End of code borrowed from libxml2 + */ + +/* Tree manipulation functions */ + +static PyObject * remove_ns(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) { +PyObject *pyobj_tree,*pyobj_ns; +xmlNsPtr nsDef,prev; +xmlNodePtr node; +xmlNodePtr declNode = NULL; +xmlAttrPtr attr; +xmlNodePtr tree; +xmlNsPtr ns; + + if (!PyArg_ParseTuple(args, "OO", &pyobj_tree,&pyobj_ns)) return NULL; + tree = (xmlNodePtr) PyxmlNode_Get(pyobj_tree); + ns = (xmlNsPtr) PyxmlNode_Get(pyobj_ns); + node = tree; + + if (ns == NULL) { + PyErr_SetString(MyError,"remove_ns: NULL namespace"); + return NULL; + } + + while (node != NULL) { + /* + * Check if the namespace is in use by the node + */ + if (node->ns == ns) { + PyErr_SetString(MyError,"remove_ns: NULL namespace"); + return NULL; + } + + /* + * now check for namespace hold by attributes on the node. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == ns) { + PyErr_SetString(MyError,"remove_ns: NULL namespace"); + return NULL; + } + attr = attr->next; + } + + /* + * Check if the namespace is declared in the node + */ + nsDef=node->nsDef; + while(nsDef != NULL) { + if (nsDef == ns) { + declNode = node; + break; + } + nsDef=nsDef->next; + } + + /* + * Browse the full subtree, deep first + */ + if (node->children != NULL) { + /* deep first */ + node = node->children; + } else if ((node != tree) && (node->next != NULL)) { + /* then siblings */ + node = node->next; + } else if (node != tree) { + /* go up to parents->next if needed */ + while (node != tree) { + if (node->parent != NULL) + node = node->parent; + if ((node != tree) && (node->next != NULL)) { + node = node->next; + break; + } + if (node->parent == NULL) { + node = NULL; + break; + } + } + /* exit condition */ + if (node == tree) node = NULL; + } else break; + } + + /* there is no such namespace declared here */ + if (declNode == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + + prev=NULL; + nsDef=declNode->nsDef; + while(nsDef != NULL) { + if (nsDef == ns) { + if (prev == NULL) declNode->nsDef=nsDef->next; + else prev->next=nsDef->next; + xmlFreeNs(ns); + break; + } + prev=nsDef; + nsDef=nsDef->next; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * replace_ns(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) { +PyObject *pyobj_tree,*pyobj_old_ns,*pyobj_new_ns; +xmlNodePtr tree,node; +xmlAttrPtr attr; +xmlNsPtr new_ns,old_ns; + + if (!PyArg_ParseTuple(args, "OOO", &pyobj_tree,&pyobj_old_ns,&pyobj_new_ns)) return NULL; + tree = (xmlNodePtr) PyxmlNode_Get(pyobj_tree); + old_ns = (xmlNsPtr) PyxmlNode_Get(pyobj_old_ns); + new_ns = (xmlNsPtr) PyxmlNode_Get(pyobj_new_ns); + node = tree; + + while (node != NULL) { + /* + * Check if the namespace is in use by the node + */ + if (node->ns == old_ns) { + node->ns = new_ns; + } + + /* + * now check for namespace hold by attributes on the node. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == old_ns) { + node->ns = new_ns; + } + attr = attr->next; + } + + /* + * Browse the full subtree, deep first + */ + if (node->children != NULL) { + /* deep first */ + node = node->children; + } else if ((node != tree) && (node->next != NULL)) { + /* then siblings */ + node = node->next; + } else if (node != tree) { + /* go up to parents->next if needed */ + while (node != tree) { + if (node->parent != NULL) node = node->parent; + if ((node != tree) && (node->next != NULL)) { + node = node->next; + break; + } + if (node->parent == NULL) { + node = NULL; + break; + } + } + /* exit condition */ + if (node == tree) node = NULL; + } else break; + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* Stream reader functions */ + +staticforward PyTypeObject ReaderType; + +typedef struct _reader{ + PyObject_HEAD + + xmlParserCtxtPtr ctxt; + xmlSAXHandler sax; + + startElementSAXFunc startElement; + endElementSAXFunc endElement; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; + + PyObject *handler; + + int eof; + int exception; +}ReaderObject; + +void myStartElement(void *ctx,const xmlChar *name,const xmlChar **atts){ +xmlParserCtxtPtr ctxt=(xmlParserCtxtPtr) ctx; +ReaderObject *reader=(ReaderObject *)ctxt->_private; +PyObject *obj; + + reader->startElement(ctx,name,atts); + if (ctxt->nodeNr==1){ + obj=PyObject_CallMethod(reader->handler,"_stream_start","O", + libxml_xmlDocPtrWrap(ctxt->myDoc)); + if (obj==NULL) reader->exception=1; + else Py_DECREF(obj); + } + else if (ctxt->nodeNr==2){ + obj=PyObject_CallMethod(reader->handler,"_stanza_start","OO", + libxml_xmlDocPtrWrap(ctxt->myDoc), + libxml_xmlNodePtrWrap(ctxt->node)); + if (obj==NULL) reader->exception=1; + else Py_DECREF(obj); + } +} + +void myEndElement(void *ctx,const xmlChar *name){ +xmlParserCtxtPtr ctxt=(xmlParserCtxtPtr) ctx; +ReaderObject *reader=(ReaderObject *)ctxt->_private; +PyObject *obj; +xmlNodePtr node; + + node=ctxt->node; + reader->endElement(ctx,name); + if (ctxt->nodeNr==0){ + reader->eof=1; + obj=PyObject_CallMethod(reader->handler,"_stream_end","O", + libxml_xmlDocPtrWrap(ctxt->myDoc)); + if (obj==NULL) reader->exception=1; + else Py_DECREF(obj); + } + else if (ctxt->nodeNr==1){ + obj=PyObject_CallMethod(reader->handler,"_stanza_end","OO", + libxml_xmlDocPtrWrap(ctxt->myDoc), + libxml_xmlNodePtrWrap(node)); + if (obj==NULL) reader->exception=1; + else Py_DECREF(obj); + } +} + +static void myError(void *ctx, const char *msg, ...){ +va_list vargs; +xmlParserCtxtPtr ctxt=(xmlParserCtxtPtr) ctx; +ReaderObject *reader=(ReaderObject *)ctxt->_private; +PyObject *str,*obj; + + va_start (vargs, msg); + str=PyString_FromFormatV(msg,vargs); + va_end (vargs); + if (str==NULL) { + reader->exception=1; + return; + } + obj=PyObject_CallMethod(reader->handler,"error","O",str); + Py_DECREF(str); + if (obj==NULL) reader->exception=1; + else Py_DECREF(obj); +} + +static void myFatalError(void *ctx, const char *msg, ...){ +va_list vargs; +xmlParserCtxtPtr ctxt=(xmlParserCtxtPtr) ctx; +ReaderObject *reader=(ReaderObject *)ctxt->_private; +PyObject *str,*obj; + + va_start (vargs, msg); + str=PyString_FromFormatV(msg,vargs); + va_end (vargs); + if (str==NULL) { + reader->exception=1; + return; + } + obj=PyObject_CallMethod(reader->handler,"error","O",str); + Py_DECREF(str); + if (obj==NULL) reader->exception=1; + else Py_DECREF(obj); +} + +static PyObject * reader_new(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) { +ReaderObject *reader; +PyObject *handler; + + if (!PyArg_ParseTuple(args, "O", &handler)) return NULL; + + reader=PyObject_New(ReaderObject,&ReaderType); + if (reader==NULL) return NULL; + + memcpy(&reader->sax,&xmlDefaultSAXHandler,sizeof(xmlSAXHandler)); + reader->startElement=reader->sax.startElement; + reader->sax.startElement=myStartElement; + reader->endElement=reader->sax.endElement; + reader->sax.endElement=myEndElement; + reader->error=reader->sax.error; + reader->sax.error=myError; + reader->fatalError=reader->sax.fatalError; + reader->sax.fatalError=myFatalError; + reader->eof=0; + reader->exception=0; + reader->handler=handler; + + reader->ctxt=xmlCreatePushParserCtxt(&reader->sax,NULL,"",0,"test.xml"); + reader->ctxt->_private=reader; + + return (PyObject *)reader; +} + +static void reader_free(PyObject *self) { +ReaderObject *reader=(ReaderObject *)self; + + xmlFreeParserCtxt(reader->ctxt); + Py_DECREF(reader->handler); + PyObject_Del(self); +} + +static PyObject * reader_feed(PyObject *self, PyObject *args) { +ReaderObject *reader=(ReaderObject *)self; +char *str; +int len; +int ret; + + if (!PyArg_ParseTuple(args, "s#", &str, &len)) return NULL; + + ret=xmlParseChunk(reader->ctxt,str,len,len==0); + + if (reader->exception) return NULL; + + if (ret==0){ + Py_INCREF(Py_None); + return Py_None; + } + + PyErr_Format(MyError,"Parser error #%i",ret); + return NULL; +} + +static PyObject * reader_doc(PyObject *self, PyObject *args) { + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef reader_methods[] = { + {(char *)"feed", reader_feed, METH_VARARGS, NULL}, + {(char *)"doc", reader_doc, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +static PyObject * reader_getattr(PyObject *obj, char *name) { +ReaderObject *reader=(ReaderObject *)obj; + + return Py_FindMethod(reader_methods, (PyObject *)reader, name); +} + +static int reader_setattr(PyObject *obj, char *name, PyObject *v) { + (void)PyErr_Format(PyExc_RuntimeError, "Read-only attribute: \%s", name); + return -1; +} + +static PyTypeObject ReaderType = { + PyObject_HEAD_INIT(NULL) + 0, + "_Reader", + sizeof(ReaderObject), + 0, + reader_free, /*tp_dealloc*/ + 0, /*tp_print*/ + reader_getattr, /*tp_getattr*/ + reader_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ +}; + +static PyMethodDef libxmlMethods[] = { + {(char *)"replace_ns", replace_ns, METH_VARARGS, NULL }, + {(char *)"remove_ns", remove_ns, METH_VARARGS, NULL }, + {(char *)"reader_new", reader_new, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +void init_xmlextra(void) { +static int initialized = 0; +PyObject *m, *d; + + if (initialized != 0) return; + ReaderType.ob_type = &PyType_Type; + m = Py_InitModule((char *) "_xmlextra", libxmlMethods); + d = PyModule_GetDict(m); + MyError = PyErr_NewException("_xmlextra.error", NULL, NULL); + PyDict_SetItemString(d, "error", MyError); + initialized = 1; +} |