Mercurial > paraspace
view paraspace/structpath.py @ 35:2f9e7f03dbf7
Support predicates in structpath.py
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Wed, 15 Jun 2011 12:03:23 +0800 |
parents | fe1ebf0c3d40 |
children | 0b9ac7cef6e5 |
line wrap: on
line source
## # Implement a xpath liked query language. # # \section predicate Predicate # Structpath uses syntax of Python for predicate. That means you must use # '==' instead of '='. # class context(object): all_classes = None class_instances = None root = None objs = None def __init__(self, objs, ctx=None): if ctx: self.all_classes = ctx.all_classes self.class_instances = ctx.class_instances self.root = ctx.root pass self.objs = objs pass def get_parent(self, obj): raise NotImplementedError, 'get_parent() is not implemented' pass def _path_split(path): parts = [p.strip() for p in path.split('/')] return parts def _is_abs(path_parts): if len(path_parts) == 0: return False return path_parts[0] == '' def _rel_of_abs(path_parts): return path_parts[1:] def _is_class(part): return part.startswith('.') def _class_name(part): return part[1:] def _is_parent_name(part): return part == '..' def _split_attr_pred(part): try: lq_idx = part.index('[') except: return part, '' return part[:lq_idx].strip(), part[lq_idx:].strip() def _eval_obj_sub_pred(ctx, obj, sub_pred): ns_global = {} for attr in dir(obj): if attr.startswith('_'): continue v = _obj_attr(obj, attr) ns_global[attr] = v pass truth_v = eval(sub_pred, ns_global) return truth_v def _split_pred_into_subs(pred): striped_pred = pred.strip(' []\n\r') subs = striped_pred.split('][') return subs def _eval_obj_pred(ctx, obj, pred): subs = _split_pred_into_subs(pred) for sub in subs: if not sub: continue if not _eval_obj_sub_pred(ctx, obj, sub): return False pass return True def _obj_attr(obj, attrname): if isinstance(obj, list): idx = int(attrname) return obj[idx] elif isinstance(obj, dict): key = eval(attrname) return obj[key] return getattr(obj, attrname) def _handle_path_part_obj(ctx, part, obj): attr, pred = _split_attr_pred(part) if _is_parent_name(attr): new_objs = [ctx.get_parent(obj)] elif _is_class(attr): class_name = _class_name(attr) new_objs = ctx.class_instances[class_name] else: try: new_objs = [_obj_attr(obj, attr)] except AttributeError: return [] pass new_objs = filter((lambda x: _eval_obj_pred(ctx, x, pred)), new_objs) return new_objs def _handle_path_part(ctx, part): from itertools import chain if not ctx.objs: ctx = ctx.__class__([ctx.root], ctx) pass objss = [_handle_path_part_obj(ctx, part, obj) for obj in ctx.objs] objs = [o for o in chain(*objss)] new_ctx = ctx.__class__(objs, ctx) return new_ctx def _handle_path_parts(ctx, path_parts): if _is_abs(path_parts): ctx = ctx.__class__([ctx.root], ctx) path_parts = _rel_of_abs(path_parts) pass if len(path_parts) == 1 and path_parts[0] == '': return ctx for path_part in path_parts: ctx = _handle_path_part(ctx, path_part) pass return ctx def find_objs_path(ctx, path): path_parts = _path_split(path) rctx = _handle_path_parts(ctx, path_parts) return rctx.objs