Mercurial > genshi > genshi-test
comparison markup/path.py @ 121:22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
author | cmlenz |
---|---|
date | Wed, 02 Aug 2006 12:55:05 +0000 |
parents | 8f53c3ad385c |
children | 441545dbed4a |
comparison
equal
deleted
inserted
replaced
120:eb6cead67474 | 121:22a7080ed242 |
---|---|
230 def _function_comment(): | 230 def _function_comment(): |
231 def _function_comment(kind, data, pos): | 231 def _function_comment(kind, data, pos): |
232 return kind is COMMENT and (kind, data, pos) | 232 return kind is COMMENT and (kind, data, pos) |
233 return _function_comment | 233 return _function_comment |
234 | 234 |
235 def _function_local_name(): | |
236 def _function_local_name(kind, data, pos): | |
237 if kind is START: | |
238 return TEXT, data[0].localname, pos | |
239 return kind, data, pos | |
240 return _function_local_name | |
241 | |
242 def _function_name(): | |
243 def _function_name(kind, data, pos): | |
244 if kind is START: | |
245 return TEXT, data[0], pos | |
246 return kind, data, pos | |
247 return _function_name | |
248 | |
249 def _function_namespace_uri(): | |
250 def _function_namespace_uri(kind, data, pos): | |
251 if kind is START: | |
252 return TEXT, data[0].namespace, pos | |
253 return kind, data, pos | |
254 return _function_namespace_uri | |
255 | |
235 def _function_node(): | 256 def _function_node(): |
236 def _function_node(kind, data, pos): | 257 def _function_node(kind, data, pos): |
237 if kind is START: | 258 if kind is START: |
238 return True | 259 return True |
239 return kind, data, pos | 260 return kind, data, pos |
240 return _function_node | 261 return _function_node |
241 | 262 |
263 def _function_not(expr): | |
264 def _function_not(kind, data, pos): | |
265 return not expr(kind, data, pos) | |
266 return _function_not | |
267 | |
242 def _function_processing_instruction(name=None): | 268 def _function_processing_instruction(name=None): |
243 def _function_processing_instruction(kind, data, pos): | 269 def _function_processing_instruction(kind, data, pos): |
244 if kind is PI and (not name or data[0] == name): | 270 if kind is PI and (not name or data[0] == name): |
245 return (kind, data, pos) | 271 return (kind, data, pos) |
246 return _function_processing_instruction | 272 return _function_processing_instruction |
256 return _literal_string | 282 return _literal_string |
257 | 283 |
258 def _operator_eq(lval, rval): | 284 def _operator_eq(lval, rval): |
259 def _operator_eq(kind, data, pos): | 285 def _operator_eq(kind, data, pos): |
260 lv = lval(kind, data, pos) | 286 lv = lval(kind, data, pos) |
287 if type(lv) is tuple: | |
288 lv = lv[1] | |
261 rv = rval(kind, data, pos) | 289 rv = rval(kind, data, pos) |
262 return (lv and lv[1]) == (rv and rv[1]) | 290 if type(rv) is tuple: |
291 rv = rv[1] | |
292 return lv == rv | |
263 return _operator_eq | 293 return _operator_eq |
264 | 294 |
265 def _operator_neq(lval, rval): | 295 def _operator_neq(lval, rval): |
266 def _operator_neq(kind, data, pos): | 296 def _operator_neq(kind, data, pos): |
267 lv = lval(kind, data, pos) | 297 lv = lval(kind, data, pos) |
298 if type(lv) is tuple: | |
299 lv = lv[1] | |
268 rv = rval(kind, data, pos) | 300 rv = rval(kind, data, pos) |
269 return (lv and lv[1]) != (rv and rv[1]) | 301 if type(rv) is tuple: |
302 rv = rv[1] | |
303 return lv != rv | |
270 return _operator_neq | 304 return _operator_neq |
271 | 305 |
272 def _operator_and(lval, rval): | 306 def _operator_and(lval, rval): |
273 def _operator_and(kind, data, pos): | 307 def _operator_and(kind, data, pos): |
274 lv = lval(kind, data, pos) | 308 lv = lval(kind, data, pos) |
275 if not lv or (lv is not True and not lv[1]): | 309 if type(lv) is tuple: |
310 lv = lv[1] | |
311 if not lv: | |
276 return False | 312 return False |
277 rv = rval(kind, data, pos) | 313 rv = rval(kind, data, pos) |
278 if not rv or (rv is not True and not rv[1]): | 314 if type(rv) is tuple: |
279 return False | 315 rv = rv[1] |
280 return True | 316 return bool(rv) |
281 return _operator_and | 317 return _operator_and |
282 | 318 |
283 def _operator_or(lval, rval): | 319 def _operator_or(lval, rval): |
284 def _operator_or(kind, data, pos): | 320 def _operator_or(kind, data, pos): |
285 lv = lval(kind, data, pos) | 321 lv = lval(kind, data, pos) |
286 if lv and (lv is True or lv[1]): | 322 if type(lv) is tuple: |
323 lv = lv[1] | |
324 if lv: | |
287 return True | 325 return True |
288 rv = rval(kind, data, pos) | 326 rv = rval(kind, data, pos) |
289 if rv and (rv is True or rv[1]): | 327 if type(rv) is tuple: |
290 return True | 328 rv = rv[1] |
291 return False | 329 return bool(rv) |
292 return _operator_or | 330 return _operator_or |
293 | 331 |
294 | 332 |
295 class PathSyntaxError(Exception): | 333 class PathSyntaxError(Exception): |
296 """Exception raised when an XPath expression is syntactically incorrect.""" | 334 """Exception raised when an XPath expression is syntactically incorrect.""" |
307 class _PathParser(object): | 345 class _PathParser(object): |
308 """Tokenizes and parses an XPath expression.""" | 346 """Tokenizes and parses an XPath expression.""" |
309 | 347 |
310 _QUOTES = (("'", "'"), ('"', '"')) | 348 _QUOTES = (("'", "'"), ('"', '"')) |
311 _TOKENS = ('::', ':', '..', '.', '//', '/', '[', ']', '()', '(', ')', '@', | 349 _TOKENS = ('::', ':', '..', '.', '//', '/', '[', ']', '()', '(', ')', '@', |
312 '=', '!=', '!', '|') | 350 '=', '!=', '!', '|', ',') |
313 _tokenize = re.compile('(%s)|([^%s\s]+)|\s+' % ( | 351 _tokenize = re.compile('(%s)|([^%s\s]+)|\s+' % ( |
314 '|'.join([re.escape(t) for t in _TOKENS]), | 352 '|'.join([re.escape(t) for t in _TOKENS]), |
315 ''.join([re.escape(t[0]) for t in _TOKENS]))).findall | 353 ''.join([re.escape(t[0]) for t in _TOKENS]))).findall |
316 | 354 |
317 def __init__(self, text): | 355 def __init__(self, text): |
445 | 483 |
446 def _predicate(self): | 484 def _predicate(self): |
447 assert self.cur_token == '[' | 485 assert self.cur_token == '[' |
448 self.next_token() | 486 self.next_token() |
449 expr = self._or_expr() | 487 expr = self._or_expr() |
450 assert self.cur_token == ']' | 488 if self.cur_token != ']': |
489 raise PathSyntaxError('Expected "]" to close predicate, ' | |
490 'but found "%s"' % self.cur_token) | |
451 if not self.at_end: | 491 if not self.at_end: |
452 self.next_token() | 492 self.next_token() |
453 return expr | 493 return expr |
454 | 494 |
455 def _or_expr(self): | 495 def _or_expr(self): |
480 self.next_token() | 520 self.next_token() |
481 return _literal_string(token[1:-1]) | 521 return _literal_string(token[1:-1]) |
482 elif token[0].isdigit(): | 522 elif token[0].isdigit(): |
483 self.next_token() | 523 self.next_token() |
484 return _literal_number(float(token)) | 524 return _literal_number(float(token)) |
525 elif not self.at_end and self.peek_token().startswith('('): | |
526 if self.next_token() == '()': | |
527 args = [] | |
528 else: | |
529 self.next_token() | |
530 args = [self._or_expr()] | |
531 while self.cur_token not in (',', ')'): | |
532 args.append(self._or_expr()) | |
533 self.next_token() | |
534 if token == 'local-name': | |
535 return _function_local_name(*args) | |
536 elif token == 'name': | |
537 return _function_name(*args) | |
538 elif token == 'namespace-uri': | |
539 return _function_namespace_uri(*args) | |
540 elif token == 'not': | |
541 return _function_not(*args) | |
542 else: | |
543 raise PathSyntaxError('Unsupported function "%s"' % token) | |
485 else: | 544 else: |
486 axis = None | 545 axis = None |
487 if token == '@': | 546 if token == '@': |
488 axis = ATTRIBUTE | 547 axis = ATTRIBUTE |
489 self.next_token() | 548 self.next_token() |