Reputation: 23859
I want to initialize a Javascript variable from some JSON (generated via Jackson) in my JSPX, something like this:
<script>
var x = <c:out value="${myJson}" />;
</script>
But the output I get looks like:
<script>
var x = {"foo":"bar"};
</script>
I see what you did there, HTML-escaping the string. Obviously, I can't leave it completely unescaped because angle brackets in the data could break the page. But I don't really need all the quotes to be escaped, since I'm not putting the JSON within an attribute value, do I?
Now, this looks like it would be a perfectly valid way to write a script in HTML, just needlessly complicated (like, say, replacing spaces with As it turns out, it works just fine in XHTML, but with an HTML content type, I get an error, both in Firefox and IE. I'm not sure of the rationale, but that's how it is.  
).
So, what's the best approach here? Do I really want to simply escape angle brackets but not escape double quotes, or are there any other gotchas? Is there a tag out there that would replace c:out
(I know there are Spring tags for escaping Javascript, but that's still not the right kind of escaping)? How do people get this to work?
BTW, yes, I could make a separate AJAX call, but an extra round trip just to work around this problem seems silly.
UPDATE
I had a lot to learn about CDATA vs. PCDATA and how HTML is different from XHTML. Here I thought JSPX would make polyglot markup easy, but it turns out to be, as someone put it, a big ball of nasty.
For HTML, the <script>
element has a CDATA content model (not to be confused with CDATA sections), which means nothing can be escaped, but </
must be absolutely avoided.
In the special case of JSON, where end tags can only occur within a quoted string, this therefore means the safe way to escape is to use Javascript (rather than HTML) escaping and replace </
with <\/
.
For XHTML (if you care about such things) on the other hand, you just XML-escape everything as usual (&
becomes &
, etc.) and it all works beautifully. A compatible solution would have to use CDATA with guarding comments (<!--/*--><![CDATA[/*><!--*/
etc.) around the entire <script>
body and then escape any occurrences of ]]>
within the JSON; furthermore, I'd still escape </
too just to be safe. Big ball of nasty, indeed, but at least it can be automated.
Upvotes: 3
Views: 2806
Reputation: 23859
OK, answering my own question here, after much research and no real help.
Based my "update" above, the most straightforward way targeting HTML is just:
<script>
var x = ${fn:replace(myJson, "\</", "\<\\/")};
</script>
Ugly but simple.
This will not yield valid XML or XHTML, unfortunately. If you really need that, the original c:out
will work fine, though it will not yield valid HTML. And if you really need a single solution to work on both, you probably need a custom taglib (or TAGX) that will either switch from the content type or do all of the following:
</
with <\/
]]>
with ]]\>
Upvotes: 1
Reputation: 94653
set escapeXml=false
<c:out value="${myJson}" escapeXml="false"/>
Upvotes: 4