GNOME Bugzilla – Bug 345779
equality check for python bindings
Last modified: 2006-06-26 19:21:11 UTC
Hi, this is a request for a function in the python bindings that will tell the user wether two given nodes are the same. You cannot use pythons "==" operator as the nodes are always newly created to avoid the need for reference-counting. Daniel Veillard dropped a short note on libxml2 list how this could be done: unfortunately I'm afraid you need to go down to the C level and check the 2 pointers, they aren't seen at the python level. Should be a fairly easy change to python/libxml.c to add this equality entry point and then add a method in the node class in libxml.py to be used for (I'm citing him here, because his mail doesn't show up in the archive) I don't know wether I can provide an initial patch as my knowledge about these things is rather limited. Thanks, Andreas
Hi, I had a shot at this and came up with the attached patches (the first for libxml.c and libxml.py, the second is the testcase). However it seems that the nodes are always equal, i.e. comparing xmlNodePtr1 == xmlNodePtr2 always evaluates to true and I don't really see what else I could use (I already tried using psvi from xmlNode, but that didn't work either). I'm stuck there now and would really appreciate some help. Thanks, Andreas
Created attachment 67986 [details] [review] support equality check for xmlNode's in python bindings The patch adds 2 methods to xmlCore: __eq__ and __ne__ which will be used by Python when comparing two xmlCore-derived objects using == or !=. The underlying C function compares the xmlNodePtr values, however it seems this is not sufficient (always returns true)
Created attachment 67987 [details] [review] testcase for the comparison patch Tests for equality and un-equality of 2 xmlNodes.
Do not despair - your patch works OK for me :-) When testing, make sure that your paths are setup correctly - I'm not sure of which OS you are working with - if it's Linux, then one easy way is to (manually) set LD_LIBRARY_PATH and PYTHONPATH, e.g.: bill@bbsf /usr/projects/gnomecvs/xmltest/python/tests $ echo $LD_LIBRARY_PATH /usr/projects/gnomecvs/xmltest/.libs bill@bbsf /usr/projects/gnomecvs/xmltest/python/tests $ echo $PYTHONPATH /usr/projects/gnomecvs/xmltest/python/:/usr/projects/gnomecvs/xmltest/python/.libs bill@bbsf /usr/projects/gnomecvs/xmltest/python/tests $ ./compareNodes.py <xmlNode (foo) object at 0x2b8768f8c8c0> <xmlNode (foo) object at 0x2b8768f8c908> __eq__ 1 <xmlNode (foo) object at 0x2b8768f8c8c0> <xmlNode (root) object at 0x2b8768f8c1b8> __ne__ 1 OK
That is, because the patch is actually wrong. __ne__ returns the same value as __eq__, you could try >>> import libxml2 >>> doc=libxml2.parseDoc('<root><doc /></root>') >>> root = doc.getRootElement() >>> foonode1=doc.children >>> foonode1==root <xmlNode (root) object at 0x-483cb674> <xmlNode (root) object at 0x-483cbbb4> __eq__ 1 1 Which is totally wrong... I think it would already help if I could get the actual pointer addresses out of the function I wrote. I currently don't really want to try to debug libxml2 with plain gdb... I'll attach a new patch which shows that somethings wrong. Andreas
Created attachment 67995 [details] [review] fixed patch for the comparison method this fixes the __ne__ function which returned the same as __eq__ (a missing not in the return).
Hi, so I started gdb and ran the test script in it. It seems that the PyObject's given in args are somehow not containing proper xmlNodePtr's: Breakpoint 6, libxml_compareNodesEqual (self=0x0, args=0xb72f5cac) at libxml.c:3697 3697 node1 = PyxmlNode_Get(py_node1); (gdb) step 3699 node2 = PyxmlNode_Get(py_node2); (gdb) step 3700 if ( node1 == NULL || node2 == NULL ) (gdb) print node1 $9 = (xmlNodePtr) 0xb78bd17c (gdb) print node2 $10 = (xmlNodePtr) 0xb78bd17c (gdb) print node1->name $11 = (const xmlChar *) 0xb740d76c "\001" (gdb) print node2->name $12 = (const xmlChar *) 0xb740d76c "\001" (gdb) print node2->type $13 = 135379328 (gdb) print node1->type $14 = 135379328 I'll try with __eq__ and __ne__ on the xmlNode class instead, maybe the problem is that it's defined on xmlCore class.
Try a small enhancement to your patch for libxml.py: change the ret = libxml2mod.compareNodesEqual(self, other) to be ret = libxml2mod.compareNodesEqual(self._o, other._o) and see how you like the results...
Thanks, somhow I missed that all the other functions in libxml.py do this. Attaching the final version of the patch. Andreas
Created attachment 68018 [details] [review] final patch for comparing 2 nodes in the python bindings Thanks to William Brack, this patch now works as it is expected. So I'm uploading a clean patch (that doesn't contain any extra print's).
Created attachment 68024 [details] [review] new testcase, including 2 more tests I updated the testcase, to also check wether == returns true on unequal nodes and != returns false on unequal nodes.
I combined the later bug 345961 with this request, added some small enhancements (including taking care of the case where one operand is None, and assuring that __eq__ always returns a Boolean), and committed to CVS. Please check that you agree with what I did, and re-open this bug if there are any problems. Bill
Looks good to me.