diff 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 diff
--- a/paraspace/structpath.py	Wed Jun 15 02:33:54 2011 +0800
+++ b/paraspace/structpath.py	Wed Jun 15 12:03:23 2011 +0800
@@ -1,6 +1,10 @@
 ##
 # 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
@@ -49,6 +53,46 @@
     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)
@@ -60,17 +104,22 @@
 
 
 def _handle_path_part_obj(ctx, part, obj):
-    if _is_parent_name(part):
+    attr, pred = _split_attr_pred(part)
+    
+    if _is_parent_name(attr):
         new_objs = [ctx.get_parent(obj)]
-    elif _is_class(part):
-        class_name = _class_name(part)
+    elif _is_class(attr):
+        class_name = _class_name(attr)
         new_objs = ctx.class_instances[class_name]
     else:
         try:
-            new_objs = [_obj_attr(obj, part)]
+            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