DisplayTag

problem for single quote escaping for single quote character in displaytag column tags using escapeXML="true"

Details

  • Type: Bug Bug
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

It appears that displaytag escapes (when escapeXml="true") a single quote with '
c:out and bean:write tags escape it with '
The problem is that while Firefox and Safari understand ', Internet Explorer does not. All three browsers understand '.

This means that all single quotes in displaytag tables will appear as ugly "'".

This might be related to issue: maven-83: xdocs entity encoding problem for single quote

If there is a known workaround, could you let me know? thanks.

Activity

Hide
Paul Sammy added a comment -
My workaround is to modify the standard org.displaytag.decorator.EscapeXmlColumnDecorator class to do a search and replace on the unsupported alphanumeric entity and replace it with the numeric entity.

So:

            // escape the contents
            returnValue = StringEscapeUtils.escapeXml(columnValue.toString());
            // because IE doesn't understand ' we replace with '
            if (StringUtils.contains(returnValue.toString(), "'")) {
                // tis found
                returnValue =
                    StringUtils.replace(
                        returnValue.toString(),
                        "'",
                        "'");
            }

then in the jsp, instead of using escapeXml="true", you need to do decorator="foo.blah.myclass"
Show
Paul Sammy added a comment - My workaround is to modify the standard org.displaytag.decorator.EscapeXmlColumnDecorator class to do a search and replace on the unsupported alphanumeric entity and replace it with the numeric entity. So:             // escape the contents             returnValue = StringEscapeUtils.escapeXml(columnValue.toString());             // because IE doesn't understand ' we replace with '             if (StringUtils.contains(returnValue.toString(), "'")) {                 // tis found                 returnValue =                     StringUtils.replace(                         returnValue.toString(),                         "'",                         "'");             } then in the jsp, instead of using escapeXml="true", you need to do decorator="foo.blah.myclass"
Hide
Dmitri Schoeman added a comment -
I think the core issue is that the EscapeXmlColumnDecorator is calling StringEscapeUtils.escapeXml()

Apache is doing what they are asked: in XML it is appropriate to escape a single quote. I think the behavior should probably be to call StringEscapeUtils.escapeHtml instead, which understands that a ' should not be escaped in HTML.

My workaround is to create my own Decorator as Paul has done, but rather than try to undo the wrong parts that escapeXML causes, I just directly call escapeHTML.

I think this would also be the appropriate fix for the EscapeXmlColumnDecorator class itself.

  if (columnValue == null || (!media.equals(MediaTypeEnum.HTML) && !media.equals(MediaTypeEnum.XML)))
        {
            return columnValue;
        }

        return StringEscapeUtils.escapeHtml(columnValue.toString());



Show
Dmitri Schoeman added a comment - I think the core issue is that the EscapeXmlColumnDecorator is calling StringEscapeUtils.escapeXml() Apache is doing what they are asked: in XML it is appropriate to escape a single quote. I think the behavior should probably be to call StringEscapeUtils.escapeHtml instead, which understands that a ' should not be escaped in HTML. My workaround is to create my own Decorator as Paul has done, but rather than try to undo the wrong parts that escapeXML causes, I just directly call escapeHTML. I think this would also be the appropriate fix for the EscapeXmlColumnDecorator class itself.   if (columnValue == null || (!media.equals(MediaTypeEnum.HTML) && !media.equals(MediaTypeEnum.XML)))         {             return columnValue;         }         return StringEscapeUtils.escapeHtml(columnValue.toString());
Hide
Manuel Dominguez Sarmiento added a comment -
escapeHtml is not really the solution, since this will be used on XML exports as well, and escapeHtml also escapes ALL KNOWN HTML entities, which are quite a few, and are invalid in XML.

The solution is to use the following code, which works for both markup languages, and is in fact the approach used by the standard Apache JSTL implementation:

<pre>
/**
 * Safely escapes XML reserved characters for use both within XML and HTML
 * contexts.
 *
 */
public class SafeXmlEscaper {

/**
* Safely escapes XML reserved characters from the input string.
*
* @param s
* the input string.
* @return the escaped string.
*/
public static String escapeXml(String s) {
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
switch (c) {
case '&':
sb.append("&amp;");
break;
case '<':
sb.append("&lt;");
break;
case '>':
sb.append("&gt;");
break;
case '"':
sb.append("&#034;");
break;
case '\'':
sb.append("&#039;");
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
}
}
</pre>
Show
Manuel Dominguez Sarmiento added a comment - escapeHtml is not really the solution, since this will be used on XML exports as well, and escapeHtml also escapes ALL KNOWN HTML entities, which are quite a few, and are invalid in XML. The solution is to use the following code, which works for both markup languages, and is in fact the approach used by the standard Apache JSTL implementation: <pre> /**  * Safely escapes XML reserved characters for use both within XML and HTML  * contexts.  *  */ public class SafeXmlEscaper { /** * Safely escapes XML reserved characters from the input string. * * @param s * the input string. * @return the escaped string. */ public static String escapeXml(String s) { StringBuilder sb = new StringBuilder(); for (char c : s.toCharArray()) { switch (c) { case '&': sb.append("&amp;"); break; case '<': sb.append("&lt;"); break; case '>': sb.append("&gt;"); break; case '"': sb.append("&#034;"); break; case '\'': sb.append("&#039;"); break; default: sb.append(c); break; } } return sb.toString(); } } </pre>
Hide
Don Mornes added a comment -
Dmitri Schoeman,

Shouldn't you use StringEscapeUtils.escapeXml when the media type is XML?

Here is my decorator.

package graco.service.util;

import javax.servlet.jsp.PageContext;
import org.displaytag.decorator.DisplaytagColumnDecorator;
import org.displaytag.exception.DecoratorException;
import org.displaytag.properties.MediaTypeEnum;
import org.apache.commons.lang.StringEscapeUtils;
/**
* Simple column decorator which escapes HTML.
* @author Don Mornes
* @version $Revision: 1.0 $ ($Author: qadhm1 $)
*/
public class EscapeHtmlWrapper implements DisplaytagColumnDecorator {
/**
* transform the String with escapeHTML
* @see org.displaytag.decorator.DisplaytagColumnDecorator#decorate(Object, PageContext, MediaTypeEnum)
*/
public Object decorate(
Object columnValue,
PageContext pageContext,
MediaTypeEnum media)
throws DecoratorException
{
if (columnValue == null) {
return columnValue;
} else
if (media.equals(MediaTypeEnum.HTML)) {
return StringEscapeUtils.escapeHtml((String)columnValue);
} else
if (media.equals(MediaTypeEnum.XML)) {
return StringEscapeUtils.escapeXml((String)columnValue);
} else {
return columnValue;
}
}
}


Show
Don Mornes added a comment - Dmitri Schoeman, Shouldn't you use StringEscapeUtils.escapeXml when the media type is XML? Here is my decorator. package graco.service.util; import javax.servlet.jsp.PageContext; import org.displaytag.decorator.DisplaytagColumnDecorator; import org.displaytag.exception.DecoratorException; import org.displaytag.properties.MediaTypeEnum; import org.apache.commons.lang.StringEscapeUtils; /** * Simple column decorator which escapes HTML. * @author Don Mornes * @version $Revision: 1.0 $ ($Author: qadhm1 $) */ public class EscapeHtmlWrapper implements DisplaytagColumnDecorator { /** * transform the String with escapeHTML * @see org.displaytag.decorator.DisplaytagColumnDecorator#decorate(Object, PageContext, MediaTypeEnum) */ public Object decorate( Object columnValue, PageContext pageContext, MediaTypeEnum media) throws DecoratorException { if (columnValue == null) { return columnValue; } else if (media.equals(MediaTypeEnum.HTML)) { return StringEscapeUtils.escapeHtml((String)columnValue); } else if (media.equals(MediaTypeEnum.XML)) { return StringEscapeUtils.escapeXml((String)columnValue); } else { return columnValue; } } }

People

Vote (5)
Watch (5)

Dates

  • Created:
    Updated: