I can’t make GWT it generate valid XHTML. On our project we use table layout therefore there are many tables on the pages and they have <colgroup> tags along with <col> tags inside. The <col> tags are not closed regardless which doctype is put in the main HTML template. Both XHTML Transitional and XHTML String have been tried. The result is the same.
<table class="header-grid" cellpadding="0" cellspacing="0">
<colgroup>
<col class="header-left">
<col class="header-center">
<col class="header-right">
</colgroup>
<tbody>
...
</tbody>
</table>
<input> elements are not closed either. My guess that there could be other not properly closed elements, but they are not used in the application or I haven’t found them.
FYI. GWT manipulates DOM and doesn’t do any insertions to the inner HTML as text. It uses the JavaScript’s appendChild(...) method along with doc.createElement(...).
The issue is reproduced in Chrome, Firefox and IE both in the Web and Dev modes. It occurs on the pages where UIBinder is not used.
GWT version: 2.4.0.
Main HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="svg.render.forceflash" content="false"/>
<meta name="gwt:property" content="locale=en"/>
<meta http-equiv="X-UA-Compatible" content="IE=8, IE9"/>
<title>NPQ Facility Management</title>
<script src="https://maps-api-ssl.google.com/maps/api/js?v=3&sensor=false" type="text/javascript"></script>
<script type="text/javascript" language="javascript" src="FMInsight.nocache.js"></script>
<script type="text/javascript" language="javascript" src="gr/abiss/js/sarissa/sarissa.js"></script>
<script type="text/javascript" src="js/svg-web/svg.js" data-path="js/svg-web" data-debug="false"></script>
<script type="text/javascript" src="js/svgviewer.js"></script>
<link media="all" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"
type="text/javascript" charset="utf-8"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js"
type="text/javascript" charset="utf-8"></script>
</head>
<body>
<iframe id="__printingFrame" style="width:0; height:0;border: 0"></iframe>
<iframe id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>
</body>
</html>
GWT XML file of the main module:
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to="FMInsight">
<!-- Inheriting the core Web Toolkit stuff. -->
<inherits name="com.google.gwt.user.User"/>
<inherits name="com.google.gwt.inject.Inject"/>
<inherits name="com.npq.fm.core.common.Commons"/>
<inherits name="com.npq.fm.svg.viewer.SvgViewer"/>
<!-- Inheriting the default GWT style sheet. You can change -->
<!-- the theme of your GWT application by unommenting -->
<!-- any one of the following lines. -->
<inherits name="com.google.gwt.user.theme.standard.Standard"/>
<inherits name="com.google.gwt.user.theme.chrome.Chrome"/>
<!-- <inherits name="com.google.gwt.user.theme.dark.Dark"/> -->
<!-- Other module inherits. -->
<inherits name="com.google.gwt.xml.XML"/>
<inherits name="com.google.gwt.i18n.I18N"/>
<inherits name="com.google.gwt.http.HTTP"/>
<!-- Other module inherits. -->
<inherits name="com.google.gwt.user.ClippedImage"/>
<inherits name="com.google.gwt.maps.Maps" />
<!-- Compiled languages -->
<!-- In main file we set only EN language and only in compilation files,
that inherits from this file define what languages are allowed by
re-defining locale like in line below:
<extend-property name="locale" values="en,de,fr,nl,uk"/>
-->
<extend-property name="locale" values="en"/>
<set-property name="locale" value="en"/>
<set-property-fallback name="locale" value="en"/>
<!-- This property provider changes from GWT parameter name -->
<!-- for changing application locale from "locale" to -->
<!-- property "sap-language". -->
<property-provider name="locale"><![CDATA[
var defaultLocale = "en";
try {
var locale;
// Looking for the locale as a url argument in SAP way
if (locale == null) {
var args = location.search;
var startLang = args.indexOf("sap-language");
if (startLang < 0) {
startLang = args.indexOf("locale");
}
if (startLang >= 0) {
var language = args.substring(startLang);
var begin = language.indexOf("=") + 1;
var end = language.indexOf("&");
if (end == -1) {
end = language.length;
}
locale = language.substring(begin, end);
var lowerCase = locale.toLowerCase()
locale = lowerCase;
}
}
if (locale == null) {
// Looking for the locale on the web page
locale = __gwt_getMetaProperty("locale");
}
if (locale == null) {
return defaultLocale;
}
while (!__gwt_isKnownPropertyValue("locale", locale)) {
var lastIndex = locale.lastIndexOf("_");
if (lastIndex == -1) {
locale = defaultLocale;
break;
} else {
locale = locale.substring(0,lastIndex);
}
}
return locale;
} catch(e) {
alert("Unexpected exception in locale detection, using default=" + defaultLocale + ", " + e);
return defaultLocale;
}
]]></property-provider>
<!--
Inspired by Apache log4j PatternLayout:
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
-->
<set-configuration-property name="log_pattern" value="%d [%-2p] %F %M: %m%n"/>
<!--<set-configuration-property name="log_pattern" value="%d [%-2p] %m%n"/>-->
<set-property name="log_FirebugLogger" value="ENABLED"/>
<set-property name="log_GWTLogger" value="ENABLED"/>
<set-property name="log_DivLogger" value="ENABLED"/>
<!-- Loggers are disabled by default -->
<set-property name="log_ConsoleLogger" value="DISABLED"/>
<set-property name="log_SystemLogger" value="DISABLED"/>
<set-property name="log_WindowLogger" value="DISABLED"/>
<!-- User Agent -->
<!-- In main file we set only user-agent to "ie8" and
only in compilation files, that inherits from this file we re-define
what user agents should be supported by re-defining locale like
in line below:
<set-property name="user.agent" value="gecko1_8,safari,ie6,ie8,ie9"/>
-->
<set-property name="user.agent" value="gecko1_8,safari"/>
<property-provider name="user.agent"><![CDATA[
var defaultUserAgent = "ie7";
var ua = navigator.userAgent.toLowerCase();
var makeVersion = function(result) {
return (parseInt(result[1]) * 1000) + parseInt(result[2]);
};
if (ua.indexOf("opera") != -1) {
return "opera";
} else if (ua.indexOf("webkit") != -1) {
return "safari";
} else if (ua.indexOf("msie") != -1) {
if (document.documentMode >= 8 && document.documentMode < 9) {
return "ie8";
} else if (document.documentMode >= 9) {
return "ie9";
} else {
return defaultUserAgent;
}
} else if (ua.indexOf("gecko") != -1) {
var result = /rv:([0-9]+)\.([0-9]+)/.exec(ua);
if (result && result.length == 3) {
if (makeVersion(result) >= 1008) {
return "gecko1_8";
}
}
return "gecko1_8";
}
return defaultUserAgent;
]]></property-provider>
<replace-with class="com.npq.fm.core.main.client.commons.browserspecific.impl.BrowserSpecificCommonsGecko">
<when-type-is class="com.npq.fm.core.main.client.commons.browserspecific.BrowserSpecificCommons" />
<any>
<when-property-is name="user.agent" value="gecko"/>
<when-property-is name="user.agent" value="gecko1_8" />
</any>
</replace-with>
<replace-with class="com.npq.fm.core.main.client.commons.browserspecific.impl.BrowserSpecificCommonsIE">
<when-type-is class="com.npq.fm.core.main.client.commons.browserspecific.BrowserSpecificCommons" />
<any>
<when-property-is name="user.agent" value="ie6"/>
<when-property-is name="user.agent" value="ie8" />
<when-property-is name="user.agent" value="ie9" />
</any>
</replace-with>
<replace-with class="com.npq.fm.core.main.client.commons.browserspecific.impl.BrowserSpecificSafari">
<when-type-is class="com.npq.fm.core.main.client.commons.browserspecific.BrowserSpecificCommons" />
<any>
<when-property-is name="user.agent" value="safari"/>
</any>
</replace-with>
<stylesheet src="FMInsight-main.css"/>
<stylesheet src="res_localized/default.css"/>
<!-- Specifying the app entry point class. -->
<entry-point class="com.npq.fm.core.main.client.Main"/>
<inherits name="org.cobogw.gwt.user.Button"/>
</module>
If this is happening client side, then GWT isn’t generating tags at all. It is manipulating a DOM and you are using a tool to serialise it to HTML.
You might be able to persuade browsers to serialise to XHTML if you trigger XML parsing mode by serving the original document with an
application/xhtml+xmlcontent-type.That said, HTML is the native markup language of browsers and it is best to use it to communicate with them. Instead of getting XHTML out, take HTML out and use an HTML parser at the place where you send the markup to.