Ticket #81: xpath.patch
| File xpath.patch, 22.2 KB (added by Carsten Klein <carsten.klein@…>, 13 years ago) |
|---|
-
genshi/path.py
451 451 452 452 def test(self, ignore_context): 453 453 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 456 457 select_attr = steps[-1][0] is ATTRIBUTE and steps[-1][1] or None 457 458 458 459 # for every position in expression stores counters' list … … 499 500 if counters[cnum] != int(pretval): 500 501 pretval = False 501 502 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) 502 507 if not pretval: 503 508 return None 504 509 … … 765 770 nodetest = self._node_test(axis or CHILD) 766 771 predicates = [] 767 772 while self.cur_token == '[': 768 predicates.append(self._predicate( ))773 predicates.append(self._predicate(axis or CHILD)) 769 774 return axis, nodetest, predicates 770 775 771 776 def _node_test(self, axis=None): … … 816 821 self.lineno) 817 822 return cls(*args) 818 823 819 def _predicate(self ):824 def _predicate(self, axis=None): 820 825 assert self.cur_token == '[' 821 826 self.next_token() 822 expr = self._or_expr( )827 expr = self._or_expr(axis or CHILD) 823 828 if self.cur_token != ']': 824 829 raise PathSyntaxError('Expected "]" to close predicate, ' 825 830 'but found "%s"' % self.cur_token, … … 828 833 self.next_token() 829 834 return expr 830 835 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) 833 838 while self.cur_token == 'or': 834 839 self.next_token() 835 expr = OrOperator(expr, self._and_expr( ))840 expr = OrOperator(expr, self._and_expr(axis or CHILD), axis=axis) 836 841 return expr 837 842 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) 840 845 while self.cur_token == 'and': 841 846 self.next_token() 842 expr = AndOperator(expr, self._equality_expr( ))847 expr = AndOperator(expr, self._equality_expr(axis or CHILD), axis=axis) 843 848 return expr 844 849 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) 847 852 while self.cur_token in ('=', '!='): 848 853 op = _operator_map[self.cur_token] 849 854 self.next_token() 850 expr = op(expr, self._relational_expr( ))855 expr = op(expr, self._relational_expr(axis or CHILD), axis=axis) 851 856 return expr 852 857 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) 855 860 while self.cur_token in ('>', '>=', '<', '>='): 856 861 op = _operator_map[self.cur_token] 857 862 self.next_token() 858 expr = op(expr, self._sub_expr( ))863 expr = op(expr, self._sub_expr(axis or CHILD), axis=axis) 859 864 return expr 860 865 861 def _sub_expr(self ):866 def _sub_expr(self, axis=None): 862 867 token = self.cur_token 863 868 if token != '(': 864 return self._primary_expr( )869 return self._primary_expr(axis or CHILD) 865 870 self.next_token() 866 expr = self._or_expr( )871 expr = self._or_expr(axis or CHILD) 867 872 if self.cur_token != ')': 868 873 raise PathSyntaxError('Expected ")" to close sub-expression, ' 869 874 'but found "%s"' % self.cur_token, … … 871 876 self.next_token() 872 877 return expr 873 878 874 def _primary_expr(self ):879 def _primary_expr(self, axis=None): 875 880 token = self.cur_token 876 881 if len(token) > 1 and (token[0], token[-1]) in self._QUOTES: 877 882 self.next_token() … … 884 889 self.next_token() 885 890 return VariableReference(token) 886 891 elif not self.at_end and self.peek_token().startswith('('): 887 return self._function_call( )892 return self._function_call(axis or CHILD) 888 893 else: 889 894 axis = None 890 895 if token == '@': … … 892 897 self.next_token() 893 898 return self._node_test(axis) 894 899 895 def _function_call(self ):900 def _function_call(self, axis=None): 896 901 name = self.cur_token 897 902 if self.next_token() == '()': 898 903 args = [] 899 904 else: 900 905 assert self.cur_token == '(' 901 906 self.next_token() 902 args = [self._or_expr( )]907 args = [self._or_expr(axis or CHILD)] 903 908 while self.cur_token == ',': 904 909 self.next_token() 905 args.append(self._or_expr( ))910 args.append(self._or_expr(axis or CHILD)) 906 911 if not self.cur_token == ')': 907 912 raise PathSyntaxError('Expected ")" to close function argument ' 908 913 'list, but found "%s"' % self.cur_token, … … 912 917 if not cls: 913 918 raise PathSyntaxError('Unsupported function "%s"' % name, 914 919 self.filename, self.lineno) 915 return cls(*args )920 return cls(*args, axis=axis or CHILD) 916 921 917 922 918 923 # Type coercion … … 1068 1073 """ 1069 1074 __slots__ = ['expr'] 1070 1075 _return_type = bool 1071 def __init__(self, expr ):1076 def __init__(self, expr, axis=None): 1072 1077 self.expr = expr 1073 1078 def __call__(self, kind, data, pos, namespaces, variables): 1074 1079 val = self.expr(kind, data, pos, namespaces, variables) … … 1081 1086 for the given number. 1082 1087 """ 1083 1088 __slots__ = ['number'] 1084 def __init__(self, number ):1089 def __init__(self, number, axis=None): 1085 1090 self.number = number 1086 1091 def __call__(self, kind, data, pos, namespaces, variables): 1087 1092 number = self.number(kind, data, pos, namespaces, variables) … … 1094 1099 strings it gets as arguments. 1095 1100 """ 1096 1101 __slots__ = ['exprs'] 1097 def __init__(self, *exprs):1102 def __init__(self, axis=None, *exprs): 1098 1103 self.exprs = exprs 1099 1104 def __call__(self, kind, data, pos, namespaces, variables): 1100 1105 strings = [] … … 1110 1115 substring. 1111 1116 """ 1112 1117 __slots__ = ['string1', 'string2'] 1113 def __init__(self, string1, string2 ):1118 def __init__(self, string1, string2, axis=None): 1114 1119 self.string1 = string1 1115 1120 self.string2 = string2 1116 1121 def __call__(self, kind, data, pos, namespaces, variables): … … 1127 1132 __slots__ = ['string1', 'string2'] 1128 1133 flag_mapping = {'s': re.S, 'm': re.M, 'i': re.I, 'x': re.X} 1129 1134 1130 def __init__(self, string1, string2, flags='' ):1135 def __init__(self, string1, string2, flags='', axis=None): 1131 1136 self.string1 = string1 1132 1137 self.string2 = string2 1133 1138 self.flags = self._map_flags(flags) … … 1144 1149 class FalseFunction(Function): 1145 1150 """The `false` function, which always returns the boolean `false` value.""" 1146 1151 __slots__ = [] 1152 def __init__(self, axis=None): 1153 pass 1147 1154 def __call__(self, kind, data, pos, namespaces, variables): 1148 1155 return False 1149 1156 def __repr__(self): … … 1154 1161 for the given number. 1155 1162 """ 1156 1163 __slots__ = ['number'] 1157 def __init__(self, number ):1164 def __init__(self, number, axis=None): 1158 1165 self.number = number 1159 1166 def __call__(self, kind, data, pos, namespaces, variables): 1160 1167 number = self.number(kind, data, pos, namespaces, variables) … … 1167 1174 element. 1168 1175 """ 1169 1176 __slots__ = [] 1177 def __init__(self, axis=None): 1178 self.axis = axis 1170 1179 def __call__(self, kind, data, pos, namespaces, variables): 1171 1180 if kind is START: 1172 1181 return data[0].localname … … 1178 1187 element. 1179 1188 """ 1180 1189 __slots__ = [] 1190 def __init__(self, axis=None): 1191 self.axis = axis 1181 1192 def __call__(self, kind, data, pos, namespaces, variables): 1182 1193 if kind is START: 1183 1194 return data[0] … … 1189 1200 current element. 1190 1201 """ 1191 1202 __slots__ = [] 1203 def __init__(self, axis=None): 1204 pass 1192 1205 def __call__(self, kind, data, pos, namespaces, variables): 1193 1206 if kind is START: 1194 1207 return data[0].namespace … … 1200 1213 argument. 1201 1214 """ 1202 1215 __slots__ = ['expr'] 1203 def __init__(self, expr ):1216 def __init__(self, expr, axis=None): 1204 1217 self.expr = expr 1205 1218 def __call__(self, kind, data, pos, namespaces, variables): 1206 1219 return not as_bool(self.expr(kind, data, pos, namespaces, variables)) … … 1214 1227 """ 1215 1228 __slots__ = ['expr'] 1216 1229 _normalize = re.compile(r'\s{2,}').sub 1217 def __init__(self, expr ):1230 def __init__(self, expr, axis=None): 1218 1231 self.expr = expr 1219 1232 def __call__(self, kind, data, pos, namespaces, variables): 1220 1233 string = self.expr(kind, data, pos, namespaces, variables) … … 1225 1238 class NumberFunction(Function): 1226 1239 """The `number` function that converts its argument to a number.""" 1227 1240 __slots__ = ['expr'] 1228 def __init__(self, expr ):1241 def __init__(self, expr, axis=None): 1229 1242 self.expr = expr 1230 1243 def __call__(self, kind, data, pos, namespaces, variables): 1231 1244 val = self.expr(kind, data, pos, namespaces, variables) … … 1238 1251 given number. 1239 1252 """ 1240 1253 __slots__ = ['number'] 1241 def __init__(self, number ):1254 def __init__(self, number, axis=None): 1242 1255 self.number = number 1243 1256 def __call__(self, kind, data, pos, namespaces, variables): 1244 1257 number = self.number(kind, data, pos, namespaces, variables) … … 1251 1264 a given substring. 1252 1265 """ 1253 1266 __slots__ = ['string1', 'string2'] 1254 def __init__(self, string1, string2 ):1267 def __init__(self, string1, string2, axis=None): 1255 1268 self.string1 = string1 1256 1269 self.string2 = string2 1257 1270 def __call__(self, kind, data, pos, namespaces, variables): … … 1266 1279 string. 1267 1280 """ 1268 1281 __slots__ = ['expr'] 1269 def __init__(self, expr ):1282 def __init__(self, expr, axis=None): 1270 1283 self.expr = expr 1271 1284 def __call__(self, kind, data, pos, namespaces, variables): 1272 1285 string = self.expr(kind, data, pos, namespaces, variables) … … 1279 1292 at the given offset, and optionally limited to the given length. 1280 1293 """ 1281 1294 __slots__ = ['string', 'start', 'length'] 1282 def __init__(self, string, start, length=None ):1295 def __init__(self, string, start, length=None, axis=None): 1283 1296 self.string = string 1284 1297 self.start = start 1285 1298 self.length = length … … 1302 1315 is found after the given substring. 1303 1316 """ 1304 1317 __slots__ = ['string1', 'string2'] 1305 def __init__(self, string1, string2 ):1318 def __init__(self, string1, string2, axis=None): 1306 1319 self.string1 = string1 1307 1320 self.string2 = string2 1308 1321 def __call__(self, kind, data, pos, namespaces, variables): … … 1320 1333 is found before the given substring. 1321 1334 """ 1322 1335 __slots__ = ['string1', 'string2'] 1323 def __init__(self, string1, string2 ):1336 def __init__(self, string1, string2, axis=None): 1324 1337 self.string1 = string1 1325 1338 self.string2 = string2 1326 1339 def __call__(self, kind, data, pos, namespaces, variables): … … 1338 1351 string to target set of characters. 1339 1352 """ 1340 1353 __slots__ = ['string', 'fromchars', 'tochars'] 1341 def __init__(self, string, fromchars, tochars ):1354 def __init__(self, string, fromchars, tochars, axis=None): 1342 1355 self.string = string 1343 1356 self.fromchars = fromchars 1344 1357 self.tochars = tochars … … 1356 1369 class TrueFunction(Function): 1357 1370 """The `true` function, which always returns the boolean `true` value.""" 1358 1371 __slots__ = [] 1372 def __init__(self, axis=None): 1373 pass 1359 1374 def __call__(self, kind, data, pos, namespaces, variables): 1360 1375 return True 1361 1376 def __repr__(self): … … 1413 1428 1414 1429 class AndOperator(object): 1415 1430 """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 1418 1434 self.lval = lval 1419 1435 self.rval = rval 1420 1436 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) 1423 1446 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) 1426 1453 def __repr__(self): 1427 1454 return '%s and %s' % (self.lval, self.rval) 1428 1455 1429 1456 class EqualsOperator(object): 1430 1457 """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 1433 1461 self.lval = lval 1434 1462 self.rval = rval 1435 1463 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 1439 1475 def __repr__(self): 1440 1476 return '%s=%s' % (self.lval, self.rval) 1441 1477 1442 1478 class NotEqualsOperator(object): 1443 1479 """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 1446 1483 self.lval = lval 1447 1484 self.rval = rval 1448 1485 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 1452 1500 def __repr__(self): 1453 1501 return '%s!=%s' % (self.lval, self.rval) 1454 1502 1455 1503 class OrOperator(object): 1456 1504 """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 1459 1508 self.lval = lval 1460 1509 self.rval = rval 1461 1510 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) 1467 1524 def __repr__(self): 1468 1525 return '%s or %s' % (self.lval, self.rval) 1469 1526 1470 1527 class GreaterThanOperator(object): 1471 1528 """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 1474 1532 self.lval = lval 1475 1533 self.rval = rval 1476 1534 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) 1480 1549 def __repr__(self): 1481 1550 return '%s>%s' % (self.lval, self.rval) 1482 1551 1483 1552 class GreaterThanOrEqualOperator(object): 1484 1553 """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 1487 1557 self.lval = lval 1488 1558 self.rval = rval 1489 1559 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) 1493 1574 def __repr__(self): 1494 1575 return '%s>=%s' % (self.lval, self.rval) 1495 1576 1496 1577 class LessThanOperator(object): 1497 1578 """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 1500 1582 self.lval = lval 1501 1583 self.rval = rval 1502 1584 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) 1506 1599 def __repr__(self): 1507 1600 return '%s<%s' % (self.lval, self.rval) 1508 1601 1509 1602 class LessThanOrEqualOperator(object): 1510 1603 """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 1513 1607 self.lval = lval 1514 1608 self.rval = rval 1515 1609 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) 1519 1624 def __repr__(self): 1520 1625 return '%s<=%s' % (self.lval, self.rval) 1521 1626
