# HG changeset patch
# User athomas
# Date 1182672647 0
# Node ID cccb6c748609aa4e72585a304934ed75ecf982e3
# Parent dfb45908fadc593018f6702a8318ba3befbc9047
Add XPath `matches()` function which, of course, supports the Python regular
expression sytax.
diff --git a/genshi/path.py b/genshi/path.py
--- a/genshi/path.py
+++ b/genshi/path.py
@@ -755,6 +755,27 @@
def __repr__(self):
return 'contains(%r, %r)' % (self.string1, self.string2)
+class MatchesFunction(Function):
+ """The `matches` function, which returns whether a string matches a regular
+ expression.
+ """
+ __slots__ = ['string1', 'string2']
+ flag_mapping = {'s': re.S, 'm': re.M, 'i': re.I, 'x': re.X}
+
+ def __init__(self, string1, string2, flags=''):
+ self.string1 = string1
+ self.string2 = string2
+ self.flags = self._map_flags(flags)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string1 = as_string(self.string1(kind, data, pos, namespaces, variables))
+ string2 = as_string(self.string2(kind, data, pos, namespaces, variables))
+ return re.search(string2, string1, self.flags)
+ def _map_flags(self, flags):
+ return reduce(lambda a, b: a | b,
+ [self.flag_map[flag] for flag in flags], re.U)
+ def __repr__(self):
+ return 'contains(%r, %r)' % (self.string1, self.string2)
+
class FalseFunction(Function):
"""The `false` function, which always returns the boolean `false` value."""
__slots__ = []
@@ -977,17 +998,16 @@
_function_map = {'boolean': BooleanFunction, 'ceiling': CeilingFunction,
'concat': ConcatFunction, 'contains': ContainsFunction,
- 'false': FalseFunction, 'floor': FloorFunction,
- 'local-name': LocalNameFunction, 'name': NameFunction,
- 'namespace-uri': NamespaceUriFunction,
+ 'matches': MatchesFunction, 'false': FalseFunction, 'floor':
+ FloorFunction, 'local-name': LocalNameFunction, 'name':
+ NameFunction, 'namespace-uri': NamespaceUriFunction,
'normalize-space': NormalizeSpaceFunction, 'not': NotFunction,
'number': NumberFunction, 'round': RoundFunction,
- 'starts-with': StartsWithFunction,
- 'string-length': StringLengthFunction,
- 'substring': SubstringFunction,
- 'substring-after': SubstringAfterFunction,
- 'substring-before': SubstringBeforeFunction,
- 'translate': TranslateFunction, 'true': TrueFunction}
+ 'starts-with': StartsWithFunction, 'string-length':
+ StringLengthFunction, 'substring': SubstringFunction,
+ 'substring-after': SubstringAfterFunction, 'substring-before':
+ SubstringBeforeFunction, 'translate': TranslateFunction,
+ 'true': TrueFunction}
# Literals & Variables
diff --git a/genshi/tests/path.py b/genshi/tests/path.py
--- a/genshi/tests/path.py
+++ b/genshi/tests/path.py
@@ -328,6 +328,11 @@
path = Path('*[contains(name(), "oo")]')
self.assertEqual('bar', path.select(xml).render())
+ def test_predicate_matches_function(self):
+ xml = XML('barfoo')
+ path = Path('*[matches(name(), "foo|bar")]')
+ self.assertEqual('barfoo', path.select(xml).render())
+
def test_predicate_false_function(self):
xml = XML('bar')
path = Path('*[false()]')