diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2016-10-19 18:25:21 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2016-10-19 18:25:21 (GMT) |
commit | d72feaf69933b069cff3c0cb20a5f5f03ecba77b (patch) | |
tree | bf51d2814f4be65c850dba86dc2a5db0ad38bedf /libxslt/python | |
parent | 34be72f9ed749a5c013d3f7f47d810e8caf652cb (diff) | |
parent | 49e8fbec2420ef55b3246aabd89328b13530810c (diff) | |
download | blt-d72feaf69933b069cff3c0cb20a5f5f03ecba77b.zip blt-d72feaf69933b069cff3c0cb20a5f5f03ecba77b.tar.gz blt-d72feaf69933b069cff3c0cb20a5f5f03ecba77b.tar.bz2 |
Merge commit '49e8fbec2420ef55b3246aabd89328b13530810c' as 'libxslt'
Diffstat (limited to 'libxslt/python')
-rw-r--r-- | libxslt/python/Makefile.am | 77 | ||||
-rw-r--r-- | libxslt/python/TODO | 0 | ||||
-rwxr-xr-x | libxslt/python/generator.py | 924 | ||||
-rw-r--r-- | libxslt/python/libxml_wrap.h | 86 | ||||
-rw-r--r-- | libxslt/python/libxsl.py | 129 | ||||
-rw-r--r-- | libxslt/python/libxslt-python-api.xml | 234 | ||||
-rw-r--r-- | libxslt/python/libxslt.c | 1206 | ||||
-rw-r--r-- | libxslt/python/libxslt_wrap.h | 49 | ||||
-rw-r--r-- | libxslt/python/libxsltclass.txt | 238 | ||||
-rw-r--r-- | libxslt/python/tests/Makefile.am | 34 | ||||
-rwxr-xr-x | libxslt/python/tests/basic.py | 29 | ||||
-rwxr-xr-x | libxslt/python/tests/exslt.py | 56 | ||||
-rw-r--r-- | libxslt/python/tests/extelem.py | 89 | ||||
-rwxr-xr-x | libxslt/python/tests/extfunc.py | 66 | ||||
-rwxr-xr-x | libxslt/python/tests/pyxsltproc.py | 298 | ||||
-rw-r--r-- | libxslt/python/tests/test.xml | 1 | ||||
-rw-r--r-- | libxslt/python/tests/test.xsl | 9 | ||||
-rw-r--r-- | libxslt/python/types.c | 602 |
18 files changed, 4127 insertions, 0 deletions
diff --git a/libxslt/python/Makefile.am b/libxslt/python/Makefile.am new file mode 100644 index 0000000..fa58b78 --- /dev/null +++ b/libxslt/python/Makefile.am @@ -0,0 +1,77 @@ +# Makefile for libxml2 python library +AUTOMAKE_OPTIONS = 1.4 foreign + +SUBDIRS= . tests + +AM_CFLAGS = $(LIBXML_CFLAGS) + +DOCS_DIR = $(datadir)/doc/libxslt-python-$(LIBXSLT_VERSION) +# libxsltclass.txt is generated +DOCS = TODO + +EXTRA_DIST = \ + libxslt.c \ + types.c \ + generator.py \ + libxml_wrap.h \ + libxslt_wrap.h \ + libxsl.py \ + libxslt-python-api.xml \ + $(DOCS) + +libxsltmod_la_LDFLAGS = $(WIN32_EXTRA_LDFLAGS) -module -avoid-version + +if WITH_PYTHON +mylibs = \ + $(top_builddir)/libxslt/libxslt.la \ + $(top_builddir)/libexslt/libexslt.la + +all-local: libxslt.py + +python_LTLIBRARIES = libxsltmod.la + +libxsltmod_la_CPPFLAGS = \ + -I$(PYTHON_INCLUDES) \ + -I$(top_srcdir)/libxslt \ + -I$(top_srcdir) \ + -I../libexslt +libxsltmod_la_SOURCES = libxslt.c types.c +nodist_libxsltmod_la_SOURCES = libxslt-py.c +libxsltmod_la_LIBADD = $(mylibs) $(PYTHON_LIBS) + +libxslt.py: $(srcdir)/libxsl.py libxsltclass.py + cat $(srcdir)/libxsl.py libxsltclass.py > $@ + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(pythondir) + $(INSTALL) -m 0644 libxslt.py $(DESTDIR)$(pythondir) + $(MKDIR_P) $(DESTDIR)$(DOCS_DIR) + @(for doc in $(DOCS) ; \ + do $(INSTALL) -m 0644 $(srcdir)/$$doc $(DESTDIR)$(DOCS_DIR) ; done) + +uninstall-local: + rm -f $(DESTDIR)$(pythondir)/libxslt.py + rm -rf $(DESTDIR)$(DOCS_DIR) + +GENERATE = generator.py +API_DESC = $(top_srcdir)/doc/libxslt-api.xml $(srcdir)/libxslt-python-api.xml +GENERATED= libxsltclass.py \ + libxslt-export.c \ + libxslt-py.c \ + libxslt-py.h \ + libxsltclass.txt + +$(GENERATED): gen_prog + +gen_prog: $(srcdir)/$(GENERATE) $(API_DESC) + SRCDIR=$(srcdir) $(PYTHON) $(srcdir)/$(GENERATE) + touch gen_prog + +$(libxsltmod_la_OBJECTS): $(GENERATED) + +endif + +tests test: all + cd tests && $(MAKE) tests + +CLEANFILES= $(GENERATED) *.o libxslt.so *.pyc libxslt.py gen_prog diff --git a/libxslt/python/TODO b/libxslt/python/TODO new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libxslt/python/TODO diff --git a/libxslt/python/generator.py b/libxslt/python/generator.py new file mode 100755 index 0000000..c13c877 --- /dev/null +++ b/libxslt/python/generator.py @@ -0,0 +1,924 @@ +#!/usr/bin/python -u +# +# generate python wrappers from the XML API description +# + +functions = {} +enums = {} # { enumType: { enumConstant: enumValue } } + +import string + +####################################################################### +# +# That part if purely the API acquisition phase from the +# XML API description +# +####################################################################### +import os +import xml.sax + +debug = 0 +srcdir = os.getenv("SRCDIR", ".") + +def getparser(): + # Attach parser to an unmarshalling object. return both objects. + target = docParser() + parser = xml.sax.make_parser() + parser.setContentHandler(target) + return parser, target + +class docParser(xml.sax.handler.ContentHandler): + def __init__(self): + self._methodname = None + self._data = [] + self.in_function = 0 + + self.startElement = self.start + self.endElement = self.end + self.characters = self.data + + def close(self): + if debug: + print "close" + + def getmethodname(self): + return self._methodname + + def data(self, text): + if debug: + print "data %s" % text + self._data.append(text) + + def start(self, tag, attrs): + if debug: + print "start %s, %s" % (tag, attrs) + if tag == 'function': + self._data = [] + self.in_function = 1 + self.function = None + self.function_args = [] + self.function_descr = None + self.function_return = None + self.function_file = None + if attrs.has_key('name'): + self.function = attrs['name'] + if attrs.has_key('file'): + self.function_file = attrs['file'] + elif tag == 'info': + self._data = [] + elif tag == 'arg': + if self.in_function == 1: + self.function_arg_name = None + self.function_arg_type = None + self.function_arg_info = None + if attrs.has_key('name'): + self.function_arg_name = attrs['name'] + if attrs.has_key('type'): + self.function_arg_type = attrs['type'] + if attrs.has_key('info'): + self.function_arg_info = attrs['info'] + elif tag == 'return': + if self.in_function == 1: + self.function_return_type = None + self.function_return_info = None + self.function_return_field = None + if attrs.has_key('type'): + self.function_return_type = attrs['type'] + if attrs.has_key('info'): + self.function_return_info = attrs['info'] + if attrs.has_key('field'): + self.function_return_field = attrs['field'] + elif tag == 'enum': + enum(attrs['type'],attrs['name'],attrs['value']) + + + + def end(self, tag): + if debug: + print "end %s" % tag + if tag == 'function': + if self.function != None: + function(self.function, self.function_descr, + self.function_return, self.function_args, + self.function_file) + self.in_function = 0 + elif tag == 'arg': + if self.in_function == 1: + self.function_args.append([self.function_arg_name, + self.function_arg_type, + self.function_arg_info]) + elif tag == 'return': + if self.in_function == 1: + self.function_return = [self.function_return_type, + self.function_return_info, + self.function_return_field] + elif tag == 'info': + str = '' + for c in self._data: + str = str + c + if self.in_function == 1: + self.function_descr = str + + +def function(name, desc, ret, args, file): + functions[name] = (desc, ret, args, file) + +def enum(type, name, value): + if not enums.has_key(type): + enums[type] = {} + enums[type][name] = value + +####################################################################### +# +# Some filtering rukes to drop functions/types which should not +# be exposed as-is on the Python interface +# +####################################################################### + +skipped_modules = { + 'xmlmemory': None, + 'DOCBparser': None, + 'SAX': None, + 'hash': None, + 'list': None, + 'threads': None, + 'xpointer': None, + 'transform': None, +} +skipped_types = { + 'int *': "usually a return type", + 'xmlSAXHandlerPtr': "not the proper interface for SAX", + 'htmlSAXHandlerPtr': "not the proper interface for SAX", + 'xmlRMutexPtr': "thread specific, skipped", + 'xmlMutexPtr': "thread specific, skipped", + 'xmlGlobalStatePtr': "thread specific, skipped", + 'xmlListPtr': "internal representation not suitable for python", + 'xmlBufferPtr': "internal representation not suitable for python", + 'FILE *': None, +} + +####################################################################### +# +# Table of remapping to/from the python type or class to the C +# counterpart. +# +####################################################################### + +py_types = { + 'void': (None, None, None, None, None), + 'int': ('i', None, "int", "int", "libxml_"), + 'long': ('l', None, "long", "long", "libxml_"), + 'double': ('d', None, "double", "double", "libxml_"), + 'unsigned int': ('i', None, "int", "int", "libxml_"), + 'xmlChar': ('c', None, "int", "int", "libxml_"), + 'unsigned char *': ('z', None, "charPtr", "char *", "libxml_"), + 'char *': ('z', None, "charPtr", "char *", "libxml_"), + 'const char *': ('z', None, "charPtrConst", "const char *", "libxml_"), + 'xmlChar *': ('z', None, "xmlCharPtr", "xmlChar *", "libxml_"), + 'const xmlChar *': ('z', None, "xmlCharPtrConst", "const xmlChar *", "libxml_"), + 'xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr", "libxml_"), + 'const xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr", "libxml_"), + 'xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr", "libxml_"), + 'const xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr", "libxml_"), + 'xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr", "libxml_"), + 'const xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr", "libxml_"), + 'xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr", "libxml_"), + 'const xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr", "libxml_"), + 'xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr", "libxml_"), + 'const xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr", "libxml_"), + 'xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr", "libxml_"), + 'const xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr", "libxml_"), + 'xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"), + 'const xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"), + 'xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"), + 'const xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"), + 'htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"), + 'const htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"), + 'htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"), + 'const htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"), + 'htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'const htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"), + 'xmlXPathContextPtr': ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr", "libxml_"), + 'xmlXPathParserContextPtr': ('O', "xmlXPathParserContext", "xmlXPathParserContextPtr", "xmlXPathParserContextPtr", "libxml_"), + 'xmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr", "libxml_"), + 'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr", "libxml_"), + 'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr", "libxml_"), + 'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr", "libxml_"), + 'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"), + 'FILE *': ('O', "File", "FILEPtr", "FILE *", "libxml_"), + 'xsltTransformContextPtr': ('O', "transformCtxt", "xsltTransformContextPtr", "xsltTransformContextPtr", "libxslt_"), + 'xsltTransformContext *': ('O', "transformCtxt", "xsltTransformContextPtr", "xsltTransformContextPtr", "libxslt_"), + 'xsltStylePreCompPtr': ('O', "compiledStyle", "xsltStylePreCompPtr", "xsltStylePreCompPtr", "libxslt_"), + 'xsltStylePreComp *': ('O', "compiledStyle", "xsltStylePreCompPtr", "xsltStylePreCompPtr", "libxslt_"), + 'xsltStylesheetPtr': ('O', "stylesheet", "xsltStylesheetPtr", "xsltStylesheetPtr", "libxslt_"), + 'xsltStylesheet *': ('O', "stylesheet", "xsltStylesheetPtr", "xsltStylesheetPtr", "libxslt_"), + 'xmlXPathContext *': ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr", "libxslt_"), +} + +py_return_types = { + 'xmlXPathObjectPtr': ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr", "libxml_"), +} + +unknown_types = {} + +####################################################################### +# +# This part writes the C <-> Python stubs libxslt-py.[ch] and +# the table libxslt-export.c to add when registrering the Python module +# +####################################################################### + +def skip_function(name): + if name[0:12] == "xmlXPathWrap": + return 1 + if name == "xsltMatchPattern": + return 1 +# if name[0:11] == "xmlXPathNew": +# return 1 + return 0 + +def print_function_wrapper(name, output, export, include): + global py_types + global unknown_types + global functions + global skipped_modules + + try: + (desc, ret, args, file) = functions[name] + except: + print "failed to get function %s infos" + return + + if skipped_modules.has_key(file): + return 0 + if skip_function(name) == 1: + return 0 + + c_call = "" + format="" + format_args="" + c_args="" + c_return="" + c_convert="" + for arg in args: + # This should be correct + if arg[1][0:6] == "const ": + arg[1] = arg[1][6:] + c_args = c_args + " %s %s;\n" % (arg[1], arg[0]) + if py_types.has_key(arg[1]): + (f, t, n, c, p) = py_types[arg[1]] + if f != None: + format = format + f + if t != None: + format_args = format_args + ", &pyobj_%s" % (arg[0]) + c_args = c_args + " PyObject *pyobj_%s;\n" % (arg[0]) + c_convert = c_convert + \ + " %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0], + arg[1], t, arg[0]) + else: + format_args = format_args + ", &%s" % (arg[0]) + if c_call != "": + c_call = c_call + ", " + c_call = c_call + "%s" % (arg[0]) + else: + if skipped_types.has_key(arg[1]): + return 0 + if unknown_types.has_key(arg[1]): + lst = unknown_types[arg[1]] + lst.append(name) + else: + unknown_types[arg[1]] = [name] + return -1 + if format != "": + format = format + ":%s" % (name) + + if ret[0] == 'void': + if file == "python_accessor": + if args[1][1] == "char *" or args[1][1] == "xmlChar *": + c_call = "\n if (%s->%s != NULL) xmlFree(%s->%s);\n" % ( + args[0][0], args[1][0], args[0][0], args[1][0]) + c_call = c_call + " %s->%s = xmlStrdup((const xmlChar *)%s);\n" % (args[0][0], + args[1][0], args[1][0]) + else: + c_call = "\n %s->%s = %s;\n" % (args[0][0], args[1][0], + args[1][0]) + else: + c_call = "\n %s(%s);\n" % (name, c_call) + ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n" + elif py_types.has_key(ret[0]): + (f, t, n, c, p) = py_types[ret[0]] + c_return = " %s c_retval;\n" % (ret[0]) + if file == "python_accessor" and ret[2] != None: + c_call = "\n c_retval = %s->%s;\n" % (args[0][0], ret[2]) + else: + c_call = "\n c_retval = %s(%s);\n" % (name, c_call) + ret_convert = " py_retval = %s%sWrap((%s) c_retval);\n" % (p,n,c) + ret_convert = ret_convert + " return(py_retval);\n" + elif py_return_types.has_key(ret[0]): + (f, t, n, c, p) = py_return_types[ret[0]] + c_return = " %s c_retval;\n" % (ret[0]) + if file == "python_accessor" and ret[2] != None: + c_call = "\n c_retval = %s->%s;\n" % (args[0][0], ret[2]) + else: + c_call = "\n c_retval = %s(%s);\n" % (name, c_call) + ret_convert = " py_retval = %s%sWrap((%s) c_retval);\n" % (p,n,c) + ret_convert = ret_convert + " return(py_retval);\n" + else: + if skipped_types.has_key(ret[0]): + return 0 + if unknown_types.has_key(ret[0]): + lst = unknown_types[ret[0]] + lst.append(name) + else: + unknown_types[ret[0]] = [name] + return -1 + + include.write("PyObject * ") + include.write("libxslt_%s(PyObject *self, PyObject *args);\n" % (name)) + + export.write(" { (char *)\"%s\", libxslt_%s, METH_VARARGS, NULL },\n" % (name, name)) + + if file == "python": + # Those have been manually generated + return 1 + if file == "python_accessor" and ret[0] != "void" and ret[2] == None: + # Those have been manually generated + return 1 + + output.write("PyObject *\n") + output.write("libxslt_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) + output.write(" PyObject *args") + if format == "": + output.write(" ATTRIBUTE_UNUSED") + output.write(") {\n") + if ret[0] != 'void': + output.write(" PyObject *py_retval;\n") + if c_return != "": + output.write(c_return) + if c_args != "": + output.write(c_args) + if format != "": + output.write("\n if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" % + (format, format_args)) + output.write(" return(NULL);\n") + if c_convert != "": + output.write(c_convert) + + output.write(c_call) + output.write(ret_convert) + output.write("}\n\n") + return 1 + +def buildStubs(): + global py_types + global py_return_types + global unknown_types + + try: + f = open("%s/libxslt-api.xml" % srcdir) + data = f.read() + (parser, target) = getparser() + parser.feed(data) + parser.close() + except IOError, msg: + try: + f = open("%s/../doc/libxslt-api.xml" % srcdir) + data = f.read() + (parser, target) = getparser() + parser.feed(data) + parser.close() + except IOError, msg: + print "../doc/libxslt-api.xml", ":", msg + + n = len(functions.keys()) + print "Found %d functions in libxslt-api.xml" % (n) + + py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", + "pythonObject", "libxml_") + try: + f = open("%s/libxslt-python-api.xml" % srcdir) + data = f.read() + (parser, target) = getparser() + parser.feed(data) + parser.close() + except IOError, msg: + print "libxslt-python-api.xml", ":", msg + + + print "Found %d functions in libxslt-python-api.xml" % ( + len(functions.keys()) - n) + nb_wrap = 0 + failed = 0 + skipped = 0 + + include = open("libxslt-py.h", "w") + include.write("/* Generated */\n\n") + export = open("libxslt-export.c", "w") + export.write("/* Generated */\n\n") + wrapper = open("libxslt-py.c", "w") + wrapper.write("/* Generated */\n\n") +# wrapper.write("#include \"config.h\"\n") + wrapper.write("#include <libxslt/xsltconfig.h>\n") + wrapper.write("#include \"libxslt_wrap.h\"\n") + wrapper.write("#include \"libxslt-py.h\"\n\n") + for function in functions.keys(): + ret = print_function_wrapper(function, wrapper, export, include) + if ret < 0: + failed = failed + 1 + del functions[function] + if ret == 0: + skipped = skipped + 1 + del functions[function] + if ret == 1: + nb_wrap = nb_wrap + 1 + include.close() + export.close() + wrapper.close() + + print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap, + failed, skipped) + print "Missing type converters:" + for type in unknown_types.keys(): + print "%s:%d " % (type, len(unknown_types[type])), + print + +####################################################################### +# +# This part writes part of the Python front-end classes based on +# mapping rules between types and classes and also based on function +# renaming to get consistent function names at the Python level +# +####################################################################### + +# +# The type automatically remapped to generated classes +# +libxml2_classes_type = { + "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"), + "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"), + "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), + "xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), + "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), + "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), + "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"), + "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"), + "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"), + "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"), + "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"), + "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"), + "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"), + "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"), + "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"), + "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"), + "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"), + "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"), + "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), + "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), + "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"), +} + +classes_type = { + "xsltTransformContextPtr": ("._o", "transformCtxt(_obj=%s)", "transformCtxt"), + "xsltTransformContext *": ("._o", "transformCtxt(_obj=%s)", "transformCtxt"), + "xsltStylesheetPtr": ("._o", "stylesheet(_obj=%s)", "stylesheet"), + "xsltStylesheet *": ("._o", "stylesheet(_obj=%s)", "stylesheet"), + "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"), + "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"), + "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"), + "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"), +} + +converter_type = { + "xmlXPathObjectPtr": "libxml2.xpathObjectRet(%s)", +} + +primary_classes = ["xpathParserContext", "xpathContext", "transformCtxt", "stylesheet"] + +classes_ancestor = { + "xpathContext" : "libxml2.xpathContext", + "xpathParserContext" : "libxml2.xpathParserContext", + "transformCtxt": "transformCtxtBase", + "stylesheet": "stylesheetBase", +} +classes_destructors = { + "xpathContext" : "pass" +} + +function_classes = {} +ctypes = [] +classes_list = [] + + +def nameFixup(name, classe, type, file): + listname = classe + "List" + ll = len(listname) + l = len(classe) + if name[0:l] == listname: + func = name[l:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:12] == "xmlParserGet" and file == "python_accessor": + func = name[12:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:12] == "xmlParserSet" and file == "python_accessor": + func = name[12:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:10] == "xmlNodeGet" and file == "python_accessor": + func = name[10:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:18] == "xsltXPathParserGet" and file == "python_accessor": + func = name[18:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:12] == "xsltXPathGet" and file == "python_accessor": + func = name[12:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:16] == "xsltTransformGet" and file == "python_accessor": + func = name[16:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:16] == "xsltTransformSet" and file == "python_accessor": + func = name[13:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:17] == "xsltStylesheetGet" and file == "python_accessor": + func = name[17:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:17] == "xsltStylesheetSet" and file == "python_accessor": + func = name[14:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:l] == classe: + func = name[l:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:7] == "libxml_": + func = name[7:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:8] == "libxslt_": + func = name[8:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:6] == "xmlGet": + func = name[6:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:3] == "xml": + func = name[3:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:7] == "xsltGet": + func = name[7:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:4] == "xslt": + func = name[4:] + func = string.lower(func[0:1]) + func[1:] + else: + func = name + if func[0:5] == "xPath": + func = "xpath" + func[5:] + elif func[0:4] == "xPtr": + func = "xpointer" + func[4:] + elif func[0:8] == "xInclude": + func = "xinclude" + func[8:] + elif func[0:2] == "iD": + func = "ID" + func[2:] + elif func[0:3] == "uRI": + func = "URI" + func[3:] + elif func[0:4] == "uTF8": + func = "UTF8" + func[4:] + return func + +def functionCompare(info1, info2): + (index1, func1, name1, ret1, args1, file1) = info1 + (index2, func2, name2, ret2, args2, file2) = info2 + if file1 == file2: + if func1 < func2: + return -1 + if func1 > func2: + return 1 + if file1 == "python_accessor": + return -1 + if file2 == "python_accessor": + return 1 + if file1 < file2: + return -1 + if file1 > file2: + return 1 + return 0 + +def writeDoc(name, args, indent, output): + if functions[name][0] == None or functions[name][0] == "": + return + val = functions[name][0] + val = string.replace(val, "NULL", "None") + output.write(indent) + output.write('"""') + while len(val) > 60: + if val[0] == " ": + val = val[1:] + continue + str = val[0:60] + i = string.rfind(str, " ") + if i < 0: + i = 60 + str = val[0:i] + val = val[i:] + output.write(str) + output.write('\n ') + output.write(indent) + output.write(val) + output.write('"""\n') + +def buildWrappers(): + global ctypes + global py_types + global py_return_types + global unknown_types + global functions + global function_classes + global libxml2_classes_type + global classes_type + global classes_list + global converter_type + global primary_classes + global converter_type + global classes_ancestor + global converter_type + global primary_classes + global classes_ancestor + global classes_destructors + + function_classes["None"] = [] + for type in classes_type.keys(): + function_classes[classes_type[type][2]] = [] + + # + # Build the list of C types to look for ordered to start with + # primary classes + # + ctypes_processed = {} + classes_processed = {} + for classe in primary_classes: + classes_list.append(classe) + classes_processed[classe] = () + for type in classes_type.keys(): + tinfo = classes_type[type] + if tinfo[2] == classe: + ctypes.append(type) + ctypes_processed[type] = () + for type in classes_type.keys(): + if ctypes_processed.has_key(type): + continue + tinfo = classes_type[type] + if not classes_processed.has_key(tinfo[2]): + classes_list.append(tinfo[2]) + classes_processed[tinfo[2]] = () + + ctypes.append(type) + ctypes_processed[type] = () + + for name in functions.keys(): + found = 0 + (desc, ret, args, file) = functions[name] + for type in ctypes: + classe = classes_type[type][2] + + if name[0:4] == "xslt" and len(args) >= 1 and args[0][1] == type: + found = 1 + func = nameFixup(name, classe, type, file) + info = (0, func, name, ret, args, file) + function_classes[classe].append(info) + elif name[0:4] == "xslt" and len(args) >= 2 and args[1][1] == type: + found = 1 + func = nameFixup(name, classe, type, file) + info = (1, func, name, ret, args, file) + function_classes[classe].append(info) + elif name[0:4] == "xslt" and len(args) >= 3 and args[2][1] == type: + found = 1 + func = nameFixup(name, classe, type, file) + info = (2, func, name, ret, args, file) + function_classes[classe].append(info) + if found == 1: + continue + if name[0:8] == "xmlXPath": + continue + if name[0:6] == "xmlStr": + continue + if name[0:10] == "xmlCharStr": + continue + func = nameFixup(name, "None", file, file) + info = (0, func, name, ret, args, file) + function_classes['None'].append(info) + + classes = open("libxsltclass.py", "w") + txt = open("libxsltclass.txt", "w") + txt.write(" Generated Classes for libxslt-python\n\n") + + txt.write("#\n# Global functions of the module\n#\n\n") + if function_classes.has_key("None"): + flist = function_classes["None"] + flist.sort(functionCompare) + oldfile = "" + for info in flist: + (index, func, name, ret, args, file) = info + if file != oldfile: + classes.write("#\n# Functions from module %s\n#\n\n" % file) + txt.write("\n# functions from module %s\n" % file) + oldfile = file + classes.write("def %s(" % func) + txt.write("%s()\n" % func) + n = 0 + for arg in args: + if n != 0: + classes.write(", ") + classes.write("%s" % arg[0]) + n = n + 1 + classes.write("):\n") + writeDoc(name, args, ' ', classes) + + for arg in args: + if classes_type.has_key(arg[1]): + classes.write(" if %s == None: %s__o = None\n" % + (arg[0], arg[0])) + classes.write(" else: %s__o = %s%s\n" % + (arg[0], arg[0], classes_type[arg[1]][0])) + elif libxml2_classes_type.has_key(arg[1]): + classes.write(" if %s == None: %s__o = None\n" % + (arg[0], arg[0])) + classes.write(" else: %s__o = %s%s\n" % + (arg[0], arg[0], libxml2_classes_type[arg[1]][0])) + if ret[0] != "void": + classes.write(" ret = ") + else: + classes.write(" ") + classes.write("libxsltmod.%s(" % name) + n = 0 + for arg in args: + if n != 0: + classes.write(", ") + classes.write("%s" % arg[0]) + if classes_type.has_key(arg[1]): + classes.write("__o") + if libxml2_classes_type.has_key(arg[1]): + classes.write("__o") + n = n + 1 + classes.write(")\n") + if ret[0] != "void": + if classes_type.has_key(ret[0]): + classes.write(" if ret == None: return None\n") + classes.write(" return ") + classes.write(classes_type[ret[0]][1] % ("ret")) + classes.write("\n") + elif libxml2_classes_type.has_key(ret[0]): + classes.write(" if ret == None: return None\n") + classes.write(" return libxml2.") + classes.write(libxml2_classes_type[ret[0]][1] % ("ret")) + classes.write("\n") + else: + classes.write(" return ret\n") + classes.write("\n") + + txt.write("\n\n#\n# Set of classes of the module\n#\n\n") + for classname in classes_list: + if classname == "None": + pass + else: + if classes_ancestor.has_key(classname): + txt.write("\n\nClass %s(%s)\n" % (classname, + classes_ancestor[classname])) + classes.write("class %s(%s):\n" % (classname, + classes_ancestor[classname])) + classes.write(" def __init__(self, _obj=None):\n") + classes.write(" self._o = None\n") + classes.write(" %s.__init__(self, _obj=_obj)\n\n" % ( + classes_ancestor[classname])) + if classes_ancestor[classname] == "xmlCore" or \ + classes_ancestor[classname] == "xmlNode": + classes.write(" def __repr__(self):\n") + format = "%s:%%s" % (classname) + classes.write(" return \"%s\" %% (self.name)\n\n" % ( + format)) + else: + txt.write("Class %s()\n" % (classname)) + classes.write("class %s:\n" % (classname)) + classes.write(" def __init__(self, _obj=None):\n") + classes.write(" if _obj != None:self._o = _obj;return\n") + classes.write(" self._o = None\n\n") + if classes_destructors.has_key(classname): + classes.write(" def __del__(self):\n") + if classes_destructors[classname] == "pass": + classes.write(" pass\n") + else: + classes.write(" if self._o != None:\n") + classes.write(" libxsltmod.%s(self._o)\n" % + classes_destructors[classname]) + classes.write(" self._o = None\n\n") + flist = function_classes[classname] + flist.sort(functionCompare) + oldfile = "" + for info in flist: + (index, func, name, ret, args, file) = info + if file != oldfile: + if file == "python_accessor": + classes.write(" # accessors for %s\n" % (classname)) + txt.write(" # accessors\n") + else: + classes.write(" #\n") + classes.write(" # %s functions from module %s\n" % ( + classname, file)) + txt.write("\n # functions from module %s\n" % file) + classes.write(" #\n\n") + oldfile = file + classes.write(" def %s(self" % func) + txt.write(" %s()\n" % func) + n = 0 + for arg in args: + if n != index: + classes.write(", %s" % arg[0]) + n = n + 1 + classes.write("):\n") + writeDoc(name, args, ' ', classes) + n = 0 + for arg in args: + if classes_type.has_key(arg[1]): + if n != index: + classes.write(" if %s == None: %s__o = None\n" % + (arg[0], arg[0])) + classes.write(" else: %s__o = %s%s\n" % + (arg[0], arg[0], classes_type[arg[1]][0])) + elif libxml2_classes_type.has_key(arg[1]): + classes.write(" if %s == None: %s__o = None\n" % + (arg[0], arg[0])) + classes.write(" else: %s__o = %s%s\n" % + (arg[0], arg[0], + libxml2_classes_type[arg[1]][0])) + n = n + 1 + if ret[0] != "void": + classes.write(" ret = ") + else: + classes.write(" ") + classes.write("libxsltmod.%s(" % name) + n = 0 + for arg in args: + if n != 0: + classes.write(", ") + if n != index: + classes.write("%s" % arg[0]) + if classes_type.has_key(arg[1]): + classes.write("__o") + elif libxml2_classes_type.has_key(arg[1]): + classes.write("__o") + else: + classes.write("self") + if classes_type.has_key(arg[1]): + classes.write(classes_type[arg[1]][0]) + elif libxml2_classes_type.has_key(arg[1]): + classes.write(libxml2_classes_type[arg[1]][0]) + n = n + 1 + classes.write(")\n") + if ret[0] != "void": + if classes_type.has_key(ret[0]): + classes.write(" if ret == None: return None\n") + classes.write(" return ") + classes.write(classes_type[ret[0]][1] % ("ret")) + classes.write("\n") + elif libxml2_classes_type.has_key(ret[0]): + classes.write(" if ret == None: return None\n") + classes.write(" return libxml2.") + classes.write(libxml2_classes_type[ret[0]][1] % ("ret")) + classes.write("\n") + elif converter_type.has_key(ret[0]): + classes.write(" if ret == None: return None\n") + classes.write(" return ") + classes.write(converter_type[ret[0]] % ("ret")) + classes.write("\n") + else: + classes.write(" return ret\n") + classes.write("\n") + + # + # Generate enum constants + # + for type,enum in enums.items(): + classes.write("# %s\n" % type) + items = enum.items() + items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1]))) + for name,value in items: + classes.write("%s = %s\n" % (name,value)) + classes.write("\n"); + + txt.close() + classes.close() + +buildStubs() +buildWrappers() diff --git a/libxslt/python/libxml_wrap.h b/libxslt/python/libxml_wrap.h new file mode 100644 index 0000000..53777d9 --- /dev/null +++ b/libxslt/python/libxml_wrap.h @@ -0,0 +1,86 @@ +#include <Python.h> +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#include <libxml/catalog.h> +#include <libxml/threads.h> +#include <libxml/nanoftp.h> +#include <libxml/nanohttp.h> +#include <libxml/uri.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <libxml/debugXML.h> +#include <libxml/HTMLparser.h> +#include <libxml/HTMLtree.h> +#include <libxml/xinclude.h> +#include <libxml/xpointer.h> + +#define PyxmlNode_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlNode_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlNodePtr obj; +} PyxmlNode_Object; + +#define PyxmlXPathContext_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlXPathContext_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlXPathContextPtr obj; +} PyxmlXPathContext_Object; + +#define PyxmlXPathParserContext_Get(v) (((v) == Py_None) ? NULL : \ + (((PyxmlXPathParserContext_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlXPathParserContextPtr obj; +} PyxmlXPathParserContext_Object; + +#define PyparserCtxt_Get(v) (((v) == Py_None) ? NULL : \ + (((PyparserCtxt_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlParserCtxtPtr obj; +} PyparserCtxt_Object; + +#define Pycatalog_Get(v) (((v) == Py_None) ? NULL : \ + (((Pycatalog_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xmlCatalogPtr obj; +} Pycatalog_Object; + +#define PyFile_Get(v) (((v) == Py_None) ? NULL : \ + (PyFile_Check(v) ? (PyFile_AsFile(v)) : stdout)) + +PyObject * libxml_intWrap(int val); +PyObject * libxml_longWrap(long val); +PyObject * libxml_xmlCharPtrWrap(xmlChar *str); +PyObject * libxml_constxmlCharPtrWrap(const xmlChar *str); +PyObject * libxml_charPtrWrap(char *str); +PyObject * libxml_constcharPtrWrap(const char *str); +PyObject * libxml_charPtrConstWrap(const char *str); +PyObject * libxml_xmlCharPtrConstWrap(const xmlChar *str); +PyObject * libxml_xmlDocPtrWrap(xmlDocPtr doc); +PyObject * libxml_xmlNodePtrWrap(xmlNodePtr node); +PyObject * libxml_xmlAttrPtrWrap(xmlAttrPtr attr); +PyObject * libxml_xmlNsPtrWrap(xmlNsPtr ns); +PyObject * libxml_xmlAttributePtrWrap(xmlAttributePtr ns); +PyObject * libxml_xmlElementPtrWrap(xmlElementPtr ns); +PyObject * libxml_doubleWrap(double val); +PyObject * libxml_xmlXPathContextPtrWrap(xmlXPathContextPtr ctxt); +PyObject * libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt); +PyObject * libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt); +PyObject * libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj); +PyObject * libxml_xmlCatalogPtrWrap(xmlCatalogPtr obj); +PyObject * libxml_xmlURIPtrWrap(xmlURIPtr uri); +PyObject * libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer); +PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer); +PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp); + +xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj); diff --git a/libxslt/python/libxsl.py b/libxslt/python/libxsl.py new file mode 100644 index 0000000..e8e86e4 --- /dev/null +++ b/libxslt/python/libxsl.py @@ -0,0 +1,129 @@ +# +# Both libxml2mod and libxsltmod have a dependancy on libxml2.so +# and they should share the same module, try to convince the python +# loader to work in that mode if feasible +# +import sys +if not hasattr(sys,'getdlopenflags'): + import libxml2mod + import libxsltmod + import libxml2 +else: + try: + from dl import RTLD_GLOBAL, RTLD_NOW + except ImportError: + RTLD_GLOBAL = -1 + RTLD_NOW = -1 + try: + import os + osname = os.uname()[0] + if osname == 'Linux' or osname == 'SunOS': + RTLD_GLOBAL = 0x00100 + RTLD_NOW = 0x00002 + elif osname == 'Darwin': + RTLD_GLOBAL = 0x8 + RTLD_NOW = 0x2 + # + # is there a better method ? + # +# else: +# print "libxslt could not guess RTLD_GLOBAL and RTLD_NOW " + \ +# "on this platform: %s" % (osname) + except: + pass +# print "libxslt could not guess RTLD_GLOBAL and RTLD_NOW " + \ +# "on this platform: %s" % (osname) + except: + RTLD_GLOBAL = -1 + RTLD_NOW = -1 + + if RTLD_GLOBAL != -1 and RTLD_NOW != -1: + try: + flags = sys.getdlopenflags() + sys.setdlopenflags(RTLD_GLOBAL | RTLD_NOW) + try: + import libxml2mod + import libxsltmod + import libxml2 + finally: + sys.setdlopenflags(flags) + except: + import libxml2mod + import libxsltmod + import libxml2 + else: + import libxml2mod + import libxsltmod + import libxml2 + + +class transformCtxtBase: + def __init__(self, _obj=None): + if _obj != None: + self._o = _obj; + return + self._o = None + def __hash__(self): + v = libxsltmod.xsltGetTransformContextHashCode(self._o) + return v + def __eq__(self, other): + if other == None: + return 0 + v = libxsltmod.xsltCompareTransformContextsEqual(self._o, other._o) + return v + +class stylesheetBase: + def __init__(self, _obj=None): + if _obj != None: + self._o = _obj; + return + self._o = None + def __hash__(self): + v = libxsltmod.xsltGetStylesheetHashCode(self._o) + return v + def __eq__(self, other): + if other == None: + return 0 + v = libxsltmod.xsltCompareStylesheetsEqual(self._o, other._o) + return v + +class extensionModule: + def _styleInit(self, style, URI): + return self.styleInit(stylesheet(_obj=style), URI) + + def _styleShutdown(self, style, URI, data): + return self.styleShutdown(stylesheet(_obj=style), URI, data) + + def _ctxtInit(self, ctxt, URI): + return self.ctxtInit(transformCtxt(_obj=ctxt), URI) + + def _ctxtShutdown(self, ctxt, URI, data): + return self.ctxtShutdown(transformCtxt(_obj=ctxt), URI, data) + + def styleInit(self, style, URI): + """Callback function when used in a newly compiled stylesheet, + the return value is passed in subsequent calls""" + pass + + def styleShutdown(self, style, URI, data): + """Callback function when a stylesheet using it is destroyed""" + pass + + def ctxtInit(self, ctxt, URI): + """Callback function when used in a new transformation process, + the return value is passed in subsequent calls""" + pass + + def ctxtShutdown(self, ctxt, URI, data): + """Callback function when a transformation using it finishes""" + pass + +def cleanup(): + """Cleanup all libxslt and libxml2 memory allocated""" + libxsltmod.xsltPythonCleanup() + libxml2.cleanupParser() + +# +# Everything below this point is automatically generated +# + diff --git a/libxslt/python/libxslt-python-api.xml b/libxslt/python/libxslt-python-api.xml new file mode 100644 index 0000000..49491f3 --- /dev/null +++ b/libxslt/python/libxslt-python-api.xml @@ -0,0 +1,234 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<api name='libxslt-python'> + <files> + <file name='python'> + </file> + </files> + <symbols> + <function name='xsltSaveResultToString' file='python'> + <info>Have the stylesheet serialize the result of a transformation to a python string</info> + <return type='char *' info='The result document as a string' /> + <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/> + <arg name='result' type='xmlDocPtr' info='The result document'/> + </function> + <function name='xsltSetLoaderFunc' file='python'> + <info>Set the function for controlling document loading</info> + <return type='long' info='0 for failure or 1 for success'/> + <arg name='loader' type='pythonObject' info='the loader function; should take: string URI, xsltParserContext, context, type; when type == 1 the context is a stylesheet, when type == 0 the context is a transformCtxt'/> + </function> + <function name='xsltGetLoaderFunc' file='python'> + <info>Get the function for controlling document loading</info> + <return type='pythonObject *' info='the function'/> + </function> + <function name='xsltNewTransformContext' file='python'> + <info>Create a new XSLT TransformContext</info> + <return type='xsltTransformContextPtr' info='an xslt TransformContext'/> + <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/> + <arg name='doc' type='xmlDocPtr' info='the input document'/> + </function> + <function name='xsltFreeTransformContext' file='python'> + <info>Free up an existing XSLT TransformContext</info> + <return type='void' info='None'/> + <arg name='transformCtxt' type='xsltTransformContextPtr' info='an existing tranformCtxt'/> + </function> + <function name='xsltGetTransformContextHashCode' file='python'> + <info>Get the hash code of the transformContext</info> + <return type='int' info='the hash code' /> + <arg name='transformCtxt' type='xsltTransformContextPtr' info='a parsed XSLT transformContext'/> + </function> + <function name='xsltGetStylesheetHashCode' file='python'> + <info>Get the hash code of the stylesheet</info> + <return type='int' info='the hash code' /> + <arg name='stylesheet' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/> + </function> + <function name='xsltCompareTransformContextsEqual' file='python'> + <info>Compare one transformCtxt with another</info> + <return type='int' info='1 in case of success, 0 or -1 in error' /> + <arg name='transformCtxt' type='xsltTransformContextPtr' info='a parsed XSLT transformContext'/> + <arg name='other' type='xsltTransformContextPtr' info='a parsed XSLT transformContext'/> + </function> + <function name='xsltCompareStylesheetsEqual' file='python'> + <info>Compare one stylesheet with another</info> + <return type='int' info='1 in case of success, 0 or -1 in error' /> + <arg name='stylesheet' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/> + <arg name='other' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/> + </function> + <function name='xsltApplyStylesheetUser' file='python'> + <info>Apply the stylesheet to the document</info> + <return type='xmlDocPtr' info="the result document or NULL in case of error"/> + <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/> + <arg name='doc' type='xmlDocPtr' info='a parsed XML document'/> + <arg name='params' type='pythonObject' info='the parameters dictionary'/> + <arg name='transformCtxt' type='xsltTransformContextPtr' info='transformation context'/> + </function> + <function name='xsltApplyStylesheet' file='python'> + <info>Apply the stylesheet to the document</info> + <return type='xmlDocPtr' info="the result document or NULL in case of error"/> + <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/> + <arg name='doc' type='xmlDocPtr' info='a parsed XML document'/> + <arg name='params' type='pythonObject' info='the parameters dictionary'/> + </function> + <function name='xsltRegisterErrorHandler' file='python'> + <info>Register a Python written function to for error reporting. The function is called back as f(ctx, error).</info> + <return type='int' info="1 in case of success, 0 or -1 in case of error"/> + <arg name='f' type='pythonObject' info='the python function'/> + <arg name='ctx' type='pythonObject' info='a context for the callback'/> + </function> + <function name='xsltRegisterExtModuleElement' file='python'> + <info>Register a Python written element to the XSLT engine</info> + <return type='int' info="0 in case of success, -1 in case of error"/> + <arg name='name' type='xmlChar *' info='the element name'/> + <arg name='URI' type='xmlChar *' info='the namespace or NULL'/> + <arg name='precompile' type='pythonObject' info='method called when stylesheet is compiled'/> + <arg name='transform' type='pythonObject' info='method called during transform, must not modify stylesheet'/> + </function> + <function name='xsltRegisterExtModuleFunction' file='python'> + <info>Register a Python written function to the XSLT engine</info> + <return type='int' info="0 in case of success, -1 in case of error"/> + <arg name='name' type='xmlChar *' info='the function name'/> + <arg name='URI' type='xmlChar *' info='the namespace or NULL'/> + <arg name='f' type='pythonObject' info='the python function'/> + </function> + <function name='xsltRegisterExtensionClass' file='python'> + <info>Register a Python written extension class to the XSLT engine</info> + <return type='int' info="0 in case of success, -1 in case of error"/> + <arg name='URI' type='xmlChar *' info='the namespace or NULL'/> + <arg name='c' type='pythonObject' info='the python class instance'/> + </function> + <function name='xsltPythonCleanup' file='python'> + <info>Cleanup just libxslt (not libxml2) memory allocated</info> + <return type='void'/> + </function> + <!-- xmlXPathParserContextPtr accessors --> + <function name='xsltXPathParserGetContext' file='python_accessor'> + <info>Get the xpathContext from an xpathParserContext</info> + <return type='xmlXPathContextPtr' info="The XPath context" field="context"/> + <arg name='ctxt' type='xmlXPathParserContextPtr' info='the XPath parser context'/> + </function> + <!-- xmlXPathContextPtr accessors --> + <function name='xsltXPathGetTransformContext' file='python_accessor'> + <info>Get the transformation context from an xpathContext</info> + <return type='xsltTransformContextPtr' info="The node context" field="extra"/> + <arg name='ctxt' type='xmlXPathContextPtr' info='the XPath context'/> + </function> + <!-- xsltTransformContextPtr accessors --> + <function name='xsltTransformGetStyle' file='python_accessor'> + <info>Get the stylesheet from a transformation</info> + <return type='xsltStylesheetPtr' info="The stylesheet" field="style"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetCurrent' file='python_accessor'> + <info>Get the current() node of a transformation</info> + <return type='xmlNodePtr' info="The node" field="node"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetOutputDoc' file='python_accessor'> + <info>Get the output document of a transformation</info> + <return type='xmlDocPtr' info="The output doc" field="output"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetOutputURI' file='python_accessor'> + <info>Get the output URI of a transformation if known</info> + <return type='const char *' info="The output URI" field="outputFile"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetInsertNode' file='python_accessor'> + <info>Get the insertion node in the output document</info> + <return type='xmlNodePtr' info="The insertion node" field="insert"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetInstruction' file='python_accessor'> + <info>Get the instruction node in the stylesheet</info> + <return type='xmlNodePtr' info="The instruction node" field="inst"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetMode' file='python_accessor'> + <info>Get the mode of a transformation</info> + <return type='const xmlChar *' info="The mode" field="mode"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetModeURI' file='python_accessor'> + <info>Get the mode URI of a transformation</info> + <return type='const xmlChar *' info="The mode URI" field="modeURI"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetContext' file='python_accessor'> + <info>Get the XPath context of a transformation</info> + <return type='xmlXPathContextPtr' info="The XPath context" field="xpathCtxt"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformGetPrivate' file='python_accessor'> + <info>Get the private field of a transformation</info> + <return type='pythonObject *' info="The private field" field="_private"/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + </function> + <function name='xsltTransformSetPrivate' file='python_accessor'> + <info>Set the private field of a transformation</info> + <return type='void'/> + <arg name='ctxt' type='xsltTransformContextPtr' info='the transformation context'/> + <arg name='_private' type='pythonObject *' info='The private field'/> + </function> + <!-- xsltStylesheetPtr accessors --> + <function name='xsltStylesheetGetParent' file='python_accessor'> + <info>Get the parent of a stylesheet</info> + <return type='xsltStylesheetPtr' info="The parent" field="parent"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetNext' file='python_accessor'> + <info>Get the next sibling of a stylesheet</info> + <return type='xsltStylesheetPtr' info="The next sibling" field="next"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetImports' file='python_accessor'> + <info>Get the imports of a stylesheet</info> + <return type='xsltStylesheetPtr' info="The next sibling" field="imports"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetDoc' file='python_accessor'> + <info>Get the document of a stylesheet</info> + <return type='xmlDocPtr' info="The XML document" field="doc"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetMethod' file='python_accessor'> + <info>Get the output method of a stylesheet</info> + <return type='const xmlChar *' info="The output method" field="method"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetMethodURI' file='python_accessor'> + <info>Get the output method URI of a stylesheet</info> + <return type='const xmlChar *' info="The output method URI" field="methodURI"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetVersion' file='python_accessor'> + <info>Get the output version of a stylesheet</info> + <return type='const xmlChar *' info="The output version" field="version"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetEncoding' file='python_accessor'> + <info>Get the output encoding of a stylesheet</info> + <return type='const xmlChar *' info="The output encoding" field="encoding"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetDoctypePublic' file='python_accessor'> + <info>Get the output PUBLIC of a stylesheet</info> + <return type='const xmlChar *' info="The output PUBLIC" field="doctypePublic"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetDoctypeSystem' file='python_accessor'> + <info>Get the output SYSTEM of a stylesheet</info> + <return type='const xmlChar *' info="The output SYSTEM" field="doctypeSystem"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetGetPrivate' file='python_accessor'> + <info>Get the private field of a stylesheet</info> + <return type='pythonObject *' info="The private field" field="_private"/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + </function> + <function name='xsltStylesheetSetPrivate' file='python_accessor'> + <info>Set the private field of a stylesheet</info> + <return type='void'/> + <arg name='style' type='xsltStylesheetPtr' info='the stylesheet'/> + <arg name='_private' type='pythonObject *' info='The private field'/> + </function> + </symbols> +</api> diff --git a/libxslt/python/libxslt.c b/libxslt/python/libxslt.c new file mode 100644 index 0000000..8dd6c78 --- /dev/null +++ b/libxslt/python/libxslt.c @@ -0,0 +1,1206 @@ +/* + libxslt.c: this module implements the main part of the glue of the + * libxslt library and the Python interpreter. It provides the + * entry points where an automatically generated stub is either + * unpractical or would not match cleanly the Python model. + * + * If compiled with MERGED_MODULES, the entry point will be used to + * initialize both the libxml2 and the libxslt wrappers + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ +#include <Python.h> +/* #include "config.h" */ +#include <libxml/xmlmemory.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include "libexslt/exslt.h" +#include "libxslt_wrap.h" +#include "libxslt-py.h" + +#include <stdio.h> + +#if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(vsnprintf) +#define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a) +#elif defined(XSLT_NEED_TRIO) +#include "trio.h" +#define vsnprintf trio_vsnprintf +#endif + +/* #define DEBUG */ +/* #define DEBUG_XPATH */ +/* #define DEBUG_ERROR */ +/* #define DEBUG_MEMORY */ +/* #define DEBUG_EXTENSIONS */ +/* #define DEBUG_EXTENSIONS */ + +void initlibxsltmod(void); + +/************************************************************************ + * * + * Per type specific glue * + * * + ************************************************************************/ + +PyObject * +libxslt_xsltStylesheetPtrWrap(xsltStylesheetPtr style) { + PyObject *ret; + +#ifdef DEBUG + printf("libxslt_xsltStylesheetPtrWrap: style = %p\n", style); +#endif + if (style == NULL) { + Py_INCREF(Py_None); + return(Py_None); + } + ret = PyCObject_FromVoidPtrAndDesc((void *) style, + (char *)"xsltStylesheetPtr", NULL); + + return(ret); +} + +PyObject * +libxslt_xsltTransformContextPtrWrap(xsltTransformContextPtr ctxt) { + PyObject *ret; + +#ifdef DEBUG + printf("libxslt_xsltTransformContextPtrWrap: ctxt = %p\n", ctxt); +#endif + if (ctxt == NULL) { + Py_INCREF(Py_None); + return(Py_None); + } + ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt, + (char *)"xsltTransformContextPtr", NULL); + return(ret); +} + +PyObject * +libxslt_xsltElemPreCompPtrWrap(xsltElemPreCompPtr ctxt) { + PyObject *ret; + +#ifdef DEBUG + printf("libxslt_xsltElemPreCompPtrWrap: ctxt = %p\n", ctxt); +#endif + if (ctxt == NULL) { + Py_INCREF(Py_None); + return(Py_None); + } + ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt, + (char *)"xsltElemPreCompPtr", NULL); + return(ret); +} + +PyObject * +libxslt_xsltGetTransformContextHashCode(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_tctxt; + PyObject *ret; + long hash_code; + xsltTransformContextPtr tctxt; + + if (!PyArg_ParseTuple(args, (char *)"O:getTransformContextHashCode", + &py_tctxt)) + return NULL; + + tctxt = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt); + hash_code = (long) tctxt; + + ret = PyInt_FromLong(hash_code); + return ret; +} + +PyObject * +libxslt_xsltCompareTransformContextsEqual(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + + PyObject *py_tctxt1, *py_tctxt2; + xsltTransformContextPtr tctxt1, tctxt2; + + if (!PyArg_ParseTuple(args, (char *)"OO:compareTransformContextsEqual", + &py_tctxt1, &py_tctxt2)) + return NULL; + + tctxt1 = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt1); + tctxt2 = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt2); + + if ( tctxt1 == tctxt2 ) + return Py_BuildValue((char *)"i", 1); + else + return Py_BuildValue((char *)"i", 0); +} + +PyObject * +libxslt_xsltGetStylesheetHashCode(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_style; + PyObject *ret; + long hash_code; + xsltStylesheetPtr style; + + if (!PyArg_ParseTuple(args, (char *)"O:getStylesheetHashCode", + &py_style)) + return NULL; + + style = (xsltStylesheetPtr) Pystylesheet_Get(py_style); + hash_code = (long) style; + + ret = PyInt_FromLong(hash_code); + return ret; +} + + +PyObject * +libxslt_xsltCompareStylesheetsEqual(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + + PyObject *py_style1, *py_style2; + xsltStylesheetPtr style1, style2; + + if (!PyArg_ParseTuple(args, (char *)"OO:compareStylesheetsEqual", + &py_style1, &py_style2)) + return NULL; + + style1 = (xsltStylesheetPtr) Pystylesheet_Get(py_style1); + style2 = (xsltStylesheetPtr) Pystylesheet_Get(py_style2); + + if ( style1 == style2 ) + return Py_BuildValue((char *)"i", 1); + else + return Py_BuildValue((char *)"i", 0); +} + +/************************************************************************ + * * + * Extending the API * + * * + ************************************************************************/ + +static xmlHashTablePtr libxslt_extModuleFunctions = NULL; +static xmlHashTablePtr libxslt_extModuleElements = NULL; +static xmlHashTablePtr libxslt_extModuleElementPreComp = NULL; + +static void +deallocateCallback(void *payload, xmlChar *name ATTRIBUTE_UNUSED) { + PyObject *function = (PyObject *) payload; + +#ifdef DEBUG_EXTENSIONS + printf("deallocateCallback(%s) called\n", name); +#endif + + Py_XDECREF(function); +} + +static void +deallocateClasse(void *payload, xmlChar *name ATTRIBUTE_UNUSED) { + PyObject *class = (PyObject *) payload; + +#ifdef DEBUG_EXTENSIONS + printf("deallocateClasse(%s) called\n", name); +#endif + + Py_XDECREF(class); +} + + +/** + * libxslt_xsltElementPreCompCallback + * @style: the stylesheet + * @inst: the instruction in the stylesheet + * + * Callback for preprocessing of a custom element + */ +static xsltElemPreCompPtr +libxslt_xsltElementPreCompCallback(xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function) { + xsltElemPreCompPtr ret; + const xmlChar *name; + PyObject *args; + PyObject *result; + PyObject *pyobj_element_f; + PyObject *pyobj_precomp_f; + + const xmlChar *ns_uri; + + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltElementPreCompCallback called\n"); +#endif + + if (style == NULL) { + xsltTransformError(NULL, NULL, inst, + "libxslt_xsltElementPreCompCallback: no transformation context\n"); + return (NULL); + } + + if (inst == NULL) { + xsltTransformError(NULL, style, inst, + "libxslt_xsltElementPreCompCallback: no instruction\n"); + if (style != NULL) style->errors++; + return (NULL); + } + + if (style == NULL) + return (NULL); + + if (inst != NULL && inst->ns != NULL) { + name = inst->name; + ns_uri = inst->ns->href; + } else { + xsltTransformError(NULL, style, inst, + "libxslt_xsltElementPreCompCallback: internal error bad parameter\n"); + printf("libxslt_xsltElementPreCompCallback: internal error bad parameter\n"); + if (style != NULL) style->errors++; + return (NULL); + } + + /* + * Find the functions, they should be there it was there at lookup + */ + pyobj_precomp_f = xmlHashLookup2(libxslt_extModuleElementPreComp, + name, ns_uri); + if (pyobj_precomp_f == NULL) { + xsltTransformError(NULL, style, inst, + "libxslt_xsltElementPreCompCallback: internal error, could not find precompile python function!\n"); + if (style != NULL) style->errors++; + return (NULL); + } + + pyobj_element_f = xmlHashLookup2(libxslt_extModuleElements, + name, ns_uri); + if (pyobj_element_f == NULL) { + xsltTransformError(NULL, style, inst, + "libxslt_xsltElementPreCompCallback: internal error, could not find element python function!\n"); + if (style != NULL) style->errors++; + return (NULL); + } + + args = Py_BuildValue((char *)"(OOO)", + libxslt_xsltStylesheetPtrWrap(style), + libxml_xmlNodePtrWrap(inst), + pyobj_element_f); + + Py_INCREF(pyobj_precomp_f); /* Protect refcount against reentrant manipulation of callback hash */ + result = PyEval_CallObject(pyobj_precomp_f, args); + Py_DECREF(pyobj_precomp_f); + Py_DECREF(args); + + /* FIXME allow callbacks to return meaningful information to modify compile process */ + /* If error, do we need to check the result and throw exception? */ + + Py_XDECREF(result); + + ret = xsltNewElemPreComp (style, inst, function); + return (ret); +} + + +static void +libxslt_xsltElementTransformCallback(xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp) +{ + PyObject *args, *result; + PyObject *func = NULL; + const xmlChar *name; + const xmlChar *ns_uri; + + if (ctxt == NULL) + return; + + if (inst != NULL && inst->name != NULL && inst->ns != NULL && inst->ns->href != NULL) { + name = inst->name; + ns_uri = inst->ns->href; + } else { + printf("libxslt_xsltElementTransformCallback: internal error bad parameter\n"); + return; + } + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltElementTransformCallback called name %s URI %s\n", name, ns_uri); +#endif + + /* + * Find the function, it should be there it was there at lookup + */ + func = xmlHashLookup2(libxslt_extModuleElements, + name, ns_uri); + if (func == NULL) { + printf("libxslt_xsltElementTransformCallback: internal error %s not found !\n", + name); + return; + } + + args = Py_BuildValue((char *)"OOOO", + libxslt_xsltTransformContextPtrWrap(ctxt), + libxml_xmlNodePtrWrap(node), + libxml_xmlNodePtrWrap(inst), + libxslt_xsltElemPreCompPtrWrap(comp)); + + Py_INCREF(func); /* Protect refcount against reentrant manipulation of callback hash */ + result = PyEval_CallObject(func, args); + Py_DECREF(func); + Py_DECREF(args); + + /* FIXME Check result of callobject and set exception if fail */ + + Py_XDECREF(result); +} + +PyObject * +libxslt_xsltRegisterExtModuleElement(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + int ret = 0; + xmlChar *name; + xmlChar *ns_uri; + PyObject *pyobj_element_f; + PyObject *pyobj_precomp_f; + + if (!PyArg_ParseTuple(args, (char *)"szOO:registerExtModuleElement", + &name, &ns_uri, &pyobj_precomp_f, &pyobj_element_f)) + return(NULL); + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltRegisterExtModuleElement called: %s %s\n", + name, ns_uri); +#endif + + if ((name == NULL) || (pyobj_element_f == NULL) || (pyobj_precomp_f == NULL)) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltRegisterExtModuleElement(%s, %s) called\n", + name, ns_uri); +#endif + + if (libxslt_extModuleElements == NULL) + libxslt_extModuleElements = xmlHashCreate(10); + + if (libxslt_extModuleElementPreComp == NULL) + libxslt_extModuleElementPreComp = xmlHashCreate(10); + + if (libxslt_extModuleElements == NULL || libxslt_extModuleElementPreComp == NULL) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + + ret = xmlHashAddEntry2(libxslt_extModuleElements, name, ns_uri, pyobj_element_f); + if (ret != 0) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + Py_XINCREF(pyobj_element_f); + + ret = xmlHashAddEntry2(libxslt_extModuleElementPreComp, name, ns_uri, pyobj_precomp_f); + if (ret != 0) { + xmlHashRemoveEntry2(libxslt_extModuleElements, name, ns_uri, deallocateCallback); + py_retval = libxml_intWrap(-1); + return(py_retval); + } + Py_XINCREF(pyobj_precomp_f); + + ret = xsltRegisterExtModuleElement(name, ns_uri, + libxslt_xsltElementPreCompCallback, + libxslt_xsltElementTransformCallback); + py_retval = libxml_intWrap((int) ret); + return(py_retval); +} +static void +libxslt_xmlXPathFuncCallback(xmlXPathParserContextPtr ctxt, int nargs) { + PyObject *list, *cur, *result; + xmlXPathObjectPtr obj; + xmlXPathContextPtr rctxt; + PyObject *current_function = NULL; + const xmlChar *name; + const xmlChar *ns_uri; + int i; + + if (ctxt == NULL) + return; + rctxt = ctxt->context; + if (rctxt == NULL) + return; + name = rctxt->function; + ns_uri = rctxt->functionURI; +#ifdef DEBUG_XPATH + printf("libxslt_xmlXPathFuncCallback called name %s URI %s\n", name, ns_uri); +#endif + + /* + * Find the function, it should be there it was there at lookup + */ + current_function = xmlHashLookup2(libxslt_extModuleFunctions, + name, ns_uri); + if (current_function == NULL) { + printf("libxslt_xmlXPathFuncCallback: internal error %s not found !\n", + name); + return; + } + + list = PyTuple_New(nargs + 1); + PyTuple_SetItem(list, 0, libxml_xmlXPathParserContextPtrWrap(ctxt)); + for (i = nargs - 1;i >= 0;i--) { + obj = valuePop(ctxt); + cur = libxml_xmlXPathObjectPtrWrap(obj); + PyTuple_SetItem(list, i + 1, cur); + } + + Py_INCREF(current_function); + result = PyEval_CallObject(current_function, list); + Py_DECREF(current_function); + Py_DECREF(list); + + /* Check for null in case of exception */ + if (result != NULL) { + obj = libxml_xmlXPathObjectPtrConvert(result); + valuePush(ctxt, obj); + } +} + +PyObject * +libxslt_xsltRegisterExtModuleFunction(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + int ret = 0; + xmlChar *name; + xmlChar *ns_uri; + PyObject *pyobj_f; + + if (!PyArg_ParseTuple(args, (char *)"szO:registerExtModuleFunction", + &name, &ns_uri, &pyobj_f)) + return(NULL); + + if ((name == NULL) || (pyobj_f == NULL)) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + +#ifdef DEBUG_XPATH + printf("libxslt_xsltRegisterExtModuleFunction(%s, %s) called\n", + name, ns_uri); +#endif + + if (libxslt_extModuleFunctions == NULL) + libxslt_extModuleFunctions = xmlHashCreate(10); + if (libxslt_extModuleFunctions == NULL) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + ret = xmlHashAddEntry2(libxslt_extModuleFunctions, name, ns_uri, pyobj_f); + if (ret != 0) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + Py_XINCREF(pyobj_f); + + ret = xsltRegisterExtModuleFunction(name, ns_uri, + libxslt_xmlXPathFuncCallback); + py_retval = libxml_intWrap((int) ret); + return(py_retval); +} + + +/************************************************************************ + * * + * Document loading front-ends * + * * + ************************************************************************/ + +static PyObject *pythonDocLoaderObject = NULL; + +static xmlDocPtr +pythonDocLoaderFuncWrapper(const xmlChar * URI, xmlDictPtr dict, int options, + void *ctxt ATTRIBUTE_UNUSED, + xsltLoadType type ATTRIBUTE_UNUSED) +{ + xmlParserCtxtPtr pctxt; + xmlDocPtr doc=NULL; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) + return(NULL); + if ((dict != NULL) && (pctxt->dict != NULL)) { + xmlDictFree(pctxt->dict); + pctxt->dict = NULL; + } + if (dict != NULL) { + pctxt->dict = dict; + xmlDictReference(pctxt->dict); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "Reusing dictionary for document\n"); +#endif + } + xmlCtxtUseOptions(pctxt, options); + + /* + * Now pass to python the URI, the xsltParserContext and the context + * (either a transformContext or a stylesheet) and get back an xmlDocPtr + */ + if (pythonDocLoaderObject != NULL) { + PyObject *ctxtobj, *pctxtobj, *result; + pctxtobj = libxml_xmlParserCtxtPtrWrap(pctxt); + + if (type == XSLT_LOAD_DOCUMENT) { + ctxtobj = libxslt_xsltTransformContextPtrWrap(ctxt); + result = PyObject_CallFunction(pythonDocLoaderObject, + (char *) "(sOOi)", URI, pctxtobj, ctxtobj, 0); + } + else { + ctxtobj = libxslt_xsltStylesheetPtrWrap(ctxt); + result = PyObject_CallFunction(pythonDocLoaderObject, + (char *) "(sOOi)", URI, pctxtobj, ctxtobj, 1); + } + + Py_XDECREF(pctxtobj); + + if (result != NULL) { + /* + * The return value should be the document + * Should we test it somehow before getting the C object from it? + */ + PyObject *py_doc = PyObject_GetAttrString(result, (char *) "_o"); + doc = (xmlDocPtr) PyxmlNode_Get(py_doc); + /* do we have to DECCREF the result?? */ + } + } + + if (! pctxt->wellFormed) { + if (doc != NULL) { + xmlFreeDoc(doc); + doc = NULL; + } + if (pctxt->myDoc != NULL) { + xmlFreeDoc(pctxt->myDoc); + pctxt->myDoc = NULL; + } + } + /* + * xmlFreeParserCtxt(pctxt); + * libc complains about double free-ing with this line + */ + + return(doc); +} + + +PyObject * +libxslt_xsltSetLoaderFunc(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + PyObject *loader; + + if (!PyArg_ParseTuple(args, (char *)"O:libxslt_xsltSetLoaderFunc", + &loader)) + return(NULL); + + pythonDocLoaderObject = loader; + xsltSetLoaderFunc(pythonDocLoaderFuncWrapper); + + py_retval = PyInt_FromLong(0); + return(py_retval); +} + +PyObject * +libxslt_xsltGetLoaderFunc(void) { + PyObject *py_retval; + + py_retval = pythonDocLoaderObject; + return(py_retval); +} + + +/************************************************************************ + * * + * Some customized front-ends * + * * + ************************************************************************/ + +PyObject * +libxslt_xsltNewTransformContext(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + PyObject *pyobj_style; + PyObject *pyobj_doc; + xsltStylesheetPtr style; + xmlDocPtr doc; + xsltTransformContextPtr c_retval; + + if (!PyArg_ParseTuple(args, (char *) "OO:xsltNewTransformContext", + &pyobj_style, &pyobj_doc)) + return(NULL); + + style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style); + doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc); + + c_retval = xsltNewTransformContext(style, doc); + py_retval = libxslt_xsltTransformContextPtrWrap((xsltTransformContextPtr) c_retval); + return (py_retval); +} + +PyObject * +libxslt_xsltFreeTransformContext(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_tctxt; + xsltTransformContextPtr tctxt; + + if (!PyArg_ParseTuple(args, (char *) "O:xsltFreeTransformContext", &py_tctxt)) + return(NULL); + + tctxt = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt); + xsltFreeTransformContext(tctxt); + + /* Return None */ + Py_INCREF(Py_None); + return(Py_None); +} + +PyObject * +libxslt_xsltApplyStylesheetUser(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + xmlDocPtr c_retval; + xsltStylesheetPtr style; + PyObject *pyobj_style; + xmlDocPtr doc; + xsltTransformContextPtr transformCtxt; + PyObject *pyobj_doc; + PyObject *pyobj_params; + PyObject *pyobj_transformCtxt; + const char **params = NULL; + int len = 0, i, j; + ssize_t ppos = 0; + PyObject *name; + PyObject *value; + + if (!PyArg_ParseTuple(args, (char *) "OOOO:xsltApplyStylesheetUser", + &pyobj_style, &pyobj_doc, &pyobj_params, &pyobj_transformCtxt)) + return(NULL); + + if (pyobj_params != Py_None) { + if (PyDict_Check(pyobj_params)) { + len = PyDict_Size(pyobj_params); + if (len > 0) { + params = (const char **) xmlMalloc((len + 1) * 2 * + sizeof(char *)); + if (params == NULL) { + printf("libxslt_xsltApplyStylesheet: out of memory\n"); + Py_INCREF(Py_None); + return(Py_None); + } + j = 0; + while (PyDict_Next(pyobj_params, &ppos, &name, &value)) { + const char *tmp; + int size; + + tmp = PyString_AS_STRING(name); + size = PyString_GET_SIZE(name); + params[j * 2] = (char *) xmlCharStrndup(tmp, size); + if (PyString_Check(value)) { + tmp = PyString_AS_STRING(value); + size = PyString_GET_SIZE(value); + params[(j * 2) + 1] = (char *) + xmlCharStrndup(tmp, size); + } else { + params[(j * 2) + 1] = NULL; + } + j = j + 1; + } + params[j * 2] = NULL; + params[(j * 2) + 1] = NULL; + } + } else { + printf("libxslt_xsltApplyStylesheet: parameters not a dict\n"); + Py_INCREF(Py_None); + return(Py_None); + } + } + style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style); + doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc); + transformCtxt = (xsltTransformContextPtr) PytransformCtxt_Get(pyobj_transformCtxt); + + c_retval = xsltApplyStylesheetUser(style, doc, params, NULL, NULL, transformCtxt); + py_retval = libxml_xmlDocPtrWrap((xmlDocPtr) c_retval); + if (params != NULL) { + if (len > 0) { + for (i = 0;i < 2 * len;i++) { + if (params[i] != NULL) + xmlFree((char *)params[i]); + } + xmlFree(params); + } + } + return(py_retval); +} + +PyObject * +libxslt_xsltApplyStylesheet(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + xmlDocPtr c_retval; + xsltStylesheetPtr style; + PyObject *pyobj_style; + xmlDocPtr doc; + PyObject *pyobj_doc; + PyObject *pyobj_params; + const char **params = NULL; + int len = 0, i, j, params_size; + ssize_t ppos = 0; + PyObject *name; + PyObject *value; + + if (!PyArg_ParseTuple(args, (char *) "OOO:xsltApplyStylesheet", + &pyobj_style, &pyobj_doc, &pyobj_params)) + return(NULL); + + if (pyobj_params != Py_None) { + if (PyDict_Check(pyobj_params)) { + len = PyDict_Size(pyobj_params); + if (len > 0) { + params_size = (len + 1) * 2 * sizeof(char *); + params = (const char **) xmlMalloc(params_size); + if (params == NULL) { + printf("libxslt_xsltApplyStylesheet: out of memory\n"); + Py_INCREF(Py_None); + return(Py_None); + } + memset(params, 0, params_size); + j = 0; + while (PyDict_Next(pyobj_params, &ppos, &name, &value)) { + const char *tmp; + int size; + + tmp = PyString_AS_STRING(name); + size = PyString_GET_SIZE(name); + params[j * 2] = (char *) xmlCharStrndup(tmp, size); + if (PyString_Check(value)) { + tmp = PyString_AS_STRING(value); + size = PyString_GET_SIZE(value); + params[(j * 2) + 1] = (char *) + xmlCharStrndup(tmp, size); + } else { + params[(j * 2) + 1] = NULL; + } + j = j + 1; + } + params[j * 2] = NULL; + params[(j * 2) + 1] = NULL; + } + } else { + printf("libxslt_xsltApplyStylesheet: parameters not a dict\n"); + Py_INCREF(Py_None); + return(Py_None); + } + } + style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style); + doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc); + + c_retval = xsltApplyStylesheet(style, doc, params); + py_retval = libxml_xmlDocPtrWrap((xmlDocPtr) c_retval); + if (params != NULL) { + if (len > 0) { + for (i = 0;i < 2 * len;i++) { + if (params[i] != NULL) + xmlFree((char *)params[i]); + } + xmlFree(params); + } + } + return(py_retval); +} + +PyObject * +libxslt_xsltSaveResultToString(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; /* our final return value, a python string */ + xmlChar *buffer; + int size = 0; + int emitted = 0; + xmlDocPtr result; + PyObject *pyobj_result; + xsltStylesheetPtr style; + PyObject *pyobj_style; + + if (!PyArg_ParseTuple(args, (char *)"OO:xsltSaveResultToString", &pyobj_style, &pyobj_result)) + goto FAIL; + result = (xmlDocPtr) PyxmlNode_Get(pyobj_result); + style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style); + + + /* FIXME: We should probably add more restrictive error checking + * and raise an error instead of "just" returning NULL. + * FIXME: Documentation and code for xsltSaveResultToString diff + * -> emmitted will never be positive non-null. + */ + emitted = xsltSaveResultToString(&buffer, &size, result, style); + if(!buffer || emitted < 0) + goto FAIL; + /* We haven't tested the aberrant case of a transformation that + * renders to an empty string. For now we try to play it safe. + */ + if(size) + { + buffer[size] = '\0'; + py_retval = PyString_FromString((char *) buffer); + xmlFree(buffer); + } + else + py_retval = PyString_FromString(""); + return(py_retval); + FAIL: + return(0); +} + + +/************************************************************************ + * * + * Error message callback * + * * + ************************************************************************/ + +static PyObject *libxslt_xsltPythonErrorFuncHandler = NULL; +static PyObject *libxslt_xsltPythonErrorFuncCtxt = NULL; + +static void +libxslt_xsltErrorFuncHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, + ...) +{ + int size; + int chars; + char *larger; + va_list ap; + char *str; + PyObject *list; + PyObject *message; + PyObject *result; + +#ifdef DEBUG_ERROR + printf("libxslt_xsltErrorFuncHandler(%p, %s, ...) called\n", ctx, msg); +#endif + + + if (libxslt_xsltPythonErrorFuncHandler == NULL) { + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + } else { + str = (char *) xmlMalloc(150); + if (str == NULL) + return; + + size = 150; + + while (1) { + va_start(ap, msg); + chars = vsnprintf(str, size, msg, ap); + va_end(ap); + if ((chars > -1) && (chars < size)) + break; + if (chars > -1) + size += chars + 1; + else + size += 100; + if ((larger = (char *) xmlRealloc(str, size)) == NULL) { + xmlFree(str); + return; + } + str = larger; + } + + list = PyTuple_New(2); + PyTuple_SetItem(list, 0, libxslt_xsltPythonErrorFuncCtxt); + Py_XINCREF(libxslt_xsltPythonErrorFuncCtxt); + message = libxml_charPtrWrap(str); + PyTuple_SetItem(list, 1, message); + result = PyEval_CallObject(libxslt_xsltPythonErrorFuncHandler, list); + Py_XDECREF(list); + Py_XDECREF(result); + } +} + +static void +libxslt_xsltErrorInitialize(void) +{ +#ifdef DEBUG_ERROR + printf("libxslt_xsltErrorInitialize() called\n"); +#endif + xmlSetGenericErrorFunc(NULL, libxslt_xsltErrorFuncHandler); + xsltSetGenericErrorFunc(NULL, libxslt_xsltErrorFuncHandler); +} + +PyObject * +libxslt_xsltRegisterErrorHandler(PyObject * self ATTRIBUTE_UNUSED, + PyObject * args) +{ + PyObject *py_retval; + PyObject *pyobj_f; + PyObject *pyobj_ctx; + + if (!PyArg_ParseTuple + (args, (char *) "OO:xmlRegisterErrorHandler", &pyobj_f, + &pyobj_ctx)) + return (NULL); + +#ifdef DEBUG_ERROR + printf("libxml_registerXPathFunction(%p, %p) called\n", pyobj_ctx, + pyobj_f); +#endif + + if (libxslt_xsltPythonErrorFuncHandler != NULL) { + Py_XDECREF(libxslt_xsltPythonErrorFuncHandler); + } + if (libxslt_xsltPythonErrorFuncCtxt != NULL) { + Py_XDECREF(libxslt_xsltPythonErrorFuncCtxt); + } + + Py_XINCREF(pyobj_ctx); + Py_XINCREF(pyobj_f); + + /* TODO: check f is a function ! */ + libxslt_xsltPythonErrorFuncHandler = pyobj_f; + libxslt_xsltPythonErrorFuncCtxt = pyobj_ctx; + + py_retval = libxml_intWrap(1); + return (py_retval); +} + +/************************************************************************ + * * + * Extension classes * + * * + ************************************************************************/ + +static xmlHashTablePtr libxslt_extModuleClasses = NULL; + +static void * +libxslt_xsltPythonExtModuleStyleInit(xsltStylesheetPtr style, + const xmlChar * URI) { + PyObject *result = NULL; + PyObject *class = NULL; + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltPythonExtModuleStyleInit(%p, %s) called\n", + style, URI); +#endif + + if ((style == NULL) || (URI == NULL)) + return(NULL); + + /* + * Find the function, it should be there it was there at lookup + */ + class = xmlHashLookup(libxslt_extModuleClasses, URI); + if (class == NULL) { + fprintf(stderr, "libxslt_xsltPythonExtModuleStyleInit: internal error %s not found !\n", URI); + return(NULL); + } + + if (PyObject_HasAttrString(class, (char *) "_styleInit")) { + result = PyObject_CallMethod(class, (char *) "_styleInit", + (char *) "Os", libxslt_xsltStylesheetPtrWrap(style), URI); + } + return((void *)result); +} +static void +libxslt_xsltPythonExtModuleStyleShutdown(xsltStylesheetPtr style, + const xmlChar * URI, void *data) { + PyObject *class = NULL; + PyObject *result; + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltPythonExtModuleStyleShutdown(%p, %s, %p) called\n", + style, URI, data); +#endif + + if ((style == NULL) || (URI == NULL)) + return; + + /* + * Find the function, it should be there it was there at lookup + */ + class = xmlHashLookup(libxslt_extModuleClasses, URI); + if (class == NULL) { + fprintf(stderr, "libxslt_xsltPythonExtModuleStyleShutdown: internal error %s not found !\n", URI); + return; + } + + if (PyObject_HasAttrString(class, (char *) "_styleShutdown")) { + result = PyObject_CallMethod(class, (char *) "_styleShutdown", + (char *) "OsO", libxslt_xsltStylesheetPtrWrap(style), + URI, (PyObject *) data); + Py_XDECREF(result); + Py_XDECREF((PyObject *)data); + } +} + +static void * +libxslt_xsltPythonExtModuleCtxtInit(xsltTransformContextPtr ctxt, + const xmlChar * URI) { + PyObject *result = NULL; + PyObject *class = NULL; + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltPythonExtModuleCtxtInit(%p, %s) called\n", + ctxt, URI); +#endif + + if ((ctxt == NULL) || (URI == NULL)) + return(NULL); + + /* + * Find the function, it should be there it was there at lookup + */ + class = xmlHashLookup(libxslt_extModuleClasses, URI); + if (class == NULL) { + fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtInit: internal error %s not found !\n", URI); + return(NULL); + } + + if (PyObject_HasAttrString(class, (char *) "_ctxtInit")) { + result = PyObject_CallMethod(class, (char *) "_ctxtInit", + (char *) "Os", libxslt_xsltTransformContextPtrWrap(ctxt), + URI); + } + return((void *)result); +} +static void +libxslt_xsltPythonExtModuleCtxtShutdown(xsltTransformContextPtr ctxt, + const xmlChar * URI, void *data) { + PyObject *class = NULL; + PyObject *result; + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltPythonExtModuleCtxtShutdown(%p, %s, %p) called\n", + ctxt, URI, data); +#endif + + if ((ctxt == NULL) || (URI == NULL)) + return; + + /* + * Find the function, it should be there it was there at lookup + */ + class = xmlHashLookup(libxslt_extModuleClasses, URI); + if (class == NULL) { + fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtShutdown: internal error %s not found !\n", URI); + return; + } + + if (PyObject_HasAttrString(class, (char *) "_ctxtShutdown")) { + result = PyObject_CallMethod(class, (char *) "_ctxtShutdown", + (char *) "OsO", libxslt_xsltTransformContextPtrWrap(ctxt), + URI, (PyObject *) data); + Py_XDECREF(result); + Py_XDECREF((PyObject *)data); + } +} + +PyObject * +libxslt_xsltRegisterExtensionClass(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + int ret = 0; + xmlChar *ns_uri; + PyObject *pyobj_c; + + if (!PyArg_ParseTuple(args, (char *)"zO:registerExtensionClass", + &ns_uri, &pyobj_c)) + return(NULL); + + if ((ns_uri == NULL) || (pyobj_c == NULL)) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + +#ifdef DEBUG_EXTENSIONS + printf("libxslt_xsltRegisterExtensionClass(%s) called\n", ns_uri); +#endif + + if (libxslt_extModuleClasses == NULL) + libxslt_extModuleClasses = xmlHashCreate(10); + if (libxslt_extModuleClasses == NULL) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + ret = xmlHashAddEntry(libxslt_extModuleClasses, ns_uri, pyobj_c); + if (ret != 0) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + Py_XINCREF(pyobj_c); + + ret = xsltRegisterExtModuleFull(ns_uri, + (xsltExtInitFunction) libxslt_xsltPythonExtModuleCtxtInit, + (xsltExtShutdownFunction) libxslt_xsltPythonExtModuleCtxtShutdown, + (xsltStyleExtInitFunction) libxslt_xsltPythonExtModuleStyleInit, + (xsltStyleExtShutdownFunction) libxslt_xsltPythonExtModuleStyleShutdown); + py_retval = libxml_intWrap((int) ret); + if (ret < 0) { + Py_XDECREF(pyobj_c); + } + return(py_retval); +} + +/************************************************************************ + * * + * Integrated cleanup * + * * + ************************************************************************/ + +PyObject * +libxslt_xsltPythonCleanup(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args ATTRIBUTE_UNUSED) { + + if (libxslt_extModuleFunctions != NULL) { + xmlHashFree(libxslt_extModuleFunctions, deallocateCallback); + } + if (libxslt_extModuleElements != NULL) { + xmlHashFree(libxslt_extModuleElements, deallocateCallback); + } + if (libxslt_extModuleElementPreComp != NULL) { + xmlHashFree(libxslt_extModuleElementPreComp, deallocateCallback); + } + if (libxslt_extModuleClasses != NULL) { + xmlHashFree(libxslt_extModuleClasses, deallocateClasse); + } + xsltCleanupGlobals(); + Py_INCREF(Py_None); + return(Py_None); +} + +/************************************************************************ + * * + * The registration stuff * + * * + ************************************************************************/ +static PyMethodDef libxsltMethods[] = { +#include "libxslt-export.c" + { NULL, NULL, 0, NULL } +}; + +#ifdef MERGED_MODULES +extern void initlibxml2mod(void); +#endif + +void initlibxsltmod(void) { + static int initialized = 0; + PyObject *m; + +#ifdef MERGED_MODULES + initlibxml2mod(); +#endif + + if (initialized != 0) + return; + m = Py_InitModule((char *)"libxsltmod", libxsltMethods); + initialized = 1; + /* + * Specific XSLT initializations + */ + libxslt_xsltErrorInitialize(); + xmlInitMemory(); + xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + xmlDefaultSAXHandler.cdataBlock = NULL; + /* + * Register the EXSLT extensions and the test module + */ + exsltRegisterAll(); +} + + diff --git a/libxslt/python/libxslt_wrap.h b/libxslt/python/libxslt_wrap.h new file mode 100644 index 0000000..d1c7907 --- /dev/null +++ b/libxslt/python/libxslt_wrap.h @@ -0,0 +1,49 @@ +#include "libxml_wrap.h" +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/xsltutils.h> +#include <libxslt/attributes.h> +#include <libxslt/documents.h> +#include <libxslt/extensions.h> +#include <libxslt/extra.h> +#include <libxslt/functions.h> +#include <libxslt/imports.h> +#include <libxslt/keys.h> +#include <libxslt/namespaces.h> +#include <libxslt/numbersInternals.h> +#include <libxslt/pattern.h> +#include <libxslt/preproc.h> +#include <libxslt/templates.h> +#include <libxslt/transform.h> +#include <libxslt/variables.h> +#include <libxslt/xsltconfig.h> + +#define Pystylesheet_Get(v) (((v) == Py_None) ? NULL : \ + (((Pystylesheet_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xsltStylesheetPtr obj; +} Pystylesheet_Object; + +#define PytransformCtxt_Get(v) (((v) == Py_None) ? NULL : \ + (((PytransformCtxt_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xsltTransformContextPtr obj; +} PytransformCtxt_Object; + +#define PycompiledStyle_Get(v) (((v) == Py_None) ? NULL : \ + (((PycompiledStyle_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + xsltTransformContextPtr obj; +} PycompiledStyle_Object; + + +PyObject * libxslt_xsltStylesheetPtrWrap(xsltStylesheetPtr ctxt); +PyObject * libxslt_xsltTransformContextPtrWrap(xsltTransformContextPtr ctxt); +PyObject * libxslt_xsltStylePreCompPtrWrap(xsltStylePreCompPtr comp); +PyObject * libxslt_xsltElemPreCompPtrWrap(xsltElemPreCompPtr comp); diff --git a/libxslt/python/libxsltclass.txt b/libxslt/python/libxsltclass.txt new file mode 100644 index 0000000..e1ffdb6 --- /dev/null +++ b/libxslt/python/libxsltclass.txt @@ -0,0 +1,238 @@ + Generated Classes for libxslt-python + +# +# Global functions of the module +# + + +# functions from module extensions +debugDumpExtensions() +initGlobals() +registerTestModule() +unregisterExtModule() +unregisterExtModuleElement() +unregisterExtModuleFunction() +unregisterExtModuleTopLevel() + +# functions from module extra +registerAllExtras() + +# functions from module python +pythonCleanup() +registerErrorHandler() +registerExtModuleElement() +registerExtModuleFunction() +registerExtensionClass() +setLoaderFunc() + +# functions from module xslt +cleanupGlobals() +init() + +# functions from module xsltInternals +isBlank() +loadStylesheetPI() +newStylesheet() +parseStylesheetDoc() +parseStylesheetFile() +uninit() + +# functions from module xsltlocale +freeLocales() + +# functions from module xsltutils +calibrateAdjust() +debuggerStatus() +nsProp() +setDebuggerStatus() +timestamp() +xslDropCall() + + +# +# Set of classes of the module +# + + + +Class xpathParserContext(libxml2.xpathParserContext) + # accessors + context() + + # functions from module extra + functionNodeSet() + + # functions from module functions + documentFunction() + elementAvailableFunction() + formatNumberFunction() + functionAvailableFunction() + generateIdFunction() + keyFunction() + systemPropertyFunction() + unparsedEntityURIFunction() + + +Class xpathContext(libxml2.xpathContext) + # accessors + transformContext() + + # functions from module functions + registerAllFunctions() + + +Class transformCtxt(transformCtxtBase) + # accessors + context() + current() + insertNode() + instruction() + mode() + modeURI() + outputDoc() + outputURI() + style() + + # functions from module attributes + applyAttributeSet() + + # functions from module documents + freeDocuments() + + # functions from module extensions + freeCtxtExts() + initCtxtExts() + shutdownCtxtExts() + + # functions from module extra + debug() + registerExtras() + + # functions from module imports + findElemSpaceHandling() + needElemSpaceHandling() + + # functions from module namespaces + copyNamespace() + copyNamespaceList() + namespace() + plainNamespace() + specialNamespace() + + # functions from module python + compareTransformContextsEqual() + freeTransformContext() + transformContextHashCode() + + # functions from module templates + attrListTemplateProcess() + attrTemplateProcess() + attrTemplateValueProcess() + attrTemplateValueProcessNode() + evalAttrValueTemplate() + evalTemplateString() + + # functions from module variables + evalGlobalVariables() + evalOneUserParam() + freeGlobalVariables() + parseStylesheetParam() + parseStylesheetVariable() + quoteOneUserParam() + variableLookup() + + # functions from module xsltInternals + allocateExtraCtxt() + createRVT() + extensionInstructionResultFinalize() + freeRVTs() + initAllDocKeys() + registerLocalRVT() + registerPersistRVT() + registerTmpRVT() + releaseRVT() + + # functions from module xsltutils + message() + printErrorContext() + profileInformation() + saveProfiling() + setCtxtParseOptions() + + +Class stylesheet(stylesheetBase) + # accessors + doc() + doctypePublic() + doctypeSystem() + encoding() + imports() + method() + methodURI() + next() + parent() + version() + + # functions from module attributes + freeAttributeSetsHashes() + parseStylesheetAttributeSet() + resolveStylesheetAttributeSet() + + # functions from module documents + freeStyleDocuments() + + # functions from module extensions + checkExtPrefix() + checkExtURI() + freeExts() + registerExtPrefix() + shutdownExts() + + # functions from module imports + nextImport() + parseStylesheetImport() + parseStylesheetInclude() + + # functions from module keys + addKey() + freeKeys() + + # functions from module namespaces + freeNamespaceAliasHashes() + namespaceAlias() + + # functions from module pattern + cleanupTemplates() + freeTemplateHashes() + + # functions from module preproc + freeStylePreComps() + stylePreCompute() + + # functions from module python + applyStylesheet() + applyStylesheetUser() + compareStylesheetsEqual() + newTransformContext() + saveResultToString() + stylesheetHashCode() + + # functions from module variables + parseGlobalParam() + parseGlobalVariable() + + # functions from module xsltInternals + allocateExtra() + compileAttr() + freeStylesheet() + parseStylesheetImportedDoc() + parseStylesheetOutput() + parseStylesheetProcess() + parseTemplateContent() + + # functions from module xsltutils + cNsProp() + printErrorContext() + saveResultToFd() + saveResultToFile() + saveResultToFilename() diff --git a/libxslt/python/tests/Makefile.am b/libxslt/python/tests/Makefile.am new file mode 100644 index 0000000..f757774 --- /dev/null +++ b/libxslt/python/tests/Makefile.am @@ -0,0 +1,34 @@ +EXAMPLE_DIR = $(datadir)/doc/libxslt-python-$(LIBXSLT_VERSION)/examples + +TESTSPY= \ + basic.py \ + exslt.py \ + extelem.py \ + extfunc.py + +XMLS= \ + test.xml \ + test.xsl + +EXTRAS= \ + pyxsltproc.py + +EXTRA_DIST = $(TESTSPY) $(XMLS) $(EXTRAS) + +CLEANFILES = *.pyc core + +if WITH_PYTHON +tests: $(TESTSPY) + -@(PYTHONPATH="`pwd`/..:`pwd`/../.libs:$(srcdir)/.."; \ + if test "x$(LIBXML_SRC)" != "x" ; then PYTHONPATH="$$PYTHONPATH:$(LIBXML_SRC)/python:$(LIBXML_SRC)/python/.libs"; fi; \ + export PYTHONPATH; \ + for test in $(TESTSPY) ; do echo "-- $$test" ; (cd $(srcdir) && $(PYTHON) $$test ); done) +else +tests: +endif + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(EXAMPLE_DIR) + -(for test in $(TESTSPY) $(XMLS) $(EXTRAS); \ + do $(INSTALL) -m 0644 $(srcdir)/$$test $(DESTDIR)$(EXAMPLE_DIR) ; done) + diff --git a/libxslt/python/tests/basic.py b/libxslt/python/tests/basic.py new file mode 100755 index 0000000..89a57ac --- /dev/null +++ b/libxslt/python/tests/basic.py @@ -0,0 +1,29 @@ +#!/usr/bin/python -u +import sys +import libxml2 +# Memory debug specific +libxml2.debugMemory(1) +import libxslt + + + +styledoc = libxml2.parseFile("test.xsl") +style = libxslt.parseStylesheetDoc(styledoc) +doc = libxml2.parseFile("test.xml") +result = style.applyStylesheet(doc, None) +style.saveResultToFilename("foo", result, 0) +stringval = style.saveResultToString(result) +if (len(stringval) != 68): + print "Error in saveResultToString" + sys.exit(255) +style.freeStylesheet() +doc.freeDoc() +result.freeDoc() + +# Memory debug specific +libxslt.cleanup() +if libxml2.debugMemory(1) == 0: + print "OK" +else: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory() diff --git a/libxslt/python/tests/exslt.py b/libxslt/python/tests/exslt.py new file mode 100755 index 0000000..c64b2e4 --- /dev/null +++ b/libxslt/python/tests/exslt.py @@ -0,0 +1,56 @@ +#!/usr/bin/python -u +import sys +import libxml2 +# Memory debug specific +libxml2.debugMemory(1) +import libxslt + + +styledoc = libxml2.parseDoc( +"""<?xml version="1.0"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:str="http://exslt.org/strings" + exclude-result-prefixes="str"> + +<xsl:template match="/"> +<out>; + str:tokenize('2001-06-03T11:40:23', '-T:') + <xsl:copy-of select="str:tokenize('2001-06-03T11:40:23', '-T:')"/>; + + str:tokenize('date math str') + <xsl:copy-of select="str:tokenize('date math str')"/>; +</out> +</xsl:template> + +</xsl:stylesheet> +""") +style = libxslt.parseStylesheetDoc(styledoc) +doc = libxml2.parseDoc("<doc/>") +result = style.applyStylesheet(doc, None) +stringval = style.saveResultToString(result) +style.freeStylesheet() +doc.freeDoc() +result.freeDoc() + +expect="""<?xml version="1.0"?> +<out>; + str:tokenize('2001-06-03T11:40:23', '-T:') + <token>2001</token><token>06</token><token>03</token><token>11</token><token>40</token><token>23</token>; + + str:tokenize('date math str') + <token>date</token><token>math</token><token>str</token>; +</out> +""" + +if stringval != expect: + print "Exslt processing failed" + sys.exit(255) + +# Memory debug specific +libxslt.cleanup() +if libxml2.debugMemory(1) == 0: + print "OK" +else: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory() diff --git a/libxslt/python/tests/extelem.py b/libxslt/python/tests/extelem.py new file mode 100644 index 0000000..3364d01 --- /dev/null +++ b/libxslt/python/tests/extelem.py @@ -0,0 +1,89 @@ +#!/usr/bin/python -u +import sys +import string +import StringIO +import libxml2 +# Memory debug specific +libxml2.debugMemory(1) +import libxslt + +EXT_URL="http://example.com/foo" + +insertNodeName = None +transformNodeName = None + +def compile_test(style, inst, func): + pass + +def transform_test(ctx, node, inst, comp): + global insertNodeName + + # + # Small check to verify the context is correcly accessed + # + try: + # + # FIXME add some more sanity checks + # + tctxt = libxslt.transformCtxt(_obj=ctx) + insertNodeName = tctxt.insertNode().name + + # FIXME find and confirm the note being replaced is called 'test' + # transformNodeName = libxml2.xmlNode(inst).name + except: + pass + + tctxt.insertNode().addContent('SUCCESS') + + + +styledoc = libxml2.parseDoc(""" +<xsl:stylesheet version='1.0' + xmlns:xsl='http://www.w3.org/1999/XSL/Transform' + xmlns:foo='%s' + extension-element-prefixes='foo'> + + <xsl:template match='/'> + <article><foo:test>FAILURE</foo:test></article> + <deeper><article><foo:test>something<foo:test>nested</foo:test>even</foo:test></article></deeper> + </xsl:template> +</xsl:stylesheet> +""" % EXT_URL) + +style = libxslt.parseStylesheetDoc(styledoc) +libxslt.registerExtModuleElement("test", EXT_URL, compile_test, transform_test) +doc = libxml2.parseDoc("<doc/>") +result = style.applyStylesheet(doc, None) +style.freeStylesheet() +doc.freeDoc() + + +extensions = StringIO.StringIO() +libxslt.debugDumpExtensions(extensions) + +if 0 and extensions.buf.find(EXT_URL) < 0: + print "Element extension not registered (or dumping broken)" + sys.exit(1) + +root = result.children + +if root.name != "article": + print "Unexpected root node name" + sys.exit(1) +if root.content != "SUCCESS": + print "Unexpected root node content, extension function failed" + sys.exit(1) +if insertNodeName != 'article': + print "The function callback failed to access its context" + sys.exit(1) + +result.dump(sys.stdout) +result.freeDoc() + +# Memory debug specific +libxslt.cleanup() +if libxml2.debugMemory(1) == 0: + print "OK" +else: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory() diff --git a/libxslt/python/tests/extfunc.py b/libxslt/python/tests/extfunc.py new file mode 100755 index 0000000..0a55953 --- /dev/null +++ b/libxslt/python/tests/extfunc.py @@ -0,0 +1,66 @@ +#!/usr/bin/python -u +import sys +import string +import libxml2 +# Memory debug specific +libxml2.debugMemory(1) +import libxslt + +nodeName = None + +def f(ctx, str): + global nodeName + + # + # Small check to verify the context is correcly accessed + # + try: + pctxt = libxslt.xpathParserContext(_obj=ctx) + ctxt = pctxt.context() + tctxt = ctxt.transformContext() + nodeName = tctxt.insertNode().name + except: + pass + + return string.upper(str) + +libxslt.registerExtModuleFunction("foo", "http://example.com/foo", f) + +styledoc = libxml2.parseDoc(""" +<xsl:stylesheet version='1.0' + xmlns:xsl='http://www.w3.org/1999/XSL/Transform' + xmlns:foo='http://example.com/foo' + exclude-result-prefixes='foo'> + + <xsl:param name='bar'>failure</xsl:param> + <xsl:template match='/'> + <article><xsl:value-of select='foo:foo($bar)'/></article> + </xsl:template> +</xsl:stylesheet> +""") +style = libxslt.parseStylesheetDoc(styledoc) +doc = libxml2.parseDoc("<doc/>") +result = style.applyStylesheet(doc, { "bar": "'success'" }) +style.freeStylesheet() +doc.freeDoc() + +root = result.children +if root.name != "article": + print "Unexpected root node name" + sys.exit(1) +if root.content != "SUCCESS": + print "Unexpected root node content, extension function failed" + sys.exit(1) +if nodeName != 'article': + print "The function callback failed to access its context" + sys.exit(1) + +result.freeDoc() + +# Memory debug specific +libxslt.cleanup() +if libxml2.debugMemory(1) == 0: + print "OK" +else: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory() diff --git a/libxslt/python/tests/pyxsltproc.py b/libxslt/python/tests/pyxsltproc.py new file mode 100755 index 0000000..238fa5b --- /dev/null +++ b/libxslt/python/tests/pyxsltproc.py @@ -0,0 +1,298 @@ +#!/usr/bin/python -u +# +# The exercise of rewriting xsltproc on top of the python +# bindings, not complete yet and shows up the things missing +# from the existing python interfaces +# +import sys +import time +import os +import string +import libxml2 +# Memory debug specific +libxml2.debugMemory(1) +import libxslt + +debug = 0 +repeat = 0 +timing = 0 +novalid = 0 +noout = 0 +docbook = 0 +html = 0 +xinclude = 0 +profile = 0 +params = {} +output = None +errorno = 0 + +# +# timing +# +begin = 0 +endtime = 0 +def startTimer(): + global begin + + begin = time.time() + +def endTimer(msg): + global begin + global endtime + + endtime = time.time() + print "%s took %d ms" % (msg, (endtime - begin) * 1000) + +def xsltProcess(doc, cur, filename): + global timing + global xinclude + global params + global html + + if xinclude: + if timing: + startTimer() + doc.XIncludeProcess() + if timing: + endTimer("XInclude processing %s" % (filename)) + + if timing: + startTimer() + if output == None: + if repeat != 0: + for j in range(1, repeat): + res = cur.applyStylesheet(doc, params) + res.freeDoc() + doc.freeDoc() + if html == 1: + doc = libxml2.htmlParseFile(filename, None) + else: + doc = libxml2.parseFile(filename, None) +# ctxt = libxslt.newTransformContext(doc) +# if ctxt == None: +# return + if profile: + print "TODO: Profiling not yet supported" + else: + res = cur.applyStylesheet(doc, params) + if timing: + if repeat != 0: + endTimer("Applying stylesheet %d times" % (repeat)) + else: + endTimer("Applying stylesheet") + doc.freeDoc() + if res == None: + print "no result for %s" % (filename) + return + if noout != 0: + res.freeDoc() + return + if debug == 1: + res.debugDumpDocument(None) + else: + if timing: + startTimer() + cur.saveResultToFilename("-", res, 0) + if timing: + endTimer("Saving result") + res.freeDoc() + else: + print "TODO: xsltRunStylesheet not yet mapped" + +def usage(name = 'pyxsltproc'): + print "Usage: %s [options] stylesheet file [file ...]" % (name) + print "a reimplementation of xsltproc(1) on top of libxslt-python" + print " Options:" + print "\t--version or -V: show the version of libxml and libxslt used" + print "\t--verbose or -v: show logs of what's happening" + print "\t--output file or -o file: save to a given file" + print "\t--timing: display the time used" + print "\t--repeat: run the transformation 20 times" + print "\t--debug: dump the tree of the result instead" + print "\t--novalid skip the Dtd loading phase" + print "\t--noout: do not dump the result" + print "\t--maxdepth val : increase the maximum depth" + print "\t--html: the input document is(are) an HTML file(s)" + print "\t--param name value : pass a (parameter,value) pair" + print "\t value is an XPath expression." + print "\t string values must be quoted like \"'string'\"" + print "\t or use stringparam to avoid it" + print "\t--stringparam name value : pass a (parameter,string value) pair" + print "\t--nonet refuse to fetch DTDs or entities over network" + print "\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES" + print "\t otherwise XML Catalogs starting from " + print "\t file:///etc/xml/catalog are activated by default" + print "\t--xinclude : do XInclude processing on document input" + print "\t--profile or --norman : dump profiling informations " + print "\nProject libxslt home page: http://xmlsoft.org/XSLT/" + print "To report bugs and get help: http://xmlsoft.org/XSLT/bugs.html" + +def main(args = None): + global debug + global repeat + global timing + global novalid + global noout + global docbook + global html + global xinclude + global profile + global params + global output + global errorno + + done = 0 + cur = None + + if not args: + args = sys.argv[1:] + if len(args) <= 0: + usage(sys.argv[0]) + + + i = 0 + while i < len(args): + if args[i] == "-": + break + if args[i][0] != '-': + i = i + 1 + continue + if args[i] == "-timing" or args[i] == "--timing": + timing = 1 + elif args[i] == "-debug" or args[i] == "--debug": + debug = 1 + elif args[i] == "-verbose" or args[i] == "--verbose" or \ + args[i] == "-v": + print "TODO: xsltSetGenericDebugFunc() mapping missing" + elif args[i] == "-version" or args[i] == "--version" or \ + args[i] == "-V": + print "TODO: version informations mapping missing" + elif args[i] == "-verbose" or args[i] == "--verbose" or \ + args[i] == "-v": + if repeat == 0: + repeat = 20 + else: + repeat = 100 + elif args[i] == "-novalid" or args[i] == "--novalid": + print "TODO: xmlLoadExtDtdDefaultValue mapping missing" + novalid = 1 + elif args[i] == "-noout" or args[i] == "--noout": + noout = 1 + elif args[i] == "-html" or args[i] == "--html": + html = 1 + elif args[i] == "-nonet" or args[i] == "--nonet": + print "TODO: xmlSetExternalEntityLoader mapping missing" + nonet = 1 + elif args[i] == "-catalogs" or args[i] == "--catalogs": + try: + catalogs = os.environ['SGML_CATALOG_FILES'] + except: + catalogs = None + if catalogs != none: + libxml2.xmlLoadCatalogs(catalogs) + else: + print "Variable $SGML_CATALOG_FILES not set" + elif args[i] == "-xinclude" or args[i] == "--xinclude": + xinclude = 1 + libxslt.setXIncludeDefault(1) + elif args[i] == "-param" or args[i] == "--param": + i = i + 1 + params[args[i]] = args[i + 1] + i = i + 1 + elif args[i] == "-stringparam" or args[i] == "--stringparam": + i = i + 1 + params[args[i]] = "'%s'" % (args[i + 1]) + i = i + 1 + elif args[i] == "-maxdepth" or args[i] == "--maxdepth": + print "TODO: xsltMaxDepth mapping missing" + else: + print "Unknown option %s" % (args[i]) + usage() + return(3) + + + + + i = i + 1 + + libxml2.lineNumbersDefault(1) + libxml2.substituteEntitiesDefault(1) + # TODO: xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS + # if novalid: + # TODO: xmlLoadExtDtdDefaultValue = 0 + + # TODO libxslt.exsltRegisterAll(); + libxslt.registerTestModule() + + i = 0 + while i < len(args) and done == 0: + if args[i] == "-maxdepth" or args[i] == "--maxdepth": + i = i + 2 + continue + if args[i] == "-o" or args[i] == "-output" or args[i] == "--output": + i = i + 2 + continue + if args[i] == "-param" or args[i] == "--param": + i = i + 3 + continue + if args[i] == "-stringparam" or args[i] == "--stringparam": + i = i + 3 + continue + if args[i] != "-" and args[i][0] == '-': + i = i + 1 + continue + if timing: + startTimer() + style = libxml2.parseFile(args[i]) + if timing: + endTimer("Parsing stylesheet %s" % (args[i])) + if style == None: + print "cannot parse %s" % (args[i]) + cur = None + errorno = 4 + done = 1 + else: + cur = libxslt.loadStylesheetPI(style) + if cur != None: + xsltProcess(style, cur, args[i]) + cur = None + else: + cur = libxslt.parseStylesheetDoc(style) + if cur == None: + style.freeDoc() + errorno = 5 + done = 1 + i = i + 1 + break + + while i < len(args) and done == 0 and cur != None: + if timing: + startTimer() + if html: + doc = libxml2.htmlParseFile(args[i], None) + else: + doc = libxml2.parseFile(args[i]) + if doc == None: + print "unable to parse %s" % (args[i]) + errorno = 6 + i = i + 1 + continue + if timing: + endTimer("Parsing document %s" % (args[i])) + xsltProcess(doc, cur, args[i]) + i = i + 1 + + if cur != None: + cur.freeStylesheet() + params = None + +if __name__ == "__main__": + main() + +# Memory debug specific +libxslt.cleanup() +if libxml2.debugMemory(1) != 0: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory() + +sys.exit(errorno) diff --git a/libxslt/python/tests/test.xml b/libxslt/python/tests/test.xml new file mode 100644 index 0000000..24110d9 --- /dev/null +++ b/libxslt/python/tests/test.xml @@ -0,0 +1 @@ +<test/> diff --git a/libxslt/python/tests/test.xsl b/libxslt/python/tests/test.xsl new file mode 100644 index 0000000..8d6ae3f --- /dev/null +++ b/libxslt/python/tests/test.xsl @@ -0,0 +1,9 @@ +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + + <xsl:template match="/"> + <article> + <title>Hello World</title> + </article> + </xsl:template> +</xsl:stylesheet> diff --git a/libxslt/python/types.c b/libxslt/python/types.c new file mode 100644 index 0000000..1beee75 --- /dev/null +++ b/libxslt/python/types.c @@ -0,0 +1,602 @@ +/* +xmlParserInputPtr xmlNoNetExternalEntityLoader(const char *URL, + const char *ID, + xmlParserCtxtPtr ctxt); + + * types.c: converter functions between the internal representation + * and the Python objects + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ +#include "libxml_wrap.h" +#include <libxml/xpathInternals.h> + +PyObject * +libxml_intWrap(int val) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_intWrap: val = %d\n", val); +#endif + ret = PyInt_FromLong((long) val); + return (ret); +} + +PyObject * +libxml_longWrap(long val) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_longWrap: val = %ld\n", val); +#endif + ret = PyInt_FromLong(val); + return (ret); +} + +PyObject * +libxml_doubleWrap(double val) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_doubleWrap: val = %f\n", val); +#endif + ret = PyFloat_FromDouble((double) val); + return (ret); +} + +PyObject * +libxml_charPtrWrap(char *str) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlcharPtrWrap: str = %s\n", str); +#endif + if (str == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + /* TODO: look at deallocation */ + ret = PyString_FromString(str); + xmlFree(str); + return (ret); +} + +PyObject * +libxml_charPtrConstWrap(const char *str) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlcharPtrWrap: str = %s\n", str); +#endif + if (str == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + /* TODO: look at deallocation */ + ret = PyString_FromString(str); + return (ret); +} + +PyObject * +libxml_xmlCharPtrWrap(xmlChar * str) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlCharPtrWrap: str = %s\n", str); +#endif + if (str == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + /* TODO: look at deallocation */ + ret = PyString_FromString((char *) str); + xmlFree(str); + return (ret); +} + +PyObject * +libxml_xmlCharPtrConstWrap(const xmlChar * str) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlCharPtrWrap: str = %s\n", str); +#endif + if (str == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + /* TODO: look at deallocation */ + ret = PyString_FromString((char *) str); + return (ret); +} + +PyObject * +libxml_constcharPtrWrap(const char *str) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlcharPtrWrap: str = %s\n", str); +#endif + if (str == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + /* TODO: look at deallocation */ + ret = PyString_FromString(str); + return (ret); +} + +PyObject * +libxml_constxmlCharPtrWrap(const xmlChar * str) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlCharPtrWrap: str = %s\n", str); +#endif + if (str == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + /* TODO: look at deallocation */ + ret = PyString_FromString((char *) str); + return (ret); +} + +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); +} + +PyObject * +libxml_xmlURIPtrWrap(xmlURIPtr uri) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlURIPtrWrap: uri = %p\n", uri); +#endif + if (uri == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) uri, (char *) "xmlURIPtr", + NULL); + return (ret); +} + +PyObject * +libxml_xmlNsPtrWrap(xmlNsPtr ns) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlNsPtrWrap: node = %p\n", ns); +#endif + if (ns == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) ns, (char *) "xmlNsPtr", + NULL); + return (ret); +} + +PyObject * +libxml_xmlAttrPtrWrap(xmlAttrPtr attr) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlAttrNodePtrWrap: attr = %p\n", attr); +#endif + if (attr == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) attr, (char *) "xmlAttrPtr", + NULL); + return (ret); +} + +PyObject * +libxml_xmlAttributePtrWrap(xmlAttributePtr attr) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlAttributePtrWrap: attr = %p\n", attr); +#endif + if (attr == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) attr, + (char *) "xmlAttributePtr", NULL); + return (ret); +} + +PyObject * +libxml_xmlElementPtrWrap(xmlElementPtr elem) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlElementNodePtrWrap: elem = %p\n", elem); +#endif + if (elem == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) elem, + (char *) "xmlElementPtr", NULL); + return (ret); +} + +PyObject * +libxml_xmlXPathContextPtrWrap(xmlXPathContextPtr ctxt) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlXPathContextPtrWrap: ctxt = %p\n", ctxt); +#endif + if (ctxt == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) ctxt, + (char *) "xmlXPathContextPtr", NULL); + return (ret); +} + +PyObject * +libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlXPathParserContextPtrWrap: ctxt = %p\n", ctxt); +#endif + if (ctxt == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt, + (char *) "xmlXPathParserContextPtr", + NULL); + return (ret); +} + +PyObject * +libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlParserCtxtPtrWrap: ctxt = %p\n", ctxt); +#endif + if (ctxt == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) ctxt, + (char *) "xmlParserCtxtPtr", NULL); + return (ret); +} + +/** + * libxml_xmlXPathDestructNsNode: + * cobj: xmlNsPtr namespace node + * desc: ignored string + * + * This function is called if and when a namespace node returned in + * an XPath node set is to be destroyed. That's the only kind of + * object returned in node set not directly linked to the original + * xmlDoc document, see xmlXPathNodeSetDupNs. + */ +static void +libxml_xmlXPathDestructNsNode(void *cobj, void *desc ATTRIBUTE_UNUSED) { +#ifdef DEBUG + fprintf(stderr, "libxml_xmlXPathDestructNsNode called %p\n", cobj); +#endif + xmlXPathNodeSetFreeNs((xmlNsPtr) cobj); +} + +PyObject * +libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlXPathObjectPtrWrap: ctxt = %p\n", obj); +#endif + if (obj == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + switch (obj->type) { + case XPATH_XSLT_TREE: { + if ((obj->nodesetval == NULL) || + (obj->nodesetval->nodeNr == 0) || + (obj->nodesetval->nodeTab == NULL)) { + ret = PyList_New(0); + } else { + int i, len = 0; + xmlNodePtr node; + + node = obj->nodesetval->nodeTab[0]->children; + while (node != NULL) { + len++; + node = node->next; + } + ret = PyList_New(len); + node = obj->nodesetval->nodeTab[0]->children; + for (i = 0;i < len;i++) { + PyList_SetItem(ret, i, libxml_xmlNodePtrWrap(node)); + node = node->next; + } + } + /* + * Return now, do not free the object passed down + */ + return (ret); + } + case XPATH_NODESET: + if ((obj->nodesetval == NULL) + || (obj->nodesetval->nodeNr == 0)) { + ret = PyList_New(0); + } else { + int i; + xmlNodePtr node; + + ret = PyList_New(obj->nodesetval->nodeNr); + for (i = 0; i < obj->nodesetval->nodeNr; i++) { + node = obj->nodesetval->nodeTab[i]; + if (node->type == XML_NAMESPACE_DECL) { + PyObject *ns = + PyCObject_FromVoidPtrAndDesc((void *) node, + (char *) "xmlNsPtr", + libxml_xmlXPathDestructNsNode); + PyList_SetItem(ret, i, ns); + /* make sure the xmlNsPtr is not destroyed now */ + obj->nodesetval->nodeTab[i] = NULL; + } else { + PyList_SetItem(ret, i, libxml_xmlNodePtrWrap(node)); + } + } + } + break; + case XPATH_BOOLEAN: + ret = PyInt_FromLong((long) obj->boolval); + break; + case XPATH_NUMBER: + ret = PyFloat_FromDouble(obj->floatval); + break; + case XPATH_STRING: + ret = PyString_FromString((char *) obj->stringval); + break; + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + default: +#ifdef DEBUG + printf("Unable to convert XPath object type %d\n", obj->type); +#endif + Py_INCREF(Py_None); + ret = Py_None; + } + xmlXPathFreeObject(obj); + return (ret); +} + +xmlXPathObjectPtr +libxml_xmlXPathObjectPtrConvert(PyObject * obj) +{ + xmlXPathObjectPtr ret = NULL; + +#ifdef DEBUG + printf("libxml_xmlXPathObjectPtrConvert: obj = %p\n", obj); +#endif + if (obj == NULL) { + return (NULL); + } + if PyFloat_Check + (obj) { + ret = xmlXPathNewFloat((double) PyFloat_AS_DOUBLE(obj)); + } else if PyInt_Check(obj) { + + ret = xmlXPathNewFloat((double) PyInt_AS_LONG(obj)); + + } else if PyBool_Check (obj) { + + if (obj == Py_True) { + ret = xmlXPathNewBoolean(1); + } + else { + ret = xmlXPathNewBoolean(0); + } + + } else if PyString_Check + (obj) { + xmlChar *str; + + str = xmlStrndup((const xmlChar *) PyString_AS_STRING(obj), + PyString_GET_SIZE(obj)); + ret = xmlXPathWrapString(str); + } else if PyList_Check + (obj) { + int i; + PyObject *node; + xmlNodePtr cur; + xmlNodeSetPtr set; + + set = xmlXPathNodeSetCreate(NULL); + + for (i = 0; i < PyList_Size(obj); i++) { + node = PyList_GetItem(obj, i); + if ((node == NULL) || (node->ob_type == NULL)) + continue; + + cur = NULL; + if (PyCObject_Check(node)) { +#ifdef DEBUG + printf("Got a CObject\n"); +#endif + cur = PyxmlNode_Get(node); + } else if (PyInstance_Check(node)) { + PyInstanceObject *inst = (PyInstanceObject *) node; + PyObject *name = inst->in_class->cl_name; + + if PyString_Check + (name) { + char *type = PyString_AS_STRING(name); + PyObject *wrapper; + + if (!strcmp(type, "xmlNode")) { + wrapper = + PyObject_GetAttrString(node, (char *) "_o"); + if (wrapper != NULL) { + cur = PyxmlNode_Get(wrapper); + } + } + } + } else { +#ifdef DEBUG + printf("Unknown object in Python return list\n"); +#endif + } + if (cur != NULL) { + xmlXPathNodeSetAdd(set, cur); + } + } + ret = xmlXPathWrapNodeSet(set); + } else { +#ifdef DEBUG + printf("Unable to convert Python Object to XPath"); +#endif + } + Py_DECREF(obj); + return (ret); +} + +PyObject * +libxml_xmlCatalogPtrWrap(xmlCatalogPtr catal) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlNodePtrWrap: catal = %p\n", catal); +#endif + if (catal == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) catal, + (char *) "xmlCatalogPtr", NULL); + return (ret); +} + +PyObject * +libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlOutputBufferPtrWrap: buffer = %p\n", buffer); +#endif + if (buffer == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) buffer, + (char *) "xmlOutputBufferPtr", NULL); + return (ret); +} + +PyObject * +libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlParserInputBufferPtrWrap: buffer = %p\n", buffer); +#endif + if (buffer == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) buffer, + (char *) "xmlParserInputBufferPtr", NULL); + return (ret); +} + +PyObject * +libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp) +{ + PyObject *ret; + +#ifdef DEBUG + printf("libxml_xmlRegexpPtrWrap: regexp = %p\n", regexp); +#endif + if (regexp == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) regexp, + (char *) "xmlRegexpPtr", NULL); + return (ret); +} |