def test_predicate_attr_equality(self): xml = XML('<root><item/><item important="notso"/></root>') path = Path('item[@important="very"]') self.assertEqual('', path.select(xml).render()) path = Path('item[@important!="very"]') self.assertEqual('<item/><item important="notso"/>', path.select(xml).render())
def _test_eval(self, path, equiv=None, input=None, output='', namespaces=None, variables=None): path = Path(path) if equiv is not None: self.assertEqual(equiv, repr(path)) if input is None: return rendered = path.select(input, namespaces=namespaces, variables=variables).render(encoding=None) msg = 'Bad output using whole path' msg += '\nExpected:\t%r' % output msg += '\nRendered:\t%r' % rendered self.assertEqual(output, rendered, msg) if len(path.paths) == 1: self._test_strategies(input, path.paths[0], output, namespaces=namespaces, variables=variables)
def test_attrwildcard_with_namespace(self): xml = XML('<root xmlns:f="FOO"><foo f:bar="baz"/></root>') path = Path('foo[@f:*]') self.assertEqual('<foo xmlns:ns1="FOO" ns1:bar="baz"/>', path.select(xml, namespaces={ 'f': 'FOO' }).render())
def test_wildcard_with_namespace(self): xml = XML('<root xmlns:f="FOO"><f:foo>bar</f:foo></root>') path = Path('f:*') self.assertEqual('<Path "child::f:*">', repr(path)) namespaces = {'f': 'FOO'} self.assertEqual('<foo xmlns="FOO">bar</foo>', path.select(xml, namespaces=namespaces).render())
def test_attr_selection(self): xml = XML('<root><foo bar="abc"></foo></root>') path = Path('foo/@bar') result = path.select(xml) self.assertEqual(list(result), [ Attrs([(QName('bar'), u'abc')]) ])
def test_attr_selection_with_namespace(self): xml = XML('<root xmlns:ns1="http://example.com">' '<foo ns1:bar="abc"></foo>' '</root>') path = Path('foo/@ns1:bar') result = path.select(xml, namespaces={'ns1': 'http://example.com'}) self.assertEqual(list(result), [Attrs([(QName('http://example.com}bar'), 'abc')])])
def test_1step_self(self): xml = XML('<root><elem/></root>') path = Path('.') self.assertEqual('<Path "self::node()">', repr(path)) self.assertEqual('<root><elem/></root>', path.select(xml).render()) path = Path('self::node()') self.assertEqual('<Path "self::node()">', repr(path)) self.assertEqual('<root><elem/></root>', path.select(xml).render())
def test_attr_selection_with_namespace(self): xml = XML( '<root xmlns:ns1="http://example.com">' '<foo ns1:bar="abc"></foo>' '</root>') path = Path('foo/@ns1:bar') result = path.select(xml, namespaces={'ns1': 'http://example.com'}) self.assertEqual(list(result), [ Attrs([(QName('http://example.com}bar'), u'abc')]) ])
def __init__(self, value, template, hints=None, namespaces=None, lineno=-1, offset=-1): Directive.__init__(self, None, template, namespaces, lineno, offset) self.path = Path(value, template.filepath, lineno) self.namespaces = namespaces or {} self.hints = hints or ()
def test_predicate_number_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[number("3.0")=3]') self.assertEqual('<foo>bar</foo>', path.select(xml).render()) path = Path('*[number("3.0")=3.0]') self.assertEqual('<foo>bar</foo>', path.select(xml).render()) path = Path('*[number("0.1")=.1]') self.assertEqual('<foo>bar</foo>', path.select(xml).render())
def test_predicate_termination(self): """ Verify that a patch matching the self axis with a predicate doesn't cause an infinite loop. See <http://genshi.edgewall.org/ticket/82>. """ xml = XML('<ul flag="1"><li>a</li><li>b</li></ul>') path = Path('.[@flag="1"]/*') self.assertEqual('<li>a</li><li>b</li>', path.select(xml).render()) xml = XML('<ul flag="1"><li>a</li><li>b</li></ul>') path = Path('.[@flag="0"]/*') self.assertEqual('', path.select(xml).render())
def test_3step_complex(self): xml = XML('<root><foo><bar/></foo></root>') path = Path('*/bar') self.assertEqual('<Path "child::*/child::bar">', repr(path)) self.assertEqual('<bar/>', path.select(xml).render()) xml = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>') path = Path('//bar') self.assertEqual('<Path "descendant-or-self::node()/child::bar">', repr(path)) self.assertEqual('<bar id="1"/><bar id="2"/>', path.select(xml).render())
def test_1step_attribute(self): path = Path('@foo') self.assertEqual('<Path "attribute::foo">', repr(path)) xml = XML('<root/>') self.assertEqual('', path.select(xml).render()) xml = XML('<root foo="bar"/>') self.assertEqual('bar', path.select(xml).render()) path = Path('./@foo') self.assertEqual('<Path "self::node()/attribute::foo">', repr(path)) self.assertEqual('bar', path.select(xml).render())
def test_node_type_processing_instruction(self): xml = XML('<?python x = 2 * 3 ?><root><?php echo("x") ?></root>') path = Path('processing-instruction()') self.assertEqual('<Path "child::processing-instruction()">', repr(path)) self.assertEqual('<?python x = 2 * 3 ?><?php echo("x") ?>', path.select(xml).render()) path = Path('processing-instruction("php")') self.assertEqual('<Path "child::processing-instruction(\"php\")">', repr(path)) self.assertEqual('<?php echo("x") ?>', path.select(xml).render())
def select(self, path, namespaces=None, variables=None): """Return a new stream that contains the events matching the given XPath expression. >>> from genshi import HTML >>> stream = HTML('<doc><elem>foo</elem><elem>bar</elem></doc>', encoding='utf-8') >>> print(stream.select('elem')) <elem>foo</elem><elem>bar</elem> >>> print(stream.select('elem/text()')) foobar Note that the outermost element of the stream becomes the *context node* for the XPath test. That means that the expression "doc" would not match anything in the example above, because it only tests against child elements of the outermost element: >>> print(stream.select('doc')) <BLANKLINE> You can use the "." expression to match the context node itself (although that usually makes little sense): >>> print(stream.select('.')) <doc><elem>foo</elem><elem>bar</elem></doc> :param path: a string containing the XPath expression :param namespaces: mapping of namespace prefixes used in the path :param variables: mapping of variable names to values :return: the selected substream :rtype: `Stream` :raises PathSyntaxError: if the given path expression is invalid or not supported """ from genshi.path import Path return Path(path).select(self, namespaces, variables)
class MatchDirective(Directive): """Implementation of the ``py:match`` template directive. >>> from genshi.template import MarkupTemplate >>> tmpl = MarkupTemplate('''<div xmlns:py="http://genshi.edgewall.org/"> ... <span py:match="greeting"> ... Hello ${select('@name')} ... </span> ... <greeting name="Dude" /> ... </div>''') >>> print tmpl.generate() <div> <span> Hello Dude </span> </div> """ __slots__ = ['path', 'namespaces'] ATTRIBUTE = 'path' def __init__(self, value, template, namespaces=None, lineno=-1, offset=-1): Directive.__init__(self, None, template, namespaces, lineno, offset) self.path = Path(value, template.filepath, lineno) self.namespaces = namespaces or {} def __call__(self, stream, ctxt, directives): ctxt._match_templates.append((self.path.test(ignore_context=True), self.path, list(stream), self.namespaces, directives)) return [] def __repr__(self): return '<%s "%s">' % (self.__class__.__name__, self.path.source)
def __init__(self, path): """Create selection. :param path: an XPath expression (as string) or a `Path` object """ if not isinstance(path, Path): path = Path(path) self.path = path
class MatchDirective(Directive): """Implementation of the ``py:match`` template directive. >>> from genshi.template import MarkupTemplate >>> tmpl = MarkupTemplate('''<div xmlns:py="http://genshi.edgewall.org/"> ... <span py:match="greeting"> ... Hello ${select('@name')} ... </span> ... <greeting name="Dude" /> ... </div>''') >>> print tmpl.generate() <div> <span> Hello Dude </span> </div> """ __slots__ = ['path', 'namespaces', 'hints'] def __init__(self, value, template, hints=None, namespaces=None, lineno=-1, offset=-1): Directive.__init__(self, None, template, namespaces, lineno, offset) self.path = Path(value, template.filepath, lineno) self.namespaces = namespaces or {} self.hints = hints or () def attach(cls, template, stream, value, namespaces, pos): hints = [] if type(value) is dict: if value.get('buffer', '').lower() == 'false': hints.append('not_buffered') if value.get('once', '').lower() == 'true': hints.append('match_once') if value.get('recursive', '').lower() == 'false': hints.append('not_recursive') value = value.get('path') return cls(value, template, frozenset(hints), namespaces, *pos[1:]), \ stream attach = classmethod(attach) def __call__(self, stream, directives, ctxt, **vars): ctxt._match_templates.append( (self.path.test(ignore_context=True), self.path, list(stream), self.hints, self.namespaces, directives)) return [] def __repr__(self): return '<%s "%s">' % (self.__class__.__name__, self.path.source)
class MatchDirective(Directive): """Implementation of the ``py:match`` template directive. >>> from genshi.template import MarkupTemplate >>> tmpl = MarkupTemplate('''<div xmlns:py="http://genshi.edgewall.org/"> ... <span py:match="greeting"> ... Hello ${select('@name')} ... </span> ... <greeting name="Dude" /> ... </div>''') >>> print(tmpl.generate()) <div> <span> Hello Dude </span> </div> """ __slots__ = ['path', 'namespaces', 'hints'] def __init__(self, value, template, hints=None, namespaces=None, lineno=-1, offset=-1): Directive.__init__(self, None, template, namespaces, lineno, offset) self.path = Path(value, template.filepath, lineno) self.namespaces = namespaces or {} self.hints = hints or () @classmethod def attach(cls, template, stream, value, namespaces, pos): hints = [] if type(value) is dict: if value.get('buffer', '').lower() == 'false': hints.append('not_buffered') if value.get('once', '').lower() == 'true': hints.append('match_once') if value.get('recursive', '').lower() == 'false': hints.append('not_recursive') value = value.get('path') return cls(value, template, frozenset(hints), namespaces, *pos[1:]), \ stream def __call__(self, stream, directives, ctxt, **vars): ctxt._match_templates.append((self.path.test(ignore_context=True), self.path, list(stream), self.hints, self.namespaces, directives)) return [] def __repr__(self): return '<%s "%s">' % (type(self).__name__, self.path.source)
def test_2step_attribute(self): xml = XML('<elem class="x"><span id="joe">Hey Joe</span></elem>') self.assertEqual('x', Path('@*').select(xml).render()) self.assertEqual('x', Path('./@*').select(xml).render()) self.assertEqual('xjoe', Path('.//@*').select(xml).render()) self.assertEqual('joe', Path('*/@*').select(xml).render()) xml = XML('<elem><foo id="1"/><foo id="2"/></elem>') self.assertEqual('', Path('@*').select(xml).render()) self.assertEqual('12', Path('foo/@*').select(xml).render())
def test_1step(self): xml = XML('<root><elem/></root>') path = Path('elem') self.assertEqual('<Path "child::elem">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render()) path = Path('child::elem') self.assertEqual('<Path "child::elem">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render()) path = Path('//elem') self.assertEqual('<Path "descendant-or-self::node()/child::elem">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render()) path = Path('descendant::elem') self.assertEqual('<Path "descendant::elem">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render())
def test_2step_complex(self): xml = XML('<root><foo><bar/></foo></root>') path = Path('foo/bar') self.assertEqual('<Path "child::foo/child::bar">', repr(path)) self.assertEqual('<bar/>', path.select(xml).render()) path = Path('./bar') self.assertEqual('<Path "self::node()/child::bar">', repr(path)) self.assertEqual('', path.select(xml).render()) path = Path('foo/*') self.assertEqual('<Path "child::foo/child::*">', repr(path)) self.assertEqual('<bar/>', path.select(xml).render()) xml = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>') path = Path('./bar') self.assertEqual('<Path "self::node()/child::bar">', repr(path)) self.assertEqual('<bar id="2"/>', path.select(xml).render())
def test_paths_in_streams(exprs, streams, test_strategies=False): for expr in exprs: print("Testing path %r" % expr) for stream, sname in streams: print('\tRunning on "%s" example:' % sname) path = Path(expr) def f(): for e in path.select(stream): pass t = spell(benchmark(f)) print("\t\tselect:\t\t%s" % t) def f(): path = Path(expr) for e in path.select(stream): pass t = spell(benchmark(f)) print("\t\tinit + select:\t%s" % t) if test_strategies and len(path.paths) == 1: from genshi.path import ( GenericStrategy, SingleStepStrategy, SimplePathStrategy, ) from genshi.tests.path import FakePath strategies = (GenericStrategy, SingleStepStrategy, SimplePathStrategy) for strategy in strategies: if not strategy.supports(path.paths[0]): continue print("\t\t%s Strategy" % strategy.__name__) fp = FakePath(strategy(path.paths[0])) def f(): for e in fp.select(stream): pass t = spell(benchmark(f)) print("\t\t\tselect:\t\t%s" % t)
def test_1step_text(self): xml = XML('<root>Hey</root>') path = Path('text()') self.assertEqual('<Path "child::text()">', repr(path)) self.assertEqual('Hey', path.select(xml).render()) path = Path('./text()') self.assertEqual('<Path "self::node()/child::text()">', repr(path)) self.assertEqual('Hey', path.select(xml).render()) path = Path('//text()') self.assertEqual('<Path "descendant-or-self::node()/child::text()">', repr(path)) self.assertEqual('Hey', path.select(xml).render()) path = Path('.//text()') self.assertEqual('<Path "self::node()/descendant-or-self::node()/child::text()">', repr(path)) self.assertEqual('Hey', path.select(xml).render())
def test_1step_wildcard(self): xml = XML('<root><elem/></root>') path = Path('*') self.assertEqual('<Path "child::*">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render()) path = Path('child::*') self.assertEqual('<Path "child::*">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render()) path = Path('child::node()') self.assertEqual('<Path "child::node()">', repr(path)) self.assertEqual('<elem/>', Path('child::node()').select(xml).render()) path = Path('//*') self.assertEqual('<Path "descendant-or-self::node()/child::*">', repr(path)) self.assertEqual('<root><elem/></root>', path.select(xml).render())
def test_predicate_substring_before_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[substring-before(name(), "oo")="f"]') self.assertEqual('<foo>bar</foo>', path.select(xml).render())
def test_1step_wildcard(self): xml = XML('<root><elem/></root>') path = Path('*') self.assertEqual('<Path "child::*">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render()) path = Path('child::*') self.assertEqual('<Path "child::*">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render()) path = Path('child::node()') self.assertEqual('<Path "child::node()">', repr(path)) self.assertEqual('<elem/>', Path('child::node()').select(xml).render()) path = Path('//*') self.assertEqual('<Path "descendant-or-self::node()/child::*">', repr(path)) self.assertEqual('<elem/>', path.select(xml).render())
def test_predicate_normalize_space_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[normalize-space(" foo bar ")="foo bar"]') self.assertEqual('<foo>bar</foo>', path.select(xml).render())
def test_predicate_position_and_attr(self): xml = XML('<root><foo/><foo id="a1"/><foo id="a2"/></root>') path = Path('*[1][@id]') self.assertEqual('', path.select(xml).render()) path = Path('*[2][@id]') self.assertEqual('<foo id="a1"/>', path.select(xml).render())
def test_predicate_variable(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[name()=$bar]') variables = {'bar': 'foo'} self.assertEqual('<foo>bar</foo>', path.select(xml, variables=variables).render())
def test_predicate_string_length_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[string-length(name())=3]') self.assertEqual('<foo>bar</foo>', path.select(xml).render())
def test_predicate_true_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[true()]') self.assertEqual('<foo>bar</foo>', path.select(xml).render())
def test_attrwildcard_with_namespace(self): xml = XML('<root xmlns:f="FOO"><foo f:bar="baz"/></root>') path = Path('foo[@f:*]') self.assertEqual('<foo xmlns:ns1="FOO" ns1:bar="baz"/>', path.select(xml, namespaces={'f': 'FOO'}).render())
def test_predicate_starts_with_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[starts-with(name(), "f")]') self.assertEqual('<foo>bar</foo>', path.select(xml).render()) path = Path('*[starts-with(name(), "b")]') self.assertEqual('', path.select(xml).render())
def test_predicate_translate_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[translate(name(), "fo", "ba")="baa"]') self.assertEqual('<foo>bar</foo>', path.select(xml).render())
def test_predicate_floor_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[floor("4.5")=4]') self.assertEqual('<foo>bar</foo>', path.select(xml).render())
def test_predicate_position(self): xml = XML('<root><foo id="a1"/><foo id="a2"/><foo id="a3"/></root>') path = Path('*[2]') self.assertEqual('<foo id="a2"/>', path.select(xml).render())
def test_predicate_round_function(self): xml = XML('<root><foo>bar</foo></root>') path = Path('*[round("4.4")=4]') self.assertEqual('<foo>bar</foo>', path.select(xml).render()) path = Path('*[round("4.6")=5]') self.assertEqual('<foo>bar</foo>', path.select(xml).render())