23

I need to change " to \" with JSTL replace function to use the string in input tag like:

<input type="hidden" name="text" size="40" value="${text}">

If the ${text} has the ", the HTML will be broken.

So I tried

<input type="hidden" name="text" size="40" value="${fn:replace(text, "\"", "\\\""}">

and

<input type="hidden" name="text" size="40" value="${fn:replace(text, '"', '\"'}">

but didn't worked. The page makes errors like

org.apache.el.parser.ParseException: Encountered " "}" "} "" at line 1, column 32. Was expecting one of: "." ... ")" ... "[" ... "," ... ">" ... "gt" ... "<" ... "lt" ... ">=" ... "ge" ... "<=" ... "le" ... "==" ... "eq" ... "!=" ... "ne" ... "&&" ... "and" ... "||" ... "or" ... "*" ... "+" ... "-" ... "/" ... "div" ... "%" ... "mod" ...

How can I do this?

Update

I missed a close paren of replace function. The right one was this one with a close paren:

<input type="hidden" name="text" size="40" value="${fn:replace(text, '"', '\"')}">

Update2

I found out that when posting texts, using \ is not a good idea because of this reason why can't use \" in HTML input tag?. The code should be like this:

<input type="hidden" name="text" size="40" value="${fn:replace(text, '"', '&quot;')}">
Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
Sanghyun Lee
  • 21,644
  • 19
  • 100
  • 126

3 Answers3

27

It doesn't work because the \ is an escape character in Java string. To represent it literally, you need to escape it with another \ again. Also the " is a special character in EL, you also need to escape it to represent it literally. So, the proper syntax would have been:

<input type="hidden" name="text" size="40" value="${fn:replace(text, '\"', '\\\"')}">

But, you should actually be using fn:escapeXml() to prevent XSS. It not only escapes quotes, but also other characters.

<input type="hidden" name="text" size="40" value="${fn:escapeXml(text)}">

###See also:

Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • To anyone who downvoted or intend to downvote, please note that the question is about escaping for HTML, not escaping for JavaScript :) – BalusC Apr 02 '13 at 18:35
  • For escaping for JavaScript, the first method using replace is the appropriate way, right? – IcedDante Oct 01 '14 at 21:53
  • fn:escapeXml is only suitable when you want to escape XML. What if you just want to escape strings? – mcv Jan 06 '15 at 14:34
  • @mcv: "escape strings" doesn't make any sense. There's "escape XML", "escape HTML", "escape Java", "escape JavaScript", etc. Don't you actually mean "escape JavaScript"? That's namely where many JSP starters fall over. – BalusC Jan 06 '15 at 14:47
  • @BalusC I meant escaping quotes in a string. You're right that how to do that depends on the language, and in my case that's indeed Javascript. Neither fn:replace nor fn:escapeXml worked for me, but a new escapeEcmaScript function that encapsulated the Apache StringEscapeUtils.escapeEcamScript() does the trick. – mcv Jan 06 '15 at 15:34
  • @mvc: Surely they won't work. See also the 1st comment here above and this related Q: http://stackoverflow.com/q/9708242/ – BalusC Jan 06 '15 at 15:40
  • It should not use fn:escapeXml because it's in an html attribute. Simply escape quote would be sufficient. See https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.232_-_Attribute_Escape_Before_Inserting_Untrusted_Data_into_HTML_Common_Attributes for more details. – rlm Dec 22 '15 at 16:18
  • It worked for me. I was able to use a request attribute set in JSP using "setAttribute()" to be used for the "text" parameter. – tarekahf Jul 24 '20 at 22:15
6

You are doing it wrong (with fn:replace).

The correct way is:

<input type="hidden" name="text" size="40" value="<c:out value='${text}'/>">
(actually tested code - works 100%)

Edit: Upon more thinking:

  • the way by using fn:escapeXml (as written by BalusC) works too and looks nicer (no nested tags)
  • using fn:replace to mimick fn:escapeXml is asking for trouble. You will forget to include some character that should be escaped. Just use the existing, tried and tested fn:escapeXml (or c:out)
David Balažic
  • 1,319
  • 1
  • 23
  • 50
4

You may have a typo: I don't see a closing paren in there. Try this:

${fn:replace(news.title, "\"", "\\\"")}

Also, are you trying to OUTPUT the results or are you trying to update news.title so the next time you access news.title the replacement is in place? This will work to output the result, but not to replace the actual value: news.title will not be changed by this call.

Femi
  • 64,273
  • 8
  • 118
  • 148
  • You're right, the closing paren was missed. I was so foolish. I don't need to replace the actual value. I have one more question. How can I make it work in an input tag? – Sanghyun Lee Aug 18 '11 at 02:01
  • This one `${fn:replace(news.title, '\"', '\\\"')}` worked. Thanks. – Sanghyun Lee Aug 18 '11 at 02:03
  • Hey not sure why but for some reason i get exception in my attempt to escape double quotes .... error in logs: 14:42:47,564 WARNING [com.ingenta.jsp.skins] [guest,48101,48081] Setting Exception in page: javax.servlet.jsp.JspException: javax.servlet.jsp.JspException: javax.el.ELException: Error Parsing: ${fn:replace(pagePublicationName, '\"', '\\\"')} – Angus Grant Aug 16 '19 at 14:49