minor optimization more work on the python bindings, they now support

* xpath.c: minor optimization
* python/generator.py python/libxml.c python/libxml.py
  python/libxml_wrap.h: more work on the python bindings,
  they now support XPath and there is no evident leak
Daniel
diff --git a/python/generator.py b/python/generator.py
index 0eac344..decd420 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -5,8 +5,15 @@
 
 functions = {}
 
-import os
 import string
+
+#######################################################################
+#
+#  That part if purely the API acquisition phase from the
+#  XML API description
+#
+#######################################################################
+import os
 import xmllib
 try:
     import sgmlop
@@ -159,6 +166,12 @@
 
     functions[name] = (desc, ret, args, file)
 
+#######################################################################
+#
+#  Some filtering rukes to drop functions/types which should not
+#  be exposed as-is on the Python interface
+#
+#######################################################################
 
 skipped_modules = {
     'xmlmemory': None,
@@ -167,6 +180,7 @@
     'hash': None,
     'list': None,
     'threads': None,
+    'xpointer': None,
 }
 skipped_types = {
     'int *': "usually a return type",
@@ -181,6 +195,14 @@
     '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),
     'int':  ('i', None, "int", "int"),
@@ -209,18 +231,18 @@
     'const xmlEntityPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
     'xmlEntity *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
     'const xmlEntity *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'xmlElementPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'const xmlElementPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'xmlElement *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'const xmlElement *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'xmlAttributePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'const xmlAttributePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'xmlAttribute *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'const xmlAttribute *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'xmlNsPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'const xmlNsPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'xmlNs *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
-    'const xmlNs *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
+    'xmlElementPtr':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
+    'const xmlElementPtr':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
+    'xmlElement *':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
+    'const xmlElement *':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
+    'xmlAttributePtr':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
+    'const xmlAttributePtr':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
+    'xmlAttribute *':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
+    'const xmlAttribute *':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
+    'xmlNsPtr':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
+    'const xmlNsPtr':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
+    'xmlNs *':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
+    'const xmlNs *':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
     'xmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
     'const xmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
     'xmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
@@ -233,10 +255,30 @@
     'const htmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
     'htmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
     'const htmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
+    'xmlXPathContextPtr':  ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
+    'xmlXPathContext *':  ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
+}
+
+py_return_types = {
+    'xmlXPathObjectPtr':  ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr"),
 }
 
 unknown_types = {}
 
+#######################################################################
+#
+#  This part writes the C <-> Python stubs libxml2-py.[ch] and
+#  the table libxml2-export.c to add when registrering the Python module
+#
+#######################################################################
+
+def skip_function(name):
+    if name[0:12] == "xmlXPathWrap":
+        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
@@ -251,6 +293,8 @@
 
     if skipped_modules.has_key(file):
         return 0
+    if skip_function(name) == 1:
+        return 0
 
     c_call = "";
     format=""
@@ -299,6 +343,12 @@
         c_call = "\n    c_retval = %s(%s);\n" % (name, c_call);
 	ret_convert = "    py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
 	ret_convert = ret_convert + "    return(py_retval);\n"
+    elif py_return_types.has_key(ret[0]):
+	(f, t, n, c) = py_return_types[ret[0]]
+	c_return = "    %s c_retval;\n" % (ret[0])
+        c_call = "\n    c_retval = %s(%s);\n" % (name, c_call);
+	ret_convert = "    py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
+	ret_convert = ret_convert + "    return(py_retval);\n"
     else:
 	if skipped_types.has_key(ret[0]):
 	    return 0
@@ -374,156 +424,199 @@
 							  failed, skipped);
 print "Missing type converters: %s" % (unknown_types.keys())
 
+#######################################################################
+#
+#  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
+#
+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"),
+    "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
+}
+
+converter_type = {
+    "xmlXPathObjectPtr": "xpathObjectRet(%s)",
+}
+
+primary_classes = ["xmlNode", "xmlDoc"]
+
+classes_ancestor = {
+    "xmlNode" : "xmlCore",
+    "xmlDoc" : "xmlCore",
+    "xmlAttr" : "xmlCore",
+    "xmlNs" : "xmlCore",
+    "xmlDtd" : "xmlCore",
+    "xmlEntity" : "xmlCore",
+    "xmlElement" : "xmlCore",
+    "xmlAttribute" : "xmlCore",
+}
+classes_destructors = {
+    "xpathContext": "xmlXPathFreeContext",
+}
+
 function_classes = {}
-for name in functions.keys():
-    (desc, ret, args, file) = functions[name]
-    if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == "xmlNodePtr":
-        if name[0:11] == "xmlNodeList":
-	    func = name[11:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (0, func, name, ret, args, file)
-	    if function_classes.has_key('xmlNode'):
-		function_classes['xmlNode'].append(info)
-	    else:
-		function_classes['xmlNode'] = [info]
-	elif name[0:7] == "xmlNode":
-	    func = name[7:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (0, func, name, ret, args, file)
-	    if function_classes.has_key('xmlNode'):
-		function_classes['xmlNode'].append(info)
-	    else:
-		function_classes['xmlNode'] = [info]
-	elif name[0:6] == "xmlGet":
-	    func = name[6:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (0, func, name, ret, args, file)
-	    if function_classes.has_key('xmlNode'):
-		function_classes['xmlNode'].append(info)
-	    else:
-		function_classes['xmlNode'] = [info]
-	else:
-	    func = name[3:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (0, func, name, ret, args, file)
-	    if function_classes.has_key('xmlNode'):
-		function_classes['xmlNode'].append(info)
-	    else:
-		function_classes['xmlNode'] = [info]
-    elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == "xmlNodePtr":
-        if name[0:11] == "xmlNodeList":
-	    func = name[11:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (1, func, name, ret, args, file)
-	    if function_classes.has_key('xmlNode'):
-		function_classes['xmlNode'].append(info)
-	    else:
-		function_classes['xmlNode'] = [info]
-	elif name[0:7] == "xmlNode":
-	    func = name[7:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (1, func, name, ret, args, file)
-	    if function_classes.has_key('xmlNode'):
-		function_classes['xmlNode'].append(info)
-	    else:
-		function_classes['xmlNode'] = [info]
-	elif name[0:6] == "xmlGet":
-	    func = name[6:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (1, func, name, ret, args, file)
-	    if function_classes.has_key('xmlNode'):
-		function_classes['xmlNode'].append(info)
-	    else:
-		function_classes['xmlNode'] = [info]
-	else:
-	    func = name[3:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (1, func, name, ret, args, file)
-	    if function_classes.has_key('xmlNode'):
-		function_classes['xmlNode'].append(info)
-	    else:
-		function_classes['xmlNode'] = [info]
-    elif name[0:3] == "xml" and len(args) >= 1 and args[0][1] == "xmlDocPtr":
-	if name[0:6] == "xmlDoc":
-	    func = name[6:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (0, func, name, ret, args, file)
-	    if function_classes.has_key('xmlDoc'):
-		function_classes['xmlDoc'].append(info)
-	    else:
-		function_classes['xmlDoc'] = [info]
-	elif name[0:6] == "xmlGet":
-	    func = name[6:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (0, func, name, ret, args, file)
-	    if function_classes.has_key('xmlDoc'):
-		function_classes['xmlDoc'].append(info)
-	    else:
-		function_classes['xmlDoc'] = [info]
-	else:
-	    func = name[3:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (0, func, name, ret, args, file)
-	    if function_classes.has_key('xmlDoc'):
-		function_classes['xmlDoc'].append(info)
-	    else:
-		function_classes['xmlDoc'] = [info]
-    elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == "xmlDocPtr":
-	if name[0:6] == "xmlDoc":
-	    func = name[6:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (1, func, name, ret, args, file)
-	    if function_classes.has_key('xmlDoc'):
-		function_classes['xmlDoc'].append(info)
-	    else:
-		function_classes['xmlDoc'] = [info]
-	elif name[0:6] == "xmlGet":
-	    func = name[6:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (1, func, name, ret, args, file)
-	    if function_classes.has_key('xmlDoc'):
-		function_classes['xmlDoc'].append(info)
-	    else:
-		function_classes['xmlDoc'] = [info]
-	else:
-	    func = name[3:]
-	    func = string.lower(func[0:1]) + func[1:]
-	    info = (1, func, name, ret, args, file)
-	    if function_classes.has_key('xmlDoc'):
-		function_classes['xmlDoc'].append(info)
-	    else:
-		function_classes['xmlDoc'] = [info]
-    elif ret[0] == "xmlDocPtr" or ret[0] == "xmlDtdPtr":
+
+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 = []
+ctypes_processed = {}
+for classe in primary_classes:
+    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]
+    ctypes.append(type)
+    ctypes_processed[type] = ()
+
+def nameFixup(function, classe, type):
+    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:l] == classe:
+	func = name[l:]
+	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:]
-	info = (0, func, name, ret, args, file)
-	if function_classes.has_key('None'):
-	    function_classes['None'].append(info)
-	else:
-	    function_classes['None'] = [info]
     else:
-        print "unable to guess class for %s:%s" % (file,name)
+        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
 
-classes_type = {
-    "xmlNodePtr": ("._o", "xmlNode(_obj=%s)"),
-    "xmlNode *": ("._o", "xmlNode(_obj=%s)"),
-    "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)"),
-    "xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)"),
-    "xmlAttrPtr": ("._o", "xmlNode(_obj=%s)"),
-    "xmlAttr *": ("._o", "xmlNode(_obj=%s)"),
-    "xmlNsPtr": ("._o", "xmlNode(_obj=%s)"),
-    "xmlNs *": ("._o", "xmlNode(_obj=%s)"),
-    "xmlDtdPtr": ("._o", "xmlNode(_obj=%s)"),
-    "xmlDtd *": ("._o", "xmlNode(_obj=%s)"),
-    "xmlEntityPtr": ("._o", "xmlNode(_obj=%s)"),
-    "xmlEntity *": ("._o", "xmlNode(_obj=%s)"),
-}
+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:3] == "xml" and len(args) >= 1 and args[0][1] == type:
+	    found = 1
+	    func = nameFixup(name, classe, type)
+	    info = (0, func, name, ret, args, file)
+	    function_classes[classe].append(info)
+	elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type:
+	    found = 1
+	    func = nameFixup(name, classe, type)
+	    info = (1, func, name, ret, args, file)
+	    function_classes[classe].append(info)
+	elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type:
+	    found = 1
+	    func = nameFixup(name, classe, type)
+	    info = (0, func, name, ret, args, file)
+	    function_classes[classe].append(info)
+	elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type:
+	    found = 1
+	    func = nameFixup(name, classe, type)
+	    info = (1, func, name, ret, args, file)
+	    function_classes[classe].append(info)
+	if found == 1:
+	    break
+    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)
+    info = (0, func, name, ret, args, file)
+    function_classes['None'].append(info)
 
 classes = open("libxml2class.py", "w")
 
+def functionCompare(info1, info2):
+    (index1, func1, name1, ret1, args1, file1) = info1
+    (index2, func2, name2, ret2, args2, file2) = info2
+    if file1 < file2:
+        return -1
+    if file1 > file2:
+        return 1
+    if func1 < func2:
+        return -1
+    if func1 > func2:
+        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:
+         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')
+
 if function_classes.has_key("None"):
-    for info in function_classes["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)
+	    oldfile = file
 	classes.write("def %s(" % func)
 	n = 0
 	for arg in args:
@@ -532,6 +625,7 @@
 	    classes.write("%s" % arg[0])
 	    n = n + 1
 	classes.write("):\n")
+	writeDoc(name, args, '    ', classes);
 	if ret[0] != "void":
 	    classes.write("    ret = ");
 	else:
@@ -560,21 +654,35 @@
     if classname == "None":
         pass
     else:
-	classes.write("class %s(xmlCore):\n" % classname);
-        if classname == "xmlNode":
+        if classes_ancestor.has_key(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("        xmlCore.__init__(self, _obj=_obj)\n\n")
-        elif classname == "xmlDoc":
-	    classes.write("    def __init__(self, _obj=None):\n")
-	    classes.write("        self._o = None\n")
-	    classes.write("        xmlCore.__init__(self, _obj=_obj)\n\n")
+	    classes.write("        %s.__init__(self, _obj=_obj)\n\n" % (
+	                  classes_ancestor[classname]))
 	else:
+	    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");
-	for info in function_classes[classname]:
+	if classes_destructors.has_key(classname):
+	    classes.write("    def __del__(self):\n")
+	    classes.write("        if self._o != None:\n")
+	    classes.write("            _libxml.%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:
+		classes.write("    #\n")
+		classes.write("    # %s functions from module %s\n" % (
+		              classname, file))
+		classes.write("    #\n\n")
+	    oldfile = file
 	    classes.write("    def %s(self" % func)
 	    n = 0
 	    for arg in args:
@@ -582,6 +690,7 @@
 		    classes.write(", %s" % arg[0])
 		n = n + 1
 	    classes.write("):\n")
+	    writeDoc(name, args, '        ', classes);
 	    if ret[0] != "void":
 	        classes.write("        ret = ");
 	    else:
@@ -605,6 +714,11 @@
 		    classes.write("        return ");
 		    classes.write(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");
diff --git a/python/libxml.c b/python/libxml.c
index 60bd3cb..6964975 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -35,7 +35,7 @@
 }
 
 PyObject *
-libxml_charPtrWrap(const char *str) {
+libxml_charPtrWrap(char *str) {
     PyObject *ret;
 
 #ifdef DEBUG
@@ -52,7 +52,40 @@
 }
 
 PyObject *
-libxml_xmlCharPtrWrap(const xmlChar *str) {
+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(str);
+    xmlFree(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
@@ -99,11 +132,26 @@
 }
 
 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, "xmlNsPtr", NULL);
+    return(ret);
+}
+
+PyObject *
 libxml_xmlAttrPtrWrap(xmlAttrPtr attr) {
     PyObject *ret;
 
 #ifdef DEBUG
-    printf("libxml_xmlNodePtrWrap: attr = %p\n", attr);
+    printf("libxml_xmlAttrNodePtrWrap: attr = %p\n", attr);
 #endif
     if (attr == NULL) {
 	Py_INCREF(Py_None);
@@ -113,6 +161,107 @@
     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, "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, "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, "xmlXPathContextPtr",
+	                               NULL);
+    return(ret);
+}
+
+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:
+	    /* TODO !!!! Allocation problems */
+        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];
+		    /* TODO: try to cast directly to the proper node type */
+		    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(obj->stringval);
+	    break;
+        case XPATH_POINT:
+        case XPATH_RANGE:
+        case XPATH_LOCATIONSET:
+	default:
+	    printf("Unable to convert XPath object type %d\n", obj->type);
+	    Py_INCREF(Py_None);
+	    ret = Py_None;
+    }
+    xmlXPathFreeObject(obj);
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *		The PyxmlNode type					*
+ *									*
+ ************************************************************************/
 static void
 PyxmlNode_dealloc(PyxmlNode_Object * self)
 {
@@ -173,6 +322,68 @@
 
 /************************************************************************
  *									*
+ *		The PyxmlXPathContext type					*
+ *									*
+ ************************************************************************/
+static void
+PyxmlXPathContext_dealloc(PyxmlXPathContext_Object * self)
+{
+    printf("TODO PyxmlXPathContext_dealloc\n");
+    PyMem_DEL(self);
+}
+
+static int
+PyxmlXPathContext_compare(PyxmlXPathContext_Object * self, PyxmlXPathContext_Object * v)
+{
+    if (self->obj == v->obj)
+        return 0;
+    if (self->obj > v->obj)
+        return -1;
+    return 1;
+}
+
+static long
+PyxmlXPathContext_hash(PyxmlXPathContext_Object * self)
+{
+    return (long) self->obj;
+}
+
+static PyObject *
+PyxmlXPathContext_repr(PyxmlXPathContext_Object * self)
+{
+    char buf[100];
+
+    sprintf(buf, "<xmlXPathContext at %lx>",
+            (long) PyxmlXPathContext_Get(self));
+    return PyString_FromString(buf);
+}
+
+static char PyxmlXPathContext_Type__doc__[] = "This is the type of XPath evaluation contexts";
+
+PyTypeObject PyxmlXPathContext_Type = {
+    PyObject_HEAD_INIT(&PyType_Type)
+        0,                      /*ob_size */
+    "xmlXPathContext",                  /*tp_name */
+    sizeof(PyxmlXPathContext_Object),   /*tp_basicsize */
+    0,                          /*tp_itemsize */
+    (destructor) PyxmlXPathContext_dealloc,/*tp_dealloc */
+    (printfunc) 0,              /*tp_print */
+    (getattrfunc) 0,            /*tp_getattr */
+    (setattrfunc) 0,            /*tp_setattr */
+    (cmpfunc) PyxmlXPathContext_compare,/*tp_compare */
+    (reprfunc) PyxmlXPathContext_repr,  /*tp_repr */
+    0,                          /*tp_as_number */
+    0,                          /*tp_as_sequence */
+    0,                          /*tp_as_mapping */
+    (hashfunc) PyxmlXPathContext_hash,  /*tp_hash */
+    (ternaryfunc) 0,            /*tp_call */
+    (reprfunc) 0,               /*tp_str */
+    0L, 0L, 0L, 0L,
+    PyxmlXPathContext_Type__doc__
+};
+
+/************************************************************************
+ *									*
  *			Global properties access			*
  *									*
  ************************************************************************/
@@ -215,7 +426,7 @@
 	    res = cur->name;
 	    break;
     }
-    resultobj = libxml_xmlCharPtrWrap(res);
+    resultobj = libxml_constxmlCharPtrWrap(res);
 
     return resultobj;
 }
@@ -546,66 +757,17 @@
     printf("libxml_type: cur = %p: %s\n", cur, res);
 #endif
 
-    resultobj = libxml_xmlCharPtrWrap(res);
+    resultobj = libxml_constxmlCharPtrWrap(res);
     return resultobj;
 }
 
 /************************************************************************
  *									*
- *			The interface raw code				*
- *									*
- ************************************************************************/
-static PyObject *
-libxml_parseFile(PyObject *self, PyObject *args)
-{
-    PyObject *resultobj;
-    char *arg0;
-    xmlDocPtr result;
-
-    if (!PyArg_ParseTuple(args, "s:parseFile", &arg0))
-        return NULL;
-#ifdef DEBUG
-    printf("libxml_parseFile: arg0 = %s\n", arg0);
-#endif
-    result = (xmlDocPtr )xmlParseFile((char const *)arg0);
-    resultobj = libxml_xmlDocPtrWrap(result);
-#ifdef DEBUG
-    printf("libxml_parseFile: resultobj = %p\n", resultobj);
-#endif
-    return resultobj;
-}
-
-static PyObject *
-libxml_freeDoc(PyObject *self, PyObject *args)
-{
-    xmlDocPtr doc;
-
-    if (!PyArg_ParseTuple(args, "O:freeDoc", &doc))
-        return NULL;
-    switch(doc->type) {
-	case XML_DOCUMENT_NODE:
-	case XML_HTML_DOCUMENT_NODE:
-#ifdef LIBXML_DOCB_ENABLED
-	case XML_DOCB_DOCUMENT_NODE:
-#endif
-	    xmlFreeDoc(doc);
-	    break;
-	default:
-	    break;
-    }
-    Py_INCREF(Py_None);
-    return(Py_None);
-}
-
-/************************************************************************
- *									*
  *			The registration stuff				*
  *									*
  ************************************************************************/
 static PyMethodDef libxmlMethods[] = {
 #include "libxml2-export.c"
-    { "parseFile", libxml_parseFile, METH_VARARGS },
-    { "freeDoc", libxml_freeDoc, METH_VARARGS },
     { "name", libxml_name, METH_VARARGS },
     { "children", libxml_children, METH_VARARGS },
     { "properties", libxml_properties, METH_VARARGS },
@@ -622,5 +784,6 @@
     m = Py_InitModule("_libxml", libxmlMethods);
     d = PyModule_GetDict(m);
     PyDict_SetItemString(d, "xmlNodeType", (PyObject *)&PyxmlNode_Type);
+    PyDict_SetItemString(d, "xmlXPathContextType", (PyObject *)&PyxmlXPathContext_Type);
 }
 
diff --git a/python/libxml.py b/python/libxml.py
index 259a08b..476bb27 100644
--- a/python/libxml.py
+++ b/python/libxml.py
@@ -1,5 +1,11 @@
 import _libxml
 
+#
+# This class is the ancestor of all the Node classes. It provides
+# the basic functionalities shared by all nodes (and handle
+# gracefylly the exception), like name, navigation in the tree,
+# doc reference and content access
+#
 class xmlCore:
     def __init__(self, _obj=None):
         if _obj != None: 
@@ -17,7 +23,7 @@
 	    ret = _libxml.properties(self._o)
 	    if ret == None:
 	        return None
-	    return xmlNode(_obj=ret)
+	    return xmlAttr(_obj=ret)
 	elif attr == "children":
 	    ret = _libxml.children(self._o)
 	    if ret == None:
@@ -74,13 +80,25 @@
 	if ret == None:
 	    return None
 	return xmlNode(_obj=ret)
+    def get_properties(self):
+	ret = _libxml.properties(self._o)
+	if ret == None:
+	    return None
+	return xmlAttr(_obj=ret)
+    def get_doc(self):
+	ret = _libxml.doc(self._o)
+	if ret == None:
+	    return None
+	return xmlDoc(_obj=ret)
     def get_prev(self):
 	ret = _libxml.prev(self._o)
 	if ret == None:
 	    return None
 	return xmlNode(_obj=ret)
     def get_content(self):
-	return self.content()
+	return _libxml.xmlNodeGetContent(self._o)
+    def getContent(self):
+	return _libxml.xmlNodeGetContent(self._o)
     def get_name(self):
 	return _libxml.name(self._o)
     def get_type(self):
@@ -94,5 +112,36 @@
         _libxml.freeDoc(self._o)
 	    
 #
+# converters to present a nicer view of the XPath returns
+#
+def nodeWrap(o):
+    # TODO try to cast to the most appropriate node class
+    name = _libxml.name(o)
+    if name == "element" or name == "text":
+        return xmlNode(_obj=o)
+    if name == "attribute":
+        return xmlAttr(_obj=o)
+    if name[0:8] == "document":
+        return xmlDoc(_obj=o)
+    if name[0:8] == "namespace":
+        return xmlNs(_obj=o)
+    if name == "elem_decl":
+        return xmlElement(_obj=o)
+    if name == "attribute_decl":
+        return xmlAtribute(_obj=o)
+    if name == "entity_decl":
+        return xmlEntity(_obj=o)
+    if name == "dtd":
+        return xmlAttr(_obj=o)
+    return xmlNode(_obj=o)
+
+def xpathObjectRet(o):
+    if type(o) == type([]) or type(o) == type(()):
+        ret = map(lambda x: nodeWrap(x), o)
+	return ret
+    return o
+
+#
 # Everything below this point is automatically generated
 #
+
diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h
index 00421f9..972e871 100644
--- a/python/libxml_wrap.h
+++ b/python/libxml_wrap.h
@@ -12,6 +12,7 @@
 #include <libxml/HTMLparser.h>
 #include <libxml/HTMLtree.h>
 #include <libxml/xinclude.h>
+#include <libxml/xpointer.h>
 
 #define PyxmlNode_Get(v) (((PyxmlNode_Object *)(v))->obj)
 
@@ -20,11 +21,24 @@
     xmlNodePtr obj;
 } PyxmlNode_Object;
 
+#define PyxmlXPathContext_Get(v) (((PyxmlXPathContext_Object *)(v))->obj)
+typedef struct {
+    PyObject_HEAD
+    xmlXPathContextPtr obj;
+} PyxmlXPathContext_Object;
+
 PyObject * libxml_intWrap(int val);
-PyObject * libxml_xmlCharPtrWrap(const xmlChar *str);
-PyObject * libxml_charPtrWrap(const char *str);
+PyObject * libxml_xmlCharPtrWrap(xmlChar *str);
+PyObject * libxml_constxmlCharPtrWrap(const xmlChar *str);
+PyObject * libxml_charPtrWrap(char *str);
+PyObject * libxml_constcharPtrWrap(const char *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_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj);