Keywords: XHTML | Entity Reference | JavaScript | JSF | CDATA | XML Parsing
Abstract: This article provides an in-depth analysis of the 'entity name must immediately follow the &' error encountered when embedding JavaScript code in XHTML pages. By examining XML special character processing mechanisms, it详细介绍es two solutions using CDATA blocks and external JS files, with complete implementation examples and best practice recommendations tailored for JSF frameworks. The content progresses from fundamental principles to practical applications, helping developers thoroughly understand and resolve such issues.
XML Special Characters and Entity Reference Mechanisms
In XML-based view technologies like XHTML+XML used by Facelets, the XML parser treats five special characters specially: < (tag start), > (tag end), " (attribute value delimiter), ' (alternative attribute value delimiter), and & (entity reference start). When the parser encounters the & character, it expects it to be followed immediately by a predefined entity name (such as lt, gt, amp, quot, apos) or a user-defined entity name, ending with a semicolon ;.
Root Cause Analysis
In JavaScript code, && is used as the logical AND operator, but in an XML document, consecutive & characters are misinterpreted by the parser as the start of an entity reference. Since && does not conform to any valid entity reference format, it triggers the error: The entity name must immediately follow the & in the entity reference. This essentially occurs because JavaScript code is incorrectly placed within an XML document environment without proper escaping of XML special characters.
Solution 1: Character Escaping
The most direct solution is to escape all XML special characters. Specifically for the logical AND operator, replace && with &&. The modified code example is as follows:
if (Modernizr.canvas && Modernizr.localstorage &&
Modernizr.audio && (Modernizr.audio.ogg || Modernizr.audio.mp3)) {
window.setTimeout(function () { PACMAN.init(el, "./"); }, 0);
} else {
el.innerHTML = "Sorry, needs a decent browser<br /><small>" +
"(firefox 3.6+, Chrome 4+, Opera 10+ and Safari 4+)</small>";
}
While this method resolves the parsing error, it significantly reduces code readability and maintainability, especially in complex JavaScript logic where escaped characters make the code difficult to understand and debug.
Solution 2: CDATA Blocks
A more elegant solution is to use CDATA (Character Data) blocks. Content within a CDATA block is treated as plain text by the XML parser, which does not parse XML special characters inside it. In JSF, this can be achieved using the <h:outputScript> tag combined with CDATA:
<h:outputScript>
<![CDATA[
var el = document.getElementById("pacman");
if (Modernizr.canvas && Modernizr.localstorage &&
Modernizr.audio && (Modernizr.audio.ogg || Modernizr.audio.mp3)) {
window.setTimeout(function () { PACMAN.init(el, "./"); }, 0);
} else {
el.innerHTML = "Sorry, needs a decent browser<br /><small>" +
"(firefox 3.6+, Opera 10+ and Safari 4+)</small>";
}
]]>
</h:outputScript>
This method preserves the original format of the JavaScript code without requiring character escaping, while ensuring the validity of the XML document.
Best Practice: External JavaScript Files
From an engineering and performance optimization perspective, the most recommended approach is to move JavaScript code to external files and reference them via <script src> or JSF's <h:outputScript>. The specific implementation is as follows:
<h:outputScript name="game.js" target="body" />
Here, the target="body" attribute ensures the script is loaded at the end of the <body> tag, simulating the effect of window.onload or $(document).ready(), eliminating the need for additional page load event handling in the script. Advantages of the external file approach include:
- Avoiding XML special character escaping issues
- Improving code maintainability and readability
- Leveraging browser caching to reduce network requests
- Supporting code modularization and reuse
Implementation Example and Code Analysis
The following is a complete Pacman game integration example, demonstrating how to properly structure code in a JSF page:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<head>
<title>Pacman Game</title>
</head>
<body>
<div id="pacman"></div>
<h:outputScript name="js/modernizr.js" />
<h:outputScript name="js/pacman.js" target="body" />
</body>
</html>
In the external pacman.js file, the original JavaScript syntax can be maintained:
document.addEventListener("DOMContentLoaded", function() {
var el = document.getElementById("pacman");
if (Modernizr.canvas && Modernizr.localstorage &&
Modernizr.audio && (Modernizr.audio.ogg || Modernizr.audio.mp3)) {
PACMAN.init(el, "./");
} else {
el.innerHTML = "Sorry, needs a decent browser<br /><small>" +
"(firefox 3.6+, Chrome 4+, Opera 10+ and Safari 4+)</small>";
}
});
Technical Summary
The key to resolving JavaScript parsing errors in XHTML lies in understanding the conflict between XML parsing mechanisms and JavaScript syntax. Through character escaping, CDATA blocks, or external file references, these issues can be effectively avoided. In practical development, prioritizing the external file approach is recommended, as it maintains code clarity while providing performance optimization benefits. For scripts that must be inline, CDATA blocks offer the best compromise.