Debugging XML parser issues


There are often some issues that can waste several hours of your precious time: XML parser incompatibilities depending on your platform and application, i18n problems where several elements of your architecture aren't configured well to serve correct encoded and localized content, class loader hierarchy nightmares, or even Jar Hell when different libraries you depend on require different versions of the same jar. Today, I'm going to concentrate on the first problem: XML parser issues.

I was having a problem of interoperability between my Java web services and a .Net client consumming them. And it appeared that a bug in certain versions of Xalan made the XML payloads generated by .Net not parseable and generated some odd stacktrace on my backend with a pretty obscure message (NAMESPACE_ERR message). It took me quite some time to discover what the problem really was. In short, my old version of Xalan couldn't grok default namespaces inherited from parent nodes.

While debugging this problem, I created a little JSP page, to help me understand clearly which version of Xerces and Xalan I was using. I had no problem under Tomcat 5.0.x and Sun's JDK 1.4.2_06, but the problem appeared with Websphere 5.1 and IBM's JDK 1.4.2. My JSP page will tell you which versions of Xalan and Xerces you're using, from which Jars they are loaded, and it'll also print your system properties.

Just so that I can cut'n paste it some day in the future if I have a problem with XML parsers again, here it is:

<%@ page import="java.util.Properties"%>
<%@ page import="java.util.Enumeration"%>
<%@ page import="javax.xml.transform.TransformerFactory"%>
<%@ page import="javax.xml.parsers.DocumentBuilderFactory"%>
<%@ page import="javax.xml.parsers.ParserConfigurationException"%>
<%@ page import="javax.xml.parsers.SAXParserFactory"%>
<%@ page import="javax.xml.parsers.FactoryConfigurationError"%>
<%@ page import="javax.xml.transform.TransformerFactoryConfigurationError"%>
<%@ page import="java.net.URL"%>
<%@ page import="org.apache.xalan.xslt.EnvironmentCheck"%>
<%@ page import="java.io.PrintWriter"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
    private String getJarForClass(Class clazz) {
        String clsResPath = clazz.getName().replaceAll("\\.","/")+".class";

        ClassLoader clsLoader = clazz.getClassLoader();
        if (clsLoader == null) clsLoader = ClassLoader.getSystemClassLoader();

        URL clsResURL = clsLoader.getResource(clsResPath);
        return clsResURL != null ? clsResURL.toExternalForm() : "unknown";
    }
%>
<%
    String transformerClassName = "";
    try {
        Class clazz = TransformerFactory.newInstance().getClass();
        transformerClassName = clazz.getName() + "
(" + getJarForClass(clazz) + ")"; } catch (TransformerFactoryConfigurationError e) { transformerClassName = e.getMessage(); } String documentBuilderClassName = ""; try { Class clazz = DocumentBuilderFactory.newInstance().newDocumentBuilder().getClass(); documentBuilderClassName = clazz.getName() + "
(" + getJarForClass(clazz) + ")"; } catch (ParserConfigurationException e) { documentBuilderClassName = e.getMessage(); } String saxParserFactoryClassName = ""; try { Class clazz = SAXParserFactory.newInstance().getClass(); saxParserFactoryClassName = clazz.getName() + "
(" + getJarForClass(clazz) + ")"; } catch (FactoryConfigurationError e) { saxParserFactoryClassName = e.getMessage(); } %> XML parsers debugging

Debug parameters

<% Properties p = System.getProperties(); Enumeration keys = p.keys(); while( keys.hasMoreElements() ) { String key = (String) keys.nextElement(); %> <% } %>
Xalan version <%= org.apache.xalan.Version.getVersion() %>
TransformerFactory <%= transformerClassName %>
DocumentBuilder <%= documentBuilderClassName %>
SAXParserFactory <%= saxParserFactoryClassName %>
Xalan debug environement check:
<% (new EnvironmentCheck()).checkEnvironment(new PrintWriter(out)); %>
<%= key %> <%= System.getProperty(key) %>

 

 
© 2012 Guillaume Laforge | The views and opinions expressed here are mine and don't reflect the ones from my employer.