Edgewall Software

Changeset 642

Show
Ignore:
Timestamp:
06/24/07 10:10:47 (2 years ago)
Author:
athomas
Message:

Add XPath matches() function which, of course, supports the Python regular
expression sytax.

Location:
trunk/genshi
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/genshi/path.py

    r622 r642  
    756756        return 'contains(%r, %r)' % (self.string1, self.string2) 
    757757 
     758class MatchesFunction(Function): 
     759    """The `matches` function, which returns whether a string matches a regular 
     760    expression. 
     761    """ 
     762    __slots__ = ['string1', 'string2'] 
     763    flag_mapping = {'s': re.S, 'm': re.M, 'i': re.I, 'x': re.X} 
     764 
     765    def __init__(self, string1, string2, flags=''): 
     766        self.string1 = string1 
     767        self.string2 = string2 
     768        self.flags = self._map_flags(flags) 
     769    def __call__(self, kind, data, pos, namespaces, variables): 
     770        string1 = as_string(self.string1(kind, data, pos, namespaces, variables)) 
     771        string2 = as_string(self.string2(kind, data, pos, namespaces, variables)) 
     772        return re.search(string2, string1, self.flags) 
     773    def _map_flags(self, flags): 
     774        return reduce(lambda a, b: a | b, 
     775                      [self.flag_map[flag] for flag in flags], re.U) 
     776    def __repr__(self): 
     777        return 'contains(%r, %r)' % (self.string1, self.string2) 
     778 
    758779class FalseFunction(Function): 
    759780    """The `false` function, which always returns the boolean `false` value.""" 
     
    978999_function_map = {'boolean': BooleanFunction, 'ceiling': CeilingFunction, 
    9791000                 'concat': ConcatFunction, 'contains': ContainsFunction, 
    980                  'false': FalseFunction, 'floor': FloorFunction, 
    981                  'local-name': LocalNameFunction, 'name': NameFunction, 
    982                  'namespace-uri': NamespaceUriFunction, 
     1001                 'matches': MatchesFunction, 'false': FalseFunction, 'floor': 
     1002                 FloorFunction, 'local-name': LocalNameFunction, 'name': 
     1003                 NameFunction, 'namespace-uri': NamespaceUriFunction, 
    9831004                 'normalize-space': NormalizeSpaceFunction, 'not': NotFunction, 
    9841005                 'number': NumberFunction, 'round': RoundFunction, 
    985                  'starts-with': StartsWithFunction, 
    986                  'string-length': StringLengthFunction, 
    987                  'substring': SubstringFunction, 
    988                  'substring-after': SubstringAfterFunction, 
    989                  'substring-before': SubstringBeforeFunction, 
    990                  'translate': TranslateFunction, 'true': TrueFunction} 
     1006                 'starts-with': StartsWithFunction, 'string-length': 
     1007                 StringLengthFunction, 'substring': SubstringFunction, 
     1008                 'substring-after': SubstringAfterFunction, 'substring-before': 
     1009                 SubstringBeforeFunction, 'translate': TranslateFunction, 
     1010                 'true': TrueFunction} 
    9911011 
    9921012# Literals & Variables 
  • trunk/genshi/tests/path.py

    r505 r642  
    329329        self.assertEqual('<foo>bar</foo>', path.select(xml).render()) 
    330330 
     331    def test_predicate_matches_function(self): 
     332        xml = XML('<root><foo>bar</foo><bar>foo</bar></root>') 
     333        path = Path('*[matches(name(), "foo|bar")]') 
     334        self.assertEqual('<foo>bar</foo><bar>foo</bar>', path.select(xml).render()) 
     335 
    331336    def test_predicate_false_function(self): 
    332337        xml = XML('<root><foo>bar</foo></root>')