Q:

Printing '' from a xsl file in JTextArea

I'm always trying to print my xsl message in a JTextArea. With the Code of my last question I can print the xsl output in my TextArea, but not the message that is written in the xslt file.
Java Code:
public static void xslTransform(File xmlFile)throws IOException, TransformerException{
File xslFile = ...;
StreamSource xmlSource = new StreamSource(xmlFile);
StreamSource xslSource = new StreamSource(xslFile);
StreamResult result = new StreamResult (new StringWriter()); //maybe here is the problem?
TransformerFactory transformerFact = TransformerFactory.newInstance();
transformerFact.setAttribute(FeatureKeys.MESSAGE_EMITTER_CLASS, "MyMessageEmitter");
Transformer transformer = transformerFact.newTransformer(xslSource);
transformer.transform(xmlSource,result);
}

public class MyMessageEmitter extends net.sf.saxon.serialize.MessageEmitter{
String message;
private StringWriter stwriter = new StringWriter();
public void MyMessageEmitter() throws XPathException{
setWriter(stwriter);
}
@Override
public void close() throws XPathException{
super.close();
message=stwriter.toString();
myJTextArea.setText(message);
stwriter = new StringWriter();
}
}

The XSLT File:
<xsl:template match="/">
<xsl:for-each select="//@id">
<xsl:message>
<xsl:value-of select="name(parent::*)"/> <xsl:text></xsl:text><xsl:value-of select="."/>
</xslmessage>
</xsl:for-each>
</xsl:tempate>

with this Code message from java is empty because this xslt do not paste any output (for example a new xml-document. I checked this with another xslt that prints a new xml. 
So how can i get the message that prints the xslt?
Thanks for all help
KaFu

A:

If MyMessageEmitter has a reference to myJTextArea then presumably it is an inner class.
This means that its full name is not "MyMessageEmitter" but something more complex. With your code as written I get this:
Error 
  Failed to load MyMessageEmitter
net.sf.saxon.trans.XPathException: Failed to load MyMessageEmitter
    at net.sf.saxon.trans.DynamicLoader.getClass(DynamicLoader.java:123)
    ...
Caused by: java.lang.ClassNotFoundException: MyMessageEmitter
If I change the class name in factory.setAttribute to the correct name I get this:
Error 
  Failed to instantiate class jaxptest.TransformMessageTest$MyMessageEmitter
net.sf.saxon.trans.XPathException: Failed to instantiate class jaxptest.TransformMessageTest$MyMessageEmitter
    at net.sf.saxon.trans.DynamicLoader.getInstance(DynamicLoader.java:185)
    ...
Caused by: java.lang.InstantiationException: jaxptest.TransformMessageTest$MyMessageEmitter
This is because a non-static inner class cannot be instantiated except from its containing class.
Your next error is very subtle and took me a long time to diagnose. You've written
public void MyMessageEmitter() throws XPathException{ 
  setWriter(stwriter);
}

but that makes MyMessageEmitter() an ordinary method, whereas you intended it to be a constructor. So it should have been written:
public MyMessageEmitter() throws XPathException{ 
  setWriter(stwriter);
}

It works if I make the inner class static; but the problem now is that the static class can't simply refer to the jTextArea by name. 
The next problem is also quite subtle, and this time it's Saxon that's at least half to blame: the close() method on the MessageEmitter is called twice. Unfortunately when this happens the first call creates a new empty StringWriter, and the second call writes the content of this empty StringWriter to your text area. So I changed it to create a new StringWriter in the open() method rather than in the close() method.
This now leaves the question of how to communicate between your MessageEmitter and your JTextArea. This isn't trivial. I did it by having the MessageEmitter write to a static variable, and having the callling application pick up this static variable. But obviously, use of global static variables isn't really acceptable in production applications. The problem is that Saxon creates an instance of your MessageEmitter class, but doesn't provide any direct way of communicating with it. The only solution I could find to this involved using some lower-level Saxon interfaces, like this:
public void testMessageCapture() {
        try {
            String stylesheet =
                "<?xml version='1.0'?>" +
                    "<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'" +
                    "    version='2.0'>" +
                    "  <xsl:template match='/'>" +
                    "<first/>" +
                    "<xsl:message>Hi!</xsl:message>" +
                    "  </xsl:template>" +
                    "</xsl:stylesheet>";

            TransformerFactory transFactory = new TransformerFactoryImpl();
            //transFactory.setAttribute(FeatureKeys.MESSAGE_EMITTER_CLASS, "jaxptest.TransformMessageTest$MyMessageEmitter");

            Templates templates = transFactory.newTemplates(
                new SAXSource(new InputSource(new StringReader(stylesheet))));

            StreamResult result = new StreamResult(new StringWriter());
            final StringWriter messageOut = new StringWriter();
            Transformer transformer = templates.newTransformer();
            ((net.sf.saxon.jaxp.TransformerImpl)transformer).getUnderlyingController().setMessageEmitter(
                new MessageEmitter() {
                    @Override
                    public void open() throws XPathException {
                        setWriter(messageOut);
                        super.open();
                    }
                }
            );
            transformer.transform(new StreamSource(new StringReader("<in/>")), result);
            assertEquals("Hi!", messageOut.toString().trim());
        } catch (TransformerException e) {
            e.printStackTrace();
            fail();
        }
    }

(where of course you could substitute the writing to the string writer with a direct write to your JTextArea).
This code is actually specific to Saxon 9.6; in earlier releases you would cast the JAXP Transformer to a Controller directly.
This rather illustrates the limitations of relying on JAXP interfaces. It would be a lot easier to do this using Saxon's native s9api interface.

A:

I got it... Here is the solution:
Processor proc = new Processor(false);
XsltCompiler comp = new proc.newXsltCompiler();
StreamSource styleSource = new StreamSource(xsltFile);
StreamSource xmlSource = new StreamSource(xmlFile);
String msg="";
XsltExecutable templates = comp.compile(styleSource);
XsltTransformer transformer = templates.load();
transformer.setSource(xmlSource);
transformer.setMessageListener(new MessageListener(){
@Override
public void message (XdmNode content, boolean terminate, SourceLocator locator){
try{
if (content.getTypedValue!= null){
msg += content.getTypedValue().toString() + "\n";
}}
catch (SaxonApiException ex){
Logger.getLogger(...);
}
}
});
Writer write = new StringWriter();
Serializer out = proc.newSerializer(write);
transformer.setDestination(out);
transformer.transform();
textAreaOut.setText(msg);

thanks for your help!

