comparison markup/path.py @ 121:062e51ad7b19 trunk

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 4c4e81d12649
children 6c5c6f67d3e8
comparison
equal deleted inserted replaced
120:c9f0a26e28a2 121:062e51ad7b19
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()
Copyright (C) 2012-2017 Edgewall Software