Edgewall Software

Opened 17 years ago

Last modified 14 years ago

#91 new defect

naive use of concat in Path expresions causes obscure trace backs

Reported by: robinbryce@… Owned by: cmlenz
Priority: minor Milestone:
Component: XPath support Version: devel
Keywords: Cc: rbryce@…

Description

an example of naive use:

    <py:with vars="var='greeting'">
        <p py:match='.[p and @id=concat($var,"_7")]' py:attrs='select("@*")'>
        matched
        </p>
        <p id="greeting_7">not matched</p>
    </py:with>

    <py:for each="suffix in map(str, range(1,4))">
    <p>$suffix</p>
    </py:for> 

And the tail of the traceback

  File "/home/rbryce/devel-appliance/Genshi-0.3.6-py2.4.egg/genshi/path.py", line 671, in __call__
    return u''.join(strings)
TypeError: sequence item 0: expected string or Unicode, NoneType found

The issue is that the "var" in @id=concat($var,"_7") is lazily evaluated in the context of every candidate victim expresion. So, within the py:with, it's fine. Once the py:with scope closes, type(var) is Undefined. This kills genshi.path.ConcatFunction.__call__, as it assumes all expressions ultimately resolve to strings; but in the $var case its not a string and we get TypeError.

I think this should be some genshi equivelent of RuntimeError('This probably means you have not passed in the appropriate template global variables'). Certainly not SyntaxError or TypeError

I couldn't decide what I'd like to happen here: In the particular case of concat it only operates on strings and I was tempted to suggest some means of providing $<eager> (or perhaps $<static> is less gnomic, ) variables, which would get fully and permanently bound when the Function is constructed. Factoring this into the Path parser and template processing is far from minor surgery.

Would it be a useful feature ? On reflection, probably not so much. I was essentially attempting to templatize the template: Ie, procedurally generating a bunch of similar match templates. Given the way match templates are applied this is probably more than a little foolish (I've got a small set of 'well known divs' and a collection of 'similar' match templates that apply to each), and use of other XPath functions with a single match template are, I think, the right answer for me.

Posting this ticket in the hope of some free advice ;-)

Change History (3)

comment:1 Changed 17 years ago by cmlenz

  • Milestone 0.4 deleted

Hmm, I'm not sure what would be the right thing to do here. Nothing for 0.4 anyway.

comment:2 Changed 14 years ago by Carsten Klein <carsten.klein@…>

The py:match is still within the context of the py:with statement.

The main cause of the problem is actually, that upon call the provably available variable references will not be looked up in the context that is provided on call.

Instead, it will just as_string() the argument.

Perhaps calling interpolate(...) and then iterating over the stream returned by that function should do the trick?

e.g. upon ConcatFunction?.call

for ... in interpolate(...):

if ... TEXT:

buf.append(as_string(...))

elif ... EXPR:

buf.append(as_string(expr.evaluate(ctxt)))

and so on.

This then would have to be enabled for most of the existing directives in the path module.

comment:3 Changed 14 years ago by Carsten Klein <carsten.klein@…>

See also #55 which provides an initial proposal for a patch.

Note: See TracTickets for help on using tickets.