# HG changeset patch
# User mkurczych
# Date 1214262040 0
# Node ID 7320190e10c5694b9a40da9848575bd42b38d058
# Parent a27086137e6e6b31140d76cfb5b6405f175faade
Added one test and made path.py pass it (I've forgotten to implement the last_checked variable functionality, because of which some places in path were checked multiple times, which made counters wrong).
diff --git a/genshi/path.py b/genshi/path.py
--- a/genshi/path.py
+++ b/genshi/path.py
@@ -181,7 +181,7 @@
stream against the path
:rtype: ``function``
"""
- #For every path we store (path, stack, isDescendant)
+
paths = []
for p in self.paths:
if ignore_context:
@@ -194,26 +194,27 @@
else:
steps = p
- #for node it contains all positions of xpath expression
- #where its child should start checking for matches
+ # for node it contains all positions of xpath expression
+ # where its child should start checking for matches
+ # it's always increasing sequence (invariant)
stack = [[0]]
- #for every position in expression stores counters' list
- #it is used for position based predicates
+ # for every position in expression stores counters' list
+ # it is used for position based predicates
counters = [[] for _ in xrange(len(steps))]
- #indexes where explession has descendant(-or-self) axis
- descendantAxes = [i for (i, (a, _, _,),) in
+ # indexes where expression has descendant(-or-self) axis
+ descendant_axes = [i for (i, (a, _, _,),) in
enumerate(steps) if a is DESCENDANT
or a is DESCENDANT_OR_SELF]
- paths.append((steps, stack, descendantAxes, counters,))
+ paths.append((steps, stack, descendant_axes, counters,))
def _test(event, namespaces, variables, updateonly=False):
kind, data, pos = event[:3]
retval = None
- for steps, stack, descendantAxes, counters in paths:
+ for steps, stack, descendant_axes, counters in paths:
# Manage the stack that tells us "where we are" in the stream
if kind is END:
stack.pop()
@@ -222,54 +223,56 @@
pass
elif kind is START_NS or kind is END_NS \
or kind is START_CDATA or kind is END_CDATA:
- #should we make namespaces work?
+ # should we make namespaces work?
continue
- #FIXME: Need to find out when we can do this
+ # FIXME: Need to find out when we can do this
#if updateonly:
# continue
- myPositions = stack[-1]
- nextPositions = []
+ my_positions = stack[-1]
+ next_positions = []
- #length of real part of path - we omit attribute axis
- realLen = len(steps) - ((steps[-1][0] == ATTRIBUTE) or 1 and 0)
- lastChecked = realLen
+ # length of real part of path - we omit attribute axis
+ real_len = len(steps) - ((steps[-1][0] == ATTRIBUTE) or 1 and 0)
+ last_checked = -1
- #places where we have to check for match, are these
- #provided by parent
- for position in myPositions:
+ # places where we have to check for match, are these
+ # provided by parent
+ for position in my_positions:
- #we have already checked this position
- #(it had to be because of self-like axes)
- if position >= lastChecked:
+ # we have already checked this position
+ # (it had to be because of self-like axes)
+ if position <= last_checked:
continue
- for x in xrange(position, realLen):
- #number of counters - we have to create one
- #for every context position based predicate
+ for x in xrange(position, real_len):
+ # number of counters - we have to create one
+ # for every context position based predicate
cnum = 0
axis, nodetest, predicates = steps[x]
if x != position and axis is not SELF:
- nextPositions.append(x)
+ next_positions.append(x)
- #to go further we have to use self-like axes
+ # to go further we have to use self-like axes
if axis is not DESCENDANT_OR_SELF and \
axis is not SELF and x != position:
+ x -= 1 # x hasn't been really checked so we can't
+ # reall save it to last_checked
break
- #tells if we have match with position x
+ # tells if we have match with position x
matched = False
- #nodetest first
+ # nodetest first
if nodetest(kind, data, pos, namespaces, variables):
matched = True
- #TODO: or maybe add nodetest here
- #(chain((nodetest,), predicates))?
+ # TODO: or maybe add nodetest here
+ # (chain((nodetest,), predicates))?
if matched and predicates:
for predicate in predicates:
pretval = predicate(kind, data, pos,
@@ -292,8 +295,8 @@
if not matched:
break
else:
- #we reached end of expression, because x
- #is equal to the length of expression
+ # we reached end of expression, because x
+ # is equal to the length of expression
matched = True
axis, nodetest, predicates = steps[-1]
if axis is ATTRIBUTE:
@@ -301,31 +304,33 @@
namespaces, variables)
if matched:
retval = matched
+ # in x is stored the last index for which check was done
+ last_checked = x
if kind is START:
- #in nextPositions there are positions that are implied
- #by current matches, but we have to add previous
- #descendant-like axis positions
- #(which can "jump" over tree)
+ # in next_positions there are positions that are implied
+ # by current matches, but we have to add previous
+ # descendant-like axis positions
+ # (which can "jump" over tree)
i = 0
stack.append([])
- #every descendant axis before furthest position is ok
- for pos in nextPositions:
- while i != len(descendantAxes) \
- and descendantAxes[i] < pos:
- stack[-1].append(descendantAxes[i])
+ # every descendant axis before furthest position is ok
+ for pos in next_positions:
+ while i != len(descendant_axes) \
+ and descendant_axes[i] < pos:
+ stack[-1].append(descendant_axes[i])
i += 1
- if i != len(descendantAxes) \
- and descendantAxes[i] == pos:
+ if i != len(descendant_axes) \
+ and descendant_axes[i] == pos:
i += 1
stack[-1].append(pos)
- #every descendant that was parent's one is ok
- if myPositions:
- while i != len(descendantAxes) \
- and descendantAxes[i] <= myPositions[-1]:
- stack[-1].append(descendantAxes[i])
+ # every descendant that was parent's one is ok
+ if my_positions:
+ while i != len(descendant_axes) \
+ and descendant_axes[i] <= my_positions[-1]:
+ stack[-1].append(descendant_axes[i])
i += 1
return retval
@@ -404,7 +409,7 @@
if self.cur_token.startswith('/'):
if not steps:
if self.cur_token == '//':
- #hack to make //* match every node - also root
+ # hack to make //* match every node - also root
self.next_token()
axis, nodetest, predicates = self._location_step()
steps.append((DESCENDANT_OR_SELF, nodetest,
diff --git a/genshi/tests/path.py b/genshi/tests/path.py
--- a/genshi/tests/path.py
+++ b/genshi/tests/path.py
@@ -432,6 +432,11 @@
path = Path('*[2][@id]')
self.assertEqual('', path.select(xml).render())
+ def test_predicate_advanced_position(self):
+ xml = XML('')
+ path = Path('descendant-or-self::*/descendant-or-self::*/descendant-or-self::*[2]/self::*/descendant::*[3]')
+ self.assertEqual('', path.select(xml).render())
+
def test_name_with_namespace(self):
xml = XML('bar')
path = Path('f:foo')