Changeset 2740:badab58aeb50 in livinglogic.python.xist

Show
Ignore:
Timestamp:
07/02/07 18:11:42 (12 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Change walk implementation to simplify using selectors: Walk filters must
now always be WalkFilter? instances (and implement the filter() method),
i.e. callables passed to walk() will be turned into CallableSelectors?.

Let FindTyp?, FindTypeAll? etc. inherit from WalkFilter?.

Add CallableWalkFilter? and ConstantWalkFilter? (the former to still be able
to generate a WalkFilter? from a callable, the later to be able to pass
contant filter results to walk() without having to special case them
(i.e. the walk implementation can now simply do filter.filter(path)).

Add selectors hasname() and hasname_xml() to xfind.py.

Rename idis selctor to hasid (and use the XML name "id" for getting at
the attribute).

Location:
src/ll/xist
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • src/ll/xist/xfind.py

    r2739 r2740  
    3232 
    3333def makeselector(obj): 
    34     if isinstance_(obj, type) and issubclass(obj, xsc.Node): 
    35         obj = isinstance(obj) 
    36     elif callable(obj) and not isinstance_(obj, Selector): 
    37         obj = CallableSelector(obj) 
     34    if not isinstance_(obj, xsc.WalkFilter): 
     35        if isinstance_(obj, type) and issubclass(obj, xsc.Node): 
     36            obj = isinstance(obj) 
     37        elif callable(obj): 
     38            obj = CallableSelector(obj) 
     39        else: 
     40            obj = xsc.ConstantWalkFilter(obj) 
    3841    return obj 
    3942 
    4043 
    41 class Selector(xsc.FindVisitAll): 
     44class Selector(xsc.WalkFilter): 
     45    """ 
     46    Base class for all tree traversal filters that visit the complete tree. 
     47    Whether a node get output can be specified by overwriting the 
     48    <method>match</method> method. 
     49    """ 
     50 
     51    @misc.notimplemented 
     52    def match(self, path): 
     53        pass 
     54 
     55    def filter(self, path): 
     56        return (True, xsc.entercontent, xsc.enterattrs) if self.match(path) else (xsc.entercontent, xsc.enterattrs) 
     57 
    4258    def __div__(self, other): 
    4359        return ChildCombinator(self, makeselector(other)) 
     
    7692        else: 
    7793            return "%s(%s)" % (self.__class__.__name__, ", ".join("%s.%s" % (type.__module__, type.__name__) for type in self.types)) 
     94 
     95 
     96class hasname(Selector): 
     97    def __init__(self, name): 
     98        self.name = name 
     99 
     100    def match(self, path): 
     101        if path: 
     102            return path[-1].__class__.__name__ == self.name 
     103        return False 
     104 
     105    def __repr__(self): 
     106        return "%s(%r)" % (self.__class__.__name__, self.name) 
     107 
     108 
     109class hasname_xml(Selector): 
     110    def __init__(self, name): 
     111        self.name = name 
     112 
     113    def match(self, path): 
     114        if path: 
     115            return path[-1].xmlname == self.name 
     116        return False 
     117 
     118    def __repr__(self): 
     119        return "%s(%r)" % (self.__class__.__name__, self.name) 
    78120 
    79121 
     
    356398 
    357399 
    358 class idis(Selector): 
     400class hasid(Selector): 
    359401    def __init__(self, id): 
    360402        self.id = id 
    361403 
    362404    def match(self, path): 
    363         if not path: 
    364             return False 
    365         node = path[-1] 
    366         return isinstance_(node, xsc.Element) and node.Attrs.isallowed("id") and not node.attrs.id.isfancy() and unicode(node.attrs.id) == self.id 
     405        if path: 
     406            node = path[-1] 
     407            if isinstance_(node, xsc.Element) and node.Attrs.isallowed_xml("id"): 
     408                attr = node.attrs.get_xml("id") 
     409                if not attr.isfancy() and unicode(attr) == self.id: 
     410                    return True 
     411        return False 
    367412 
    368413    def __repr__(self): 
     
    9891034                rule.type = value 
    9901035            elif type == "id": 
    991                 rule.selectors.append(idis(value.lstrip("#"))) 
     1036                rule.selectors.append(hasid(value.lstrip("#"))) 
    9921037            elif type == "classname": 
    9931038                rule.selectors.append(hasclass(value)) 
  • src/ll/xist/xsc.py

    r2737 r2740  
    107107 
    108108### 
    109 ### Common tree traversal filters 
     109### Common walk filters 
    110110### 
    111111 
    112 class FindType(object): 
     112class WalkFilter(object): 
     113    """ 
     114    A <class>WalkFilter</class> can be passed to the 
     115    <pyref class="Node" method="walk"><method>walk</method></pyref> method of 
     116    nodes to specify how to traverse the tree and which nodes to output. 
     117    """ 
     118    @misc.notimplemented 
     119    def filter(self, path): 
     120        pass 
     121 
     122 
     123class FindType(WalkFilter): 
    113124    """ 
    114125    Tree traversal filter that finds nodes of a certain type on the first level 
     
    118129        self.types = types 
    119130 
    120     def __call__(self, path): 
     131    def filter(self, path): 
    121132        return (isinstance(path[-1], self.types), ) 
    122133 
    123134 
    124 class FindTypeAll(object): 
     135class FindTypeAll(WalkFilter): 
    125136    """ 
    126137    Tree traversal filter that finds nodes of a certain type searching the 
     
    130141        self.types = types 
    131142 
    132     def __call__(self, path): 
     143    def filter(self, path): 
    133144        return (isinstance(path[-1], self.types), entercontent) 
    134145 
    135146 
    136 class FindTypeAllAttrs(object): 
     147class FindTypeAllAttrs(WalkFilter): 
    137148    """ 
    138149    Tree traversal filter that finds nodes of a certain type searching the 
     
    142153        self.types = types 
    143154 
    144     def __call__(self, path): 
     155    def filter(self, path): 
    145156        return (isinstance(path[-1], self.types), entercontent, enterattrs) 
    146157 
    147158 
    148 class FindTypeTop(object): 
     159class FindTypeTop(WalkFilter): 
    149160    """ 
    150161    Tree traversal filter that finds nodes of a certain type searching the 
     
    155166        self.types = types 
    156167 
    157     def __call__(self, path): 
     168    def filter(self, path): 
    158169        if isinstance(path[-1], self.types): 
    159170            return (True,) 
     
    162173 
    163174 
    164 class FindVisitAll(object): 
    165     """ 
    166     Base class for all filters that visit the complete tree. 
    167     """ 
    168     @misc.notimplemented 
    169     def match(self, path): 
    170         pass 
    171  
    172     def __call__(self, path): 
    173         return (True, entercontent, enterattrs) if self.match(path) else (entercontent, enterattrs) 
     175class CallableWalkFilter(WalkFilter): 
     176    """ 
     177    Tree traversal filter that returns the result of a function call. 
     178    """ 
     179    def __init__(self, func): 
     180        self.func = func 
     181 
     182    def filter(self, path): 
     183        return self.func(path) 
     184 
     185 
     186class ConstantWalkFilter(WalkFilter): 
     187    """ 
     188    Tree traversal filter that returns the same value for all nodes. 
     189    """ 
     190    def __init__(self, value): 
     191        self.value = value 
     192 
     193    def filter(self, path): 
     194        return self.value 
    174195 
    175196 
     
    935956        <par>Internal helper for <pyref method="walk"><method>walk</method></pyref>.</par> 
    936957        """ 
    937         if callable(filter): 
    938             found = filter(path) 
    939         else: 
    940             found = filter 
    941  
    942         for option in found: 
     958        for option in filter.filter(path): 
    943959            if option is not entercontent and option is not enterattrs and option: 
    944960                yield path 
     
    9931009        of the list being the same across calls to <method>next</method>.</par> 
    9941010        """ 
     1011        from ll.xist import xfind 
     1012        filter = xfind.makeselector(filter) 
    9951013        return self._walk(filter, [self]) 
    9961014 
     
    10021020        """ 
    10031021        from ll.xist import xfind 
    1004         if isinstance(filter, type) and issubclass(filter, Node): 
    1005             filter = xfind.isinstance(filter) 
     1022        filter = xfind.makeselector(filter) 
    10061023        def iterate(path): 
    10071024            for path in self._walk(filter, path): 
     
    10161033        """ 
    10171034        from ll.xist import xfind 
    1018         if isinstance(filter, type) and issubclass(filter, Node): 
    1019             filter = xfind.isinstance(filter) 
     1035        filter = xfind.makeselector(filter) 
    10201036        def iterate(path): 
    10211037            for path in self._walk(filter, path): 
     
    19491965 
    19501966    def _walk(self, filter, path): 
    1951         if callable(filter): 
    1952             found = filter(path) 
    1953         else: 
    1954             found = filter 
    1955  
    1956         for option in found: 
     1967        for option in filter.filter(path): 
    19571968            if option is entercontent: 
    19581969                for result in Frag._walk(self, filter, path): 
     
    30773088 
    30783089    def _walk(self, filter, path): 
    3079         if callable(filter): 
    3080             found = filter(path) 
    3081         else: 
    3082             found = filter 
    3083  
    3084         for option in found: 
     3090        for option in filter.filter(path): 
    30853091            if option is entercontent: 
    30863092                for result in self.content._walk(filter, path):