50

As an extension of this question, I'm trying to insert Javascript to a <h:commandButton />'s onclick property as action is already rendering an ajax table.

What I want to do: Get the selected items in a list box and turn them into parameters to be used in a JSF FileServlet. i.e. para2=value1&param=value2&param=value3

Here's what I have:

<script type ="text/javascript">
function myScript() {
    var box = document.getElementbyId('myForm:box');
    var length = box.options.length;
    var paramstring = "";
    for (var i = 0; i < length; i++) {
        if (i != (length - 1) {
            if (box.options[i].selected) {
                paramstring = paramstring + "param=" + box.options[i].value + "&amp;";
            }
        } else {
            paramstring = paramstring + "param=" + box.options[i].value;
        }
    }
    if (document.getElementById('myForm:checkbox').checked) {
        window.location='fileServlet? + paramstring;
    }
}
</script>  

What I get when page is loaded: javax.servlet.ServletException: Error Parsing /page.xhtml: Error Traced[line:15] The content of elements must consist of well-formed character data or markup.

What doesn't trigger exception:

<script type ="text/javascript">
function myScript() {
    var box = document.getElementbyId('myForm:box');
    var length = box.options.length;
    var paramstring = "";

    if (document.getElementById('myForm:checkbox').checked) {
        window.location='fileServlet? + paramstring;
    }
}
</script> 

As soon as I add in for (var i = 0; i < length; i++) or even for (var i = 0; i < 10; i++) the page wouldn't load. Why does it not like the for loop?

Community
  • 1
  • 1
luciaengel
  • 667
  • 1
  • 8
  • 10

5 Answers5

109

Facelets is a XML based view technology which uses XHTML+XML to generate HTML output. XML has five special characters which has special treatment by the XML parser:

  • < the start of a tag.
  • > the end of a tag.
  • " the start and end of an attribute value.
  • ' the alternative start and end of an attribute value.
  • & the start of an entity (which ends with ;).

In case of <, the XML parser is implicitly looking for the tag name and the end tag >. However, in your particular case, you were using < as a JavaScript operator, not as an XML entity. This totally explains the XML parsing error you got:

The content of elements must consist of well-formed character data or markup.

In essence, you're writing JavaScript code in the wrong place, a XML document instead of a JS file, so you should be escaping all XML special characters accordingly. The < must be escaped as &lt;.

So, essentially, the

for (var i = 0; i < length; i++) {

must become

for (var i = 0; i &lt; length; i++) {

to make it XML-valid.

However, this makes the JavaScript code harder to read and maintain. As stated in Mozilla Developer Network's excellent document Writing JavaScript for XHTML, you should be placing the JavaScript code in a character data (CDATA) block. Thus, in JSF terms, that would be:

<h:outputScript>
    <![CDATA[
        // ...
    ]]>
</h:outputScript>

The XML parser will interpret the block's contents as "plain vanilla" character data and not as XML and hence interpret the XML special characters "as-is".

But, much better is to just put the JS code in its own JS file which you include by <script src>, or in JSF terms, the <h:outputScript>.

<h:outputScript name="functions.js" target="head" />

This way you don't need to worry about XML-special characters in your JS code. Additional advantage is that this gives the browser the opportunity to cache the JS file so that average response size is smaller.

See also:

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • The javascript doesn't run when I use the `<![CDATA[` block or using an external js file. I shortened the code for `myScript()` to `window.location='fileServlet?param=1';`, and this only runs if I put it inline with `onclick` or in `` – luciaengel Dec 02 '10 at 19:37
  • How did you invoke it? By `onclick="myScript()"` I suppose? – BalusC Dec 02 '10 at 19:39
  • 1
    While wrapping in `<![CDATA[` did you ensure that you followed the instructions in the link as in my answer? There has got to be a `]]>` at end. When using an external script, did you ensure that the `.js` file didn't contain the ` – BalusC Dec 02 '10 at 19:41
  • yes, I used a `<![CDATA[` and `]]>` block and had a `global.js` with only `function myScript() {}` – luciaengel Dec 02 '10 at 19:43
  • I spotted some minor errors in your JS function (among others, you omitted a `'`, but that should have resulted in a JS error, did you see it in JS console?) and the logic could be more simplified. I updated the answer with an example. – BalusC Dec 02 '10 at 19:48
  • Dang it, I was typing in the same answer. Including your javascript in a separate file will definitely solve this issue, and is generally a best practice. – Naganalf Dec 02 '10 at 19:53
  • @Naganalf: You started typing 44 minutes ago? :) – BalusC Dec 02 '10 at 19:56
  • Started yes, then something came up here to distract me. :P – Naganalf Dec 02 '10 at 19:56
  • Thanks for the updated code. But again, running it in `global.js` like the example, even if I shorten it to `window.location='fileServlet?param=1';` it doesn't seem to run. – luciaengel Dec 02 '10 at 20:00
  • @Naganalf: Haha ok. Sorry about that :P Next time better. – BalusC Dec 02 '10 at 20:00
  • It doesn't get invoked at all? Do you see any JS errors in the JS console? Is the `global.js` reachable anyway? (i.e. its URL is correct and so on). Web developer tools like [Firebug](http://getfirebug.com/) and [Web Developer Toolbar](https://addons.mozilla.org/en-US/firefox/addon/60/) for Firefox may give lot of new insights. – BalusC Dec 02 '10 at 20:02
  • Ok, after restarting server and refreshing page, clearing browser cache a couple times I got the `global.js` running. But only this part `if(checked) window.location='fileServlet?param=1';` As soon as I put in the line `var box = document.getElementbyId('myForm:box');` it doesn't download the file, even when the param is currently hard-coded. I will look into using Firebug. – luciaengel Dec 02 '10 at 20:24
  • Only by just putting this line? Interesting, this would suggest that calling `document` threw an exception. Anyway, is the element ID correct as per the generated HTML? – BalusC Dec 02 '10 at 20:27
  • yup, my listbox id is `box` and my form id is `myForm` It was able to get the checkbox element. – luciaengel Dec 02 '10 at 20:28
  • Press `Ctrl+Shift+J` to get the standard JS error console in Firefox. It might contain useful debug information. – BalusC Dec 02 '10 at 20:29
  • ah I was using `getElementbyId` instead of `getElementById` Now it triggers the download. – luciaengel Dec 02 '10 at 20:39
  • Thanks for tip on using external js and error console and fixing the logic too. – luciaengel Dec 02 '10 at 20:40
  • Ahh, my own typo. Sorry about that. Just typed straight from head :) But is it now working? – BalusC Dec 02 '10 at 20:44
  • It's only passing one param so far instead of the whole chain. I'm using `getParameterValues`. I'll get back to you. – luciaengel Dec 03 '10 at 13:36
  • Hmm, I shouldn't be doing `length - 1`, that's the options available in list box not the total of selected. I'll get back to you. – luciaengel Dec 03 '10 at 13:42
  • This should actually not harm. Put an `alert(paramstring)` or with Firebug, `console.log(paramstring)` before `window.location` to see if it's correct. – BalusC Dec 03 '10 at 14:03
  • but the paramstring before was putting `&` at the end because it wasn't at `length - 1` even when I was already at the end of all the selections. I updated the code now, please see updated question. thanks. – luciaengel Dec 03 '10 at 14:10
  • I updated the answer, but I see that you used `&` in JS. This is unnecessary. The `&` is only necessary when writing in a XML file. The XML parser will then turn it into a `&`. – BalusC Dec 03 '10 at 14:10
  • Ignore the code that I updated, yours is outputting the correct `paramstring` and I'm getting the correct String array with `getParameterValues`. Thanks. – luciaengel Dec 03 '10 at 14:15
  • I am using left shift operator in my code ( << ) for this it is giving me that Error parsing XHTML: The content of elements must consist of well-formed character data or markup – Sagar May 20 '15 at 16:23
  • Wow, how in a earth, you have found out this. – funky-nd Nov 30 '17 at 06:52
22

I ran across this post today as I was running into the same issue and had the same problem of the javascript not running with the CDATA tags listed above. I corrected the CDATA tags to look like:

<script type="text/javascript">
//<![CDATA[ 

your javascript code here

//]]>
</script>

Then everything worked perfectly!

MikeR
  • 633
  • 8
  • 21
  • This means that you're serving HTML as `application/xhtml+xml` (see also the CDATA link in my answer https://developer.mozilla.org/en/Writing_JavaScript_for_XHTML). Serving HTML as such is considered harmful (especially in MSIE browser). – BalusC Oct 19 '11 at 20:10
6

Sometimes you will need this :

 /*<![CDATA[*/
 /*]]>*/

and not only this :

 <![CDATA[
 ]]>
Jad B.
  • 1,403
  • 15
  • 14
1

I had a git conflict left in my workspace.xml i.e.

<<<<———————HEAD

which caused the unknown tag error. It is a bit annoying that it doesn’t name the file.

GarethReid
  • 406
  • 4
  • 12
-2

I solved this converting the JSP from XHTML to HTML, doing this in the begining:

<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
...
PedroPK
  • 519
  • 6
  • 8