Search code examples
jspescapingjstl

How to unescape HTML tags with JSTL


I have to show some content with already escaped HTML tags in page with JSTL.

I know that theexcapeXml is for escaping characters that can be interpreted as markup. But seems it's only working for plain and unescaped HTML: <p>This is the news</p>, it doesn't work correctly for already escaped HTML: &lt;p&gt;This is the news&lt;/p&gt;.

So, how can I unescape already escaped HTML with JSTL?


Solution

  • JSTL doesn't offer tags or functions specifically for unescaping HTML (nor XML). Your closest bet is the fn:replace() as shown below assuming that the unescaped HTML content in question is provided via ${bean.content}.

    <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
    ...
    ${fn:replace(fn:replace(bean.content, '&lt;','<'), '&gt;','>')}
    

    It only becomes ugly and tedious in case you have more characters which need to be unescaped than only < and >.

    Your safest bet is to bring in a custom EL function which in turn invokes Apache Commons Lang StringEscapeUtils#unescapeXml() or perhaps unescapeHtml4() method. If not done yet, download and drop commons-lang.jar in /WEB-INF/lib. Then create a /WEB-INF/functions.tld file like below:

    <?xml version="1.0" encoding="UTF-8" ?>
    <taglib 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
        version="2.1">
    
        <display-name>Custom Functions</display-name>    
        <tlib-version>1.0</tlib-version>
        <short-name>f</short-name>
        <uri>http://example.com/functions</uri>
    
        <function>
            <name>unescapeXml</name>
            <function-class>org.apache.commons.lang3.StringEscapeUtils</function-class>
            <function-signature>java.lang.String unescapeXml(java.lang.String)</function-signature>
        </function>
    </taglib>
    

    Finally just use it as below:

    <%@taglib prefix="f" uri="http://example.com/functions" %>
    ...
    ${f:escapeXml(bean.content)}
    

    Unrelated to the concrete question, I would personally take a step back. Why exactly do you have escaped HTML at hands in first place? This is strange. Normally, escaping is supposed to happen during HTML-rendering only. I'd rather lookup the one responsible for escaping that HTML and then change it as such that it doesn't unnecessarily escape HTML anymore. Perhaps the one responsible for that didn't really understand the concepts around HTML-escaping in web pages and manually performed escaping during request processing as part of an unthoughtful XSS prevention attempt. This is then food for read: XSS prevention in JSP/Servlet web application.