Commits

Walter Dörwald committed 80250f8

Fixed a bug in ll.xist.xfind.Finder.__floordiv__.

Multiple all operators in an XFind expression will now no longer produced
duplicate nodes. The all operator implements xfind() and simple checks
that no node will be yielded twice.

Add tests.

  • Participants
  • Parent commits f3ca3b7

Comments (0)

Files changed (3)

 <?xml version='1.0' encoding='iso-8859-1'?>
+<section><title>Changes in 2.6.? (released ??/??/2004)</title>
+<ulist>
+<item>Fixed a bug in <method>ll.xist.xfind.Finder.__floordiv__</method>.</item>
+<item>Multiple <lit>all</lit> operators in an XFind expression will now
+no longer produced duplicate nodes.</item>
+</ulist>
+</section>
+
+
 <section><title>Changes in 2.6 (released 10/26/2004)</title>
 <ulist>
 <item><function>ToNode</function> now tries iterating through the

File _xist/xfind.py

 # $Source$
 
 
+def iterone(node):
+	"""
+	Return an iterator that will produce one item: <arg>node</arg>.
+	"""
+	yield node
+
+
 class Operator(object):
 	"""
 	The base class of all XFind operators.
 		from ll.xist import xsc
 		# Wrap node in an iterator
 		if isinstance(other, xsc.Node):
-			def iterone(node):
-				yield node
 			other = iterone(other)
 		return Finder(other, self)
 
 		from ll.xist import xsc
 		# Wrap node in an iterator
 		if isinstance(other, xsc.Node):
-			def iterone(node):
-				yield node
 			other = iterone(other)
 		return Finder(other, all, self)
 
 	__slots__ = ("iterator", "operators")
 
 	def __init__(self, iterator, *operators):
+		from ll.xist import xsc
+		if isinstance(iterator, xsc.Node):
+			iterator = iterone(iterator)
 		self.iterator = iterator
 		self.operators = operators
 
 		return Finder(self.iterator, *(self.operators + (other,)))
 
 	def __floordiv__(self, other):
-		return Finder(self.iterator, *(self.operators + (xfind.all, other)))
+		return Finder(self.iterator, *(self.operators + (all, other)))
 
 	def __repr__(self):
 		if self.operators:
 
 
 class all(Operator):
+	def xfind(self, iterator, *operators):
+		ids = {} # FIXME: Use a set in Python 2.4
+		for child in self.xwalk(iterator):
+			for subchild in Finder(child, *operators):
+				if id(subchild) not in ids:
+					ids[id(subchild)] = None
+					yield subchild
+
 	def xwalk(self, iterator):
 		for child in iterator:
 			for subchild in child.walk():

File test/test.py

 		self.assertEqual(len(res), 1)
 		self.assert_(res[0] is self.node[1]["class_"])
 
+
+class XFindTest3(unittest.TestCase):
+	def setUp(self):
+		ds = [html.div(id=hex(id).lower()[2:]) for id in xrange(15)]
+		for i in xrange(7):
+			ds[i].append(ds[2*i+1:2*i+3])
+		self.divs = ds
+		#        ____0____
+		#       /         \
+		#     _1_         _2_
+		#    /   \       /   \
+		#   3     4     5     6
+		#  / \   / \   / \   / \
+		# 7   8 9   a b   c d   e
+
+	def tearDown(self):
+		del self.divs
+
+	def checkids(self, expr, ids):
+		self.assertEqual("".join([str(e["id"]) for e in expr]), ids)
+
 	def test_frag(self):
 		e = parsers.parseString("das ist <b>klaus</b>. das ist <b>erich</b>", prefixes=xsc.Prefixes(html))
 		# The following won't generate any nodes, because e/xfind.all iterates all
 		# The following *will* produce these nodes
 		self.assertEqual(u"".join(map(unicode, e//xfind.is_(html.b))), u"klauserich")
 
+	def test_multiall(self):
+		self.checkids(self.divs[0]//html.div//html.div, "34789a56bcde")
+
+
 def test_main():
 	unittest.main()