Edgewall Software

Ticket #81: xpath.patch

File xpath.patch, 22.2 KB (added by Carsten Klein <carsten.klein@…>, 13 years ago)

Work in progress, just for review and comment

  • genshi/path.py

     
    451451
    452452    def test(self, ignore_context):
    453453        steps = self.path
    454         if steps[0][0] is ATTRIBUTE:
    455             steps = [_DOTSLASH] + steps
     454        #if steps[0][0] is ATTRIBUTE:
     455        #    print "DOTSLASH"
     456        #    steps = [_DOTSLASH] + steps
    456457        select_attr = steps[-1][0] is ATTRIBUTE and steps[-1][1] or None
    457458
    458459        # for every position in expression stores counters' list
     
    499500                        if counters[cnum] != int(pretval):
    500501                            pretval = False
    501502                        cnum += 1
     503                    elif isinstance(pretval, Attrs):
     504                        # predicate yielded attrs that will replace
     505                        # the attrs in the current data
     506                        data = (data[0], pretval)
    502507                    if not pretval:
    503508                         return None
    504509
     
    765770        nodetest = self._node_test(axis or CHILD)
    766771        predicates = []
    767772        while self.cur_token == '[':
    768             predicates.append(self._predicate())
     773            predicates.append(self._predicate(axis or CHILD))
    769774        return axis, nodetest, predicates
    770775
    771776    def _node_test(self, axis=None):
     
    816821                                  self.lineno)
    817822        return cls(*args)
    818823
    819     def _predicate(self):
     824    def _predicate(self, axis=None):
    820825        assert self.cur_token == '['
    821826        self.next_token()
    822         expr = self._or_expr()
     827        expr = self._or_expr(axis or CHILD)
    823828        if self.cur_token != ']':
    824829            raise PathSyntaxError('Expected "]" to close predicate, '
    825830                                  'but found "%s"' % self.cur_token,
     
    828833            self.next_token()
    829834        return expr
    830835
    831     def _or_expr(self):
    832         expr = self._and_expr()
     836    def _or_expr(self, axis=None):
     837        expr = self._and_expr(axis or CHILD)
    833838        while self.cur_token == 'or':
    834839            self.next_token()
    835             expr = OrOperator(expr, self._and_expr())
     840            expr = OrOperator(expr, self._and_expr(axis or CHILD), axis=axis)
    836841        return expr
    837842
    838     def _and_expr(self):
    839         expr = self._equality_expr()
     843    def _and_expr(self, axis=None):
     844        expr = self._equality_expr(axis or CHILD)
    840845        while self.cur_token == 'and':
    841846            self.next_token()
    842             expr = AndOperator(expr, self._equality_expr())
     847            expr = AndOperator(expr, self._equality_expr(axis or CHILD), axis=axis)
    843848        return expr
    844849
    845     def _equality_expr(self):
    846         expr = self._relational_expr()
     850    def _equality_expr(self, axis=None):
     851        expr = self._relational_expr(axis or CHILD)
    847852        while self.cur_token in ('=', '!='):
    848853            op = _operator_map[self.cur_token]
    849854            self.next_token()
    850             expr = op(expr, self._relational_expr())
     855            expr = op(expr, self._relational_expr(axis or CHILD), axis=axis)
    851856        return expr
    852857
    853     def _relational_expr(self):
    854         expr = self._sub_expr()
     858    def _relational_expr(self, axis=None):
     859        expr = self._sub_expr(axis or CHILD)
    855860        while self.cur_token in ('>', '>=', '<', '>='):
    856861            op = _operator_map[self.cur_token]
    857862            self.next_token()
    858             expr = op(expr, self._sub_expr())
     863            expr = op(expr, self._sub_expr(axis or CHILD), axis=axis)
    859864        return expr
    860865
    861     def _sub_expr(self):
     866    def _sub_expr(self, axis=None):
    862867        token = self.cur_token
    863868        if token != '(':
    864             return self._primary_expr()
     869            return self._primary_expr(axis or CHILD)
    865870        self.next_token()
    866         expr = self._or_expr()
     871        expr = self._or_expr(axis or CHILD)
    867872        if self.cur_token != ')':
    868873            raise PathSyntaxError('Expected ")" to close sub-expression, '
    869874                                  'but found "%s"' % self.cur_token,
     
    871876        self.next_token()
    872877        return expr
    873878
    874     def _primary_expr(self):
     879    def _primary_expr(self, axis=None):
    875880        token = self.cur_token
    876881        if len(token) > 1 and (token[0], token[-1]) in self._QUOTES:
    877882            self.next_token()
     
    884889            self.next_token()
    885890            return VariableReference(token)
    886891        elif not self.at_end and self.peek_token().startswith('('):
    887             return self._function_call()
     892            return self._function_call(axis or CHILD)
    888893        else:
    889894            axis = None
    890895            if token == '@':
     
    892897                self.next_token()
    893898            return self._node_test(axis)
    894899
    895     def _function_call(self):
     900    def _function_call(self, axis=None):
    896901        name = self.cur_token
    897902        if self.next_token() == '()':
    898903            args = []
    899904        else:
    900905            assert self.cur_token == '('
    901906            self.next_token()
    902             args = [self._or_expr()]
     907            args = [self._or_expr(axis or CHILD)]
    903908            while self.cur_token == ',':
    904909                self.next_token()
    905                 args.append(self._or_expr())
     910                args.append(self._or_expr(axis or CHILD))
    906911            if not self.cur_token == ')':
    907912                raise PathSyntaxError('Expected ")" to close function argument '
    908913                                      'list, but found "%s"' % self.cur_token,
     
    912917        if not cls:
    913918            raise PathSyntaxError('Unsupported function "%s"' % name,
    914919                                  self.filename, self.lineno)
    915         return cls(*args)
     920        return cls(*args, axis=axis or CHILD)
    916921
    917922
    918923# Type coercion
     
    10681073    """
    10691074    __slots__ = ['expr']
    10701075    _return_type = bool
    1071     def __init__(self, expr):
     1076    def __init__(self, expr, axis=None):
    10721077        self.expr = expr
    10731078    def __call__(self, kind, data, pos, namespaces, variables):
    10741079        val = self.expr(kind, data, pos, namespaces, variables)
     
    10811086    for the given number.
    10821087    """
    10831088    __slots__ = ['number']
    1084     def __init__(self, number):
     1089    def __init__(self, number, axis=None):
    10851090        self.number = number
    10861091    def __call__(self, kind, data, pos, namespaces, variables):
    10871092        number = self.number(kind, data, pos, namespaces, variables)
     
    10941099    strings it gets as arguments.
    10951100    """
    10961101    __slots__ = ['exprs']
    1097     def __init__(self, *exprs):
     1102    def __init__(self, axis=None, *exprs):
    10981103        self.exprs = exprs
    10991104    def __call__(self, kind, data, pos, namespaces, variables):
    11001105        strings = []
     
    11101115    substring.
    11111116    """
    11121117    __slots__ = ['string1', 'string2']
    1113     def __init__(self, string1, string2):
     1118    def __init__(self, string1, string2, axis=None):
    11141119        self.string1 = string1
    11151120        self.string2 = string2
    11161121    def __call__(self, kind, data, pos, namespaces, variables):
     
    11271132    __slots__ = ['string1', 'string2']
    11281133    flag_mapping = {'s': re.S, 'm': re.M, 'i': re.I, 'x': re.X}
    11291134
    1130     def __init__(self, string1, string2, flags=''):
     1135    def __init__(self, string1, string2, flags='', axis=None):
    11311136        self.string1 = string1
    11321137        self.string2 = string2
    11331138        self.flags = self._map_flags(flags)
     
    11441149class FalseFunction(Function):
    11451150    """The `false` function, which always returns the boolean `false` value."""
    11461151    __slots__ = []
     1152    def __init__(self, axis=None):
     1153        pass
    11471154    def __call__(self, kind, data, pos, namespaces, variables):
    11481155        return False
    11491156    def __repr__(self):
     
    11541161    for the given number.
    11551162    """
    11561163    __slots__ = ['number']
    1157     def __init__(self, number):
     1164    def __init__(self, number, axis=None):
    11581165        self.number = number
    11591166    def __call__(self, kind, data, pos, namespaces, variables):
    11601167        number = self.number(kind, data, pos, namespaces, variables)
     
    11671174    element.
    11681175    """
    11691176    __slots__ = []
     1177    def __init__(self, axis=None):
     1178        self.axis = axis
    11701179    def __call__(self, kind, data, pos, namespaces, variables):
    11711180        if kind is START:
    11721181            return data[0].localname
     
    11781187    element.
    11791188    """
    11801189    __slots__ = []
     1190    def __init__(self, axis=None):
     1191        self.axis = axis
    11811192    def __call__(self, kind, data, pos, namespaces, variables):
    11821193        if kind is START:
    11831194            return data[0]
     
    11891200    current element.
    11901201    """
    11911202    __slots__ = []
     1203    def __init__(self, axis=None):
     1204        pass
    11921205    def __call__(self, kind, data, pos, namespaces, variables):
    11931206        if kind is START:
    11941207            return data[0].namespace
     
    12001213    argument.
    12011214    """
    12021215    __slots__ = ['expr']
    1203     def __init__(self, expr):
     1216    def __init__(self, expr, axis=None):
    12041217        self.expr = expr
    12051218    def __call__(self, kind, data, pos, namespaces, variables):
    12061219        return not as_bool(self.expr(kind, data, pos, namespaces, variables))
     
    12141227    """
    12151228    __slots__ = ['expr']
    12161229    _normalize = re.compile(r'\s{2,}').sub
    1217     def __init__(self, expr):
     1230    def __init__(self, expr, axis=None):
    12181231        self.expr = expr
    12191232    def __call__(self, kind, data, pos, namespaces, variables):
    12201233        string = self.expr(kind, data, pos, namespaces, variables)
     
    12251238class NumberFunction(Function):
    12261239    """The `number` function that converts its argument to a number."""
    12271240    __slots__ = ['expr']
    1228     def __init__(self, expr):
     1241    def __init__(self, expr, axis=None):
    12291242        self.expr = expr
    12301243    def __call__(self, kind, data, pos, namespaces, variables):
    12311244        val = self.expr(kind, data, pos, namespaces, variables)
     
    12381251    given number.
    12391252    """
    12401253    __slots__ = ['number']
    1241     def __init__(self, number):
     1254    def __init__(self, number, axis=None):
    12421255        self.number = number
    12431256    def __call__(self, kind, data, pos, namespaces, variables):
    12441257        number = self.number(kind, data, pos, namespaces, variables)
     
    12511264    a given substring.
    12521265    """
    12531266    __slots__ = ['string1', 'string2']
    1254     def __init__(self, string1, string2):
     1267    def __init__(self, string1, string2, axis=None):
    12551268        self.string1 = string1
    12561269        self.string2 = string2
    12571270    def __call__(self, kind, data, pos, namespaces, variables):
     
    12661279    string.
    12671280    """
    12681281    __slots__ = ['expr']
    1269     def __init__(self, expr):
     1282    def __init__(self, expr, axis=None):
    12701283        self.expr = expr
    12711284    def __call__(self, kind, data, pos, namespaces, variables):
    12721285        string = self.expr(kind, data, pos, namespaces, variables)
     
    12791292    at the given offset, and optionally limited to the given length.
    12801293    """
    12811294    __slots__ = ['string', 'start', 'length']
    1282     def __init__(self, string, start, length=None):
     1295    def __init__(self, string, start, length=None, axis=None):
    12831296        self.string = string
    12841297        self.start = start
    12851298        self.length = length
     
    13021315    is found after the given substring.
    13031316    """
    13041317    __slots__ = ['string1', 'string2']
    1305     def __init__(self, string1, string2):
     1318    def __init__(self, string1, string2, axis=None):
    13061319        self.string1 = string1
    13071320        self.string2 = string2
    13081321    def __call__(self, kind, data, pos, namespaces, variables):
     
    13201333    is found before the given substring.
    13211334    """
    13221335    __slots__ = ['string1', 'string2']
    1323     def __init__(self, string1, string2):
     1336    def __init__(self, string1, string2, axis=None):
    13241337        self.string1 = string1
    13251338        self.string2 = string2
    13261339    def __call__(self, kind, data, pos, namespaces, variables):
     
    13381351    string to target set of characters.
    13391352    """
    13401353    __slots__ = ['string', 'fromchars', 'tochars']
    1341     def __init__(self, string, fromchars, tochars):
     1354    def __init__(self, string, fromchars, tochars, axis=None):
    13421355        self.string = string
    13431356        self.fromchars = fromchars
    13441357        self.tochars = tochars
     
    13561369class TrueFunction(Function):
    13571370    """The `true` function, which always returns the boolean `true` value."""
    13581371    __slots__ = []
     1372    def __init__(self, axis=None):
     1373        pass
    13591374    def __call__(self, kind, data, pos, namespaces, variables):
    13601375        return True
    13611376    def __repr__(self):
     
    14131428
    14141429class AndOperator(object):
    14151430    """The boolean operator `and`."""
    1416     __slots__ = ['lval', 'rval']
    1417     def __init__(self, lval, rval):
     1431    __slots__ = ['lval', 'rval', 'axis']
     1432    def __init__(self, lval, rval, axis=None):
     1433        self.axis = axis
    14181434        self.lval = lval
    14191435        self.rval = rval
    14201436    def __call__(self, kind, data, pos, namespaces, variables):
    1421         lval = as_bool(self.lval(kind, data, pos, namespaces, variables))
    1422         if not lval:
     1437        if self.axis is ATTRIBUTE:
     1438            matches = []
     1439            for attr in data[1]:
     1440                lval = as_scalar(self.lval(kind, attr, pos, namespaces, variables))
     1441                rval = as_scalar(self.rval(kind, attr, pos, namespaces, variables))
     1442                if lval < rval:
     1443                    matches.append[attr]
     1444            if len(matches) > 0:
     1445                return Attrs(matches)
    14231446            return False
    1424         rval = self.rval(kind, data, pos, namespaces, variables)
    1425         return as_bool(rval)
     1447        else:
     1448            lval = as_bool(self.lval(kind, data, pos, namespaces, variables))
     1449            if not lval:
     1450                return False
     1451            rval = self.rval(kind, data, pos, namespaces, variables)
     1452            return as_bool(rval)
    14261453    def __repr__(self):
    14271454        return '%s and %s' % (self.lval, self.rval)
    14281455
    14291456class EqualsOperator(object):
    14301457    """The equality operator `=`."""
    1431     __slots__ = ['lval', 'rval']
    1432     def __init__(self, lval, rval):
     1458    __slots__ = ['lval', 'rval', 'axis']
     1459    def __init__(self, lval, rval, axis=None):
     1460        self.axis = axis
    14331461        self.lval = lval
    14341462        self.rval = rval
    14351463    def __call__(self, kind, data, pos, namespaces, variables):
    1436         lval = as_scalar(self.lval(kind, data, pos, namespaces, variables))
    1437         rval = as_scalar(self.rval(kind, data, pos, namespaces, variables))
    1438         return lval == rval
     1464        if self.axis is ATTRIBUTE:
     1465            for attr in data[1]:
     1466                lval = as_scalar(self.lval(kind, attr, pos, namespaces, variables))
     1467                rval = as_scalar(self.rval(kind, attr, pos, namespaces, variables))
     1468                if lval == rval:
     1469                    return Attrs([attr])
     1470            return False
     1471        else:
     1472            lval = as_scalar(self.lval(kind, data, pos, namespaces, variables))
     1473            rval = as_scalar(self.rval(kind, data, pos, namespaces, variables))
     1474            return lval == rval
    14391475    def __repr__(self):
    14401476        return '%s=%s' % (self.lval, self.rval)
    14411477
    14421478class NotEqualsOperator(object):
    14431479    """The equality operator `!=`."""
    1444     __slots__ = ['lval', 'rval']
    1445     def __init__(self, lval, rval):
     1480    __slots__ = ['lval', 'rval', 'axis']
     1481    def __init__(self, lval, rval, axis=None):
     1482        self.axis = axis
    14461483        self.lval = lval
    14471484        self.rval = rval
    14481485    def __call__(self, kind, data, pos, namespaces, variables):
    1449         lval = as_scalar(self.lval(kind, data, pos, namespaces, variables))
    1450         rval = as_scalar(self.rval(kind, data, pos, namespaces, variables))
    1451         return lval != rval
     1486        if self.axis is ATTRIBUTE:
     1487            matches = []
     1488            for attr in data[1]:
     1489                lval = as_scalar(self.lval(kind, attr, pos, namespaces, variables))
     1490                rval = as_scalar(self.rval(kind, attr, pos, namespaces, variables))
     1491                if lval != rval:
     1492                    matches.append[attr]
     1493            if len(matches) > 0:
     1494                return Attrs(matches)
     1495            return False
     1496        else:
     1497            lval = as_scalar(self.lval(kind, data, pos, namespaces, variables))
     1498            rval = as_scalar(self.rval(kind, data, pos, namespaces, variables))
     1499            return lval != rval
    14521500    def __repr__(self):
    14531501        return '%s!=%s' % (self.lval, self.rval)
    14541502
    14551503class OrOperator(object):
    14561504    """The boolean operator `or`."""
    1457     __slots__ = ['lval', 'rval']
    1458     def __init__(self, lval, rval):
     1505    __slots__ = ['lval', 'rval', 'axis']
     1506    def __init__(self, lval, rval, axis=None):
     1507        self.axis = axis
    14591508        self.lval = lval
    14601509        self.rval = rval
    14611510    def __call__(self, kind, data, pos, namespaces, variables):
    1462         lval = as_bool(self.lval(kind, data, pos, namespaces, variables))
    1463         if lval:
    1464             return True
    1465         rval = self.rval(kind, data, pos, namespaces, variables)
    1466         return as_bool(rval)
     1511        if self.axis is ATTRIBUTE:
     1512            lval = self.lval(kind, data, pos, namespaces, variables)
     1513            rval = self.rval(kind, data, pos, namespaces, variables)
     1514            result = Attrs()
     1515            result |= lval
     1516            result |= rval
     1517            return result
     1518        else:
     1519            lval = as_bool(self.lval(kind, data, pos, namespaces, variables))
     1520            if lval:
     1521                return True
     1522            rval = self.rval(kind, data, pos, namespaces, variables)
     1523            return as_bool(rval)
    14671524    def __repr__(self):
    14681525        return '%s or %s' % (self.lval, self.rval)
    14691526
    14701527class GreaterThanOperator(object):
    14711528    """The relational operator `>` (greater than)."""
    1472     __slots__ = ['lval', 'rval']
    1473     def __init__(self, lval, rval):
     1529    __slots__ = ['lval', 'rval', 'axis']
     1530    def __init__(self, lval, rval, axis=None):
     1531        self.axis = axis
    14741532        self.lval = lval
    14751533        self.rval = rval
    14761534    def __call__(self, kind, data, pos, namespaces, variables):
    1477         lval = self.lval(kind, data, pos, namespaces, variables)
    1478         rval = self.rval(kind, data, pos, namespaces, variables)
    1479         return as_float(lval) > as_float(rval)
     1535        if self.axis is ATTRIBUTE:
     1536            matches = []
     1537            for attr in data[1]:
     1538                lval = as_scalar(self.lval(kind, attr, pos, namespaces, variables))
     1539                rval = as_scalar(self.rval(kind, attr, pos, namespaces, variables))
     1540                if lval > rval:
     1541                    matches.append[attr]
     1542            if len(matches) > 0:
     1543                return Attrs(matches)
     1544            return False
     1545        else:
     1546            lval = self.lval(kind, data, pos, namespaces, variables)
     1547            rval = self.rval(kind, data, pos, namespaces, variables)
     1548            return as_float(lval) > as_float(rval)
    14801549    def __repr__(self):
    14811550        return '%s>%s' % (self.lval, self.rval)
    14821551
    14831552class GreaterThanOrEqualOperator(object):
    14841553    """The relational operator `>=` (greater than or equal)."""
    1485     __slots__ = ['lval', 'rval']
    1486     def __init__(self, lval, rval):
     1554    __slots__ = ['lval', 'rval', 'axis']
     1555    def __init__(self, lval, rval, axis=None):
     1556        self.axis = axis
    14871557        self.lval = lval
    14881558        self.rval = rval
    14891559    def __call__(self, kind, data, pos, namespaces, variables):
    1490         lval = self.lval(kind, data, pos, namespaces, variables)
    1491         rval = self.rval(kind, data, pos, namespaces, variables)
    1492         return as_float(lval) >= as_float(rval)
     1560        if self.axis is ATTRIBUTE:
     1561            matches = []
     1562            for attr in data[1]:
     1563                lval = as_scalar(self.lval(kind, attr, pos, namespaces, variables))
     1564                rval = as_scalar(self.rval(kind, attr, pos, namespaces, variables))
     1565                if lval >= rval:
     1566                    matches.append[attr]
     1567            if len(matches) > 0:
     1568                return Attrs(matches)
     1569            return False
     1570        else:
     1571            lval = self.lval(kind, data, pos, namespaces, variables)
     1572            rval = self.rval(kind, data, pos, namespaces, variables)
     1573            return as_float(lval) >= as_float(rval)
    14931574    def __repr__(self):
    14941575        return '%s>=%s' % (self.lval, self.rval)
    14951576
    14961577class LessThanOperator(object):
    14971578    """The relational operator `<` (less than)."""
    1498     __slots__ = ['lval', 'rval']
    1499     def __init__(self, lval, rval):
     1579    __slots__ = ['lval', 'rval', 'axis']
     1580    def __init__(self, lval, rval, axis=None):
     1581        self.axis = axis
    15001582        self.lval = lval
    15011583        self.rval = rval
    15021584    def __call__(self, kind, data, pos, namespaces, variables):
    1503         lval = self.lval(kind, data, pos, namespaces, variables)
    1504         rval = self.rval(kind, data, pos, namespaces, variables)
    1505         return as_float(lval) < as_float(rval)
     1585        if self.axis is ATTRIBUTE:
     1586            matches = []
     1587            for attr in data[1]:
     1588                lval = as_scalar(self.lval(kind, attr, pos, namespaces, variables))
     1589                rval = as_scalar(self.rval(kind, attr, pos, namespaces, variables))
     1590                if lval < rval:
     1591                    matches.append[attr]
     1592            if len(matches) > 0:
     1593                return Attrs(matches)
     1594            return False
     1595        else:
     1596            lval = self.lval(kind, data, pos, namespaces, variables)
     1597            rval = self.rval(kind, data, pos, namespaces, variables)
     1598            return as_float(lval) < as_float(rval)
    15061599    def __repr__(self):
    15071600        return '%s<%s' % (self.lval, self.rval)
    15081601
    15091602class LessThanOrEqualOperator(object):
    15101603    """The relational operator `<=` (less than or equal)."""
    1511     __slots__ = ['lval', 'rval']
    1512     def __init__(self, lval, rval):
     1604    __slots__ = ['lval', 'rval', 'axis']
     1605    def __init__(self, lval, rval, axis=None):
     1606        self.axis = axis
    15131607        self.lval = lval
    15141608        self.rval = rval
    15151609    def __call__(self, kind, data, pos, namespaces, variables):
    1516         lval = self.lval(kind, data, pos, namespaces, variables)
    1517         rval = self.rval(kind, data, pos, namespaces, variables)
    1518         return as_float(lval) <= as_float(rval)
     1610        if self.axis is ATTRIBUTE:
     1611            matches = []
     1612            for attr in data[1]:
     1613                lval = as_scalar(self.lval(kind, attr, pos, namespaces, variables))
     1614                rval = as_scalar(self.rval(kind, attr, pos, namespaces, variables))
     1615                if lval <= rval:
     1616                    matches.append[attr]
     1617            if len(matches) > 0:
     1618                return Attrs(matches)
     1619            return False
     1620        else:
     1621            lval = self.lval(kind, data, pos, namespaces, variables)
     1622            rval = self.rval(kind, data, pos, namespaces, variables)
     1623            return as_float(lval) <= as_float(rval)
    15191624    def __repr__(self):
    15201625        return '%s<=%s' % (self.lval, self.rval)
    15211626