Showing posts with label xalan. Show all posts
Showing posts with label xalan. Show all posts

Friday, February 13, 2009

XSLT output is missing the doctype

Keywords:
xslt identity transform missing doctype Document Type java DOM

Problem:
Running an XSLT 'identity transform' I would expect the XML data out to be identical to the data in ... it almost is, but it's missing the doctype declaration.
Can you tell the XSTL to keep the doctype in?

Solution:
Apparently not ... I can't find a good reference for this, but it seems that the spec (or at least xalan) is a bit vague on how this should be handled. Proposed work-arounds seem to be hard-coding the doctype in the <xsl:output> element (if outputting to xml) or hiding the doctype in the XSLT via <xsl:text disable-output-escaping="yes">.

If you want to make the inclusion of the doctype generic there's no pure XSTL solution - you can add it after the transform, but even that is not straightforward using pure java DOM elements ... here is the code:
    // assuming there's an inputDocument
    TransformerFactory factory = TransformerFactory.newInstance();
    StreamSource stylesheet = new StreamSource(stylesheetData);

    DOMSource source = new DOMSource(inputDocument);
    DOMResult result = new DOMResult();

    Transformer transformer = factory.newTransformer(stylesheet);
    transformer.transform(source, result);

    Document outputDocument = (Document)result.getNode();
    if (inputDocument.getDoctype() != null) {
        DocumentType inputDocType = inputDocument.getDoctype();
        
        // you can't importNode for DocumentType nodes but you can create 
        // them via DOMImplementation from there insert is easy
        DOMImplementation domImpl = outputDocument.getImplementation();
        DocumentType outputDocType = domImpl.createDocumentType(
              inputDocType.getName()
            , inputDocType.getPublicId()
            , inputDocType.getSystemId());
        outputDocument.insertBefore(outputDocType, outputDocument.getDocumentElement());
    } 


Notes:
It's interesting that this code is not allowed:
    DocumentType outputDocType = (DocumentType) outputDocument.importNode(inputDocType, true /*deep*/);

It seems DocumentType is a special element that can't be imported.

It's also interesting there's no method straight on the document:
    DocumentType outputDocType = outputDocument.createDocumentType(...);

The only way to get this kind of element is to obtain the special DOMImplementation object via the Document.getImplementation() method.

Quirks with the implementation? I've looked at this issue too long already to bother to find out why :)

Thursday, January 04, 2007

JSTL TransformerFactoryImpl ClassCastException on WAS 6.0.2.11

Keywords:
JSTL TransformerFactoryImpl ClassCastException WAS 6.0.2.11 xalan JAXP core xerces

Problem:
A web application that has the following properties:
  1. includes the JAXP api jar files (in WEB-INF\lib)
  2. deploys with the class loader properties of "Parent Last"
  3. uses JSTL core
Will encounter the following stack trace from WAS when ever a JSP is loaded that contains JSTL (core reference):

JSP Processing Error
HTTP Error Code: 500
java.lang.ClassCastException: org.apache.xalan.processor.TransformerFactoryImpl
at javax.xml.transform.TransformerFactory.newInstance(Unknown Source)
at com.ibm.ws.jsp.translator.visitor.validator.PageDataImpl._getInputStream(PageDataImpl.java:125)
at com.ibm.ws.jsp.translator.visitor.validator.PageDataImpl.getInputStream(PageDataImpl.java:117)
at org.apache.taglibs.standard.tlv.JstlBaseTLV.validate(JstlBaseTLV.java:156)
at org.apache.taglibs.standard.tlv.JstlCoreTLV.validate(JstlCoreTLV.java:96)
at com.ibm.ws.jsp.translator.visitor.validator.ValidateVisitor.validateTagLib(ValidateVisitor.java:939)
at com.ibm.ws.jsp.translator.visitor.validator.ValidateVisitor.visitJspRootStart(ValidateVisitor.java:453)
at com.ibm.ws.jsp.translator.visitor.JspVisitor.processJspElement(JspVisitor.java:124)
at com.ibm.ws.jsp.translator.visitor.JspVisitor.visit(JspVisitor.java:110)
at com.ibm.ws.jsp.translator.JspTranslator.processVisitors(JspTranslator.java:121)
at com.ibm.ws.jsp.translator.utils.JspTranslatorUtil.translateJsp(JspTranslatorUtil.java:168)
at com.ibm.ws.jsp.translator.utils.JspTranslatorUtil.translateJspAndCompile(JspTranslatorUtil.java:81)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.translateJsp(JSPExtensionServletWrapper.java:360)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper._checkForTranslation(JSPExtensionServletWrapper.java:329)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.checkForTranslation(JSPExtensionServletWrapper.java:237)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.handleRequest(JSPExtensionServletWrapper.java:144)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3003)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:221)
at com.ibm.ws.webcontainer.VirtualHost.handleRequest(VirtualHost.java:210)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:1958)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:88)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:472)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:411)
at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:101)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.requestComplete(WorkQueueManager.java:566)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.attemptIO(WorkQueueManager.java:619)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.workerRun(WorkQueueManager.java:952)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager$Worker.run(WorkQueueManager.java:1039)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1470)


Solution:
In short, make sure the JSPs, JSTL refs and the web app are 2.4 compliant (see past post: What Spec?) and install the latest fix pack for WAS from IBM.

In detail, the following Problem ID is a different issue but underlying problem is the same - incorrect handling of loading XML & XSLT API classes for Parent Last apps - IBM - PK26233. The comment says it is resolved in the fix pack 6.0.2.15 for WebSphere Application Server, but I used 6.0.2.17 seeing it was newer - V6.0.2 Fix Pack 17.

Friday, December 08, 2006

WebSphere DTMConfigurationException: No default implementation found

Keywords:
WebSphere DTMConfigurationException DTMManager xalan 6.0.2.11

Problem:After upgrading the WebSphere Application Server JDK with the .11 Fix pack (making it 6.0.2.11) there is the following error when my web app. tries to get a transformer:
org.apache.xml.dtm.DTMConfigurationException: No default implementation found
    at org.apache.xml.dtm.DTMManager.newInstance(DTMManager.java:177)
    at org.apache.xpath.XPathContext.(XPathContext.java:125)
    at org.apache.xalan.transformer.TransformerImpl.(TransformerImpl.java:398)
    at org.apache.xalan.templates.StylesheetRoot.newTransformer(StylesheetRoot.java:197)

Solution:
The problem seems to be at least associated with the fix pack creating a new file "xalan.properties" in APPSERVER_HOME\java\jre\lib. It could also be upgrading the xalan libraries as well (in xml.jar).

Edit this file - you'll notice this isn't defining any properties, everything is commented out - and add the property:
org.apache.xml.dtm.DTMManager=org.apache.xml.dtm.ref.DTMManagerDefault


Notes:
Alternatively, remove or rename this file and the problem should also go away.

Alternatively again, add the JVM system property "org.apache.xml.dtm.DTMManager". You can do this on WebSphere by going to:
Application servers > server1 > Process Definition > Java Virtual Machine
... and adding to the Generic JVM arguments:
-Dorg.apache.xml.dtm.DTMManager=org.apache.xml.dtm.ref.DTMManagerDefault

Restart the server and the problem should also go away - use this approach for where you don't have access to the APPSERVER_HOME\java\jre\lib files and can only configure your application's JVM.

Wednesday, July 05, 2006

xalan parameter must be a "valid Java Object"

Keywords:
xalan IllegalArgumentException "The value of param" "must be a valid Java Object"

Problem:
On an application server (JBoss) where you can't control the version of xalan that is getting loaded with your web application, you get the following error in the preparation phase of a XML transform:
java.lang.IllegalArgumentException: The value of param [param-name] must be a valid Java Object
at org.apache.xalan.transformer.TransformerImpl.setParameter(TransformerImpl.java:1587)

Solution:
The issue here is that the object being set in the javax.xml.transform.Transformer.setParameter(String name, Object) is a null. In xalan 2.5.0 this doesn't seem to be an issue, but in xalan 2.7.0 it is!

Stop the null being put set as a parameter and the issue is solved.


Notes:
The last few posts have been around this issue of the web application not being able to control its classpath in JBoss. I've tried the ClassLoadingConfiguration advice in the JBoss Wiki with no success. The endorsed directory contains the different xalan library (as visible in the "sun.boot.class.path" system property) and despite specifying some sort of isolation, the endorsed directory still applies. As the issue was ultimately with a newer version of xalan and it's probably be bad to be putting nulls in anyway I haven't tried to force this class/library loading issue.