DisplayTag
  1. DisplayTag
  2. DISPL-387

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

          • Reporter:
            ruth shacter
          • Votes:
            5 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated: