Jinja2 filter to convert custom markup to html

2019-06-24 15:04发布

问题:

Having the autoescape property on (I want to keep it that way), I want user to be able to enter some custom markup, to have the opportunity to format text. For example, [s][/s] will be translated into <strong></strong>. I believe the right way to do this is to write the custom Jinja2 filter. But the following doesn't work:

@app.template_filter()
@evalcontextfilter
def mark2html(eval_ctx, value):
    result = escape(value).replace('[s]','<strong>')
    if eval_ctx.autoescape:
        result = Markup(result)
    return result

When applied to text like

<div>{{ custom_markup_text|mark2html }}</div>

When [s] is encountered in the string, stored in custom_markup_text, it should be converted to <strong> tag. AFAIK, Markup() function ensures that we trust this particular string, so that HTML is not escaped there. The filter is successfully applied, [s] is replaced by <strong>, but it's still escaped.

Obviously, the autoescaping is done after this custom filter. On the other hand, example filter from Jinja2 documentation works perfectly:

@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
    result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', '<br>\n') \
        for p in _paragraph_re.split(escape(value)))
    if eval_ctx.autoescape:
        result = Markup(result)
    return result

What am I doing wrong?

回答1:

Problem found. It's double escaping the string - rather silly. This code works flawlessly:

@app.template_filter()
@evalcontextfilter
def mark2html(eval_ctx, value):
    result = value.replace('[s]',u'<strong>')
    result = result.replace('[/s]',u'</strong>')
    if eval_ctx.autoescape:
        result = Markup(result)
    return result

Note, value shouldn't be escaped, as autoescape property is on.