You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by Michael Smith <ms...@xn.com.au> on 2001/03/21 07:11:27 UTC

passing arbitrary objects to extension functions

Hi all,

I'm currently trying to do the following:
  I have some data which is related to my document , but isn't actually
part of the DOM tree or the xml file.
  I want to use this data from an extension function (written in java).

After some problems doing this, I went for a small test case with some
test objects (which are meaningless in themselves, but do implement the
relevent things so that I can see whether things are working)

So, I have code that does this:
  
   transformer.setParameter("DocInfo", new TestObject());
   transformer.transform(...);

Then, my xsl file has this:

<xsl:value-of select="java:extensionGetInfo.invoke($DocInfo)"/>

I have the extensionGetInfo class, with method "public static String
invoke(TestObject obj)"

However, when it gets to this point in the xsl, an exception is thrown.
The first exception is this:

java.lang.NoSuchMethodException: For extension function, could not find
method static extensionGetInfo.invoke([ExpressionContext,] #STRING).

So, it's trying to call it with a String instead of with my TestObject -
what's going wrong here, and why is it doing this? (Note that if I
provide another invoke method taking a string, it DOES work (or at least
gets called) - but that doesn't help me since I don't want to pass a
string).

I found something in the mailing list archives from Gary Peskin:
> that parameter by including
>    <xsl:param name="mystuff" select="Passed in by processor"/>
> as a top-level element. Then, you can pass $mystuff to your various
> extension functions and retrieve things from there.

So, this implies that I'm doing mostly the right thing but that I need
this <xsl:param/> as well. This doesn't work (making the obvious
substitutions). Also, why is it (supposedly) needed?

I'm using xalan 2.0.1 now (though I was originally using 2.0.D07, since
that's what I had around, upgrading didn't make any difference here). 

Any help would be much appreciated...


Michael Smith

Re: passing arbitrary objects to extension functions

Posted by Michael Smith <ms...@xn.com.au>.
> As far as the mailing list part:
> 
> http://marc.theaimsgroup.com/?l=xalan-dev&r=1&w=2

Ah. Very useful - thanks.
Perhaps you (or someone else) could update the web pages, which point to
somewhere else (where the mailing list archives used to be. They no
longer are there, but that points somewhere else, which does have
archives, that are now out of date). 

Michael

Re: passing arbitrary objects to extension functions

Posted by Gary L Peskin <ga...@firstech.com>.
Michael Smith wrote:
> Most of my trouble was that the requirement for the <xsl:param> call
> isn't clearly documented anywhere that I could find - that'd be a nice
> thing to add somewhere, since there isn't a mailing list archive that I
> can find which is usable (there is one, but it doesn't seem to be up to
> date, and it's unsearchable), and things like this should really be
> documented more directly than that anyway.

As far as the mailing list part:

http://marc.theaimsgroup.com/?l=xalan-dev&r=1&w=2

Gary

Re: passing arbitrary objects to extension functions

Posted by Michael Smith <ms...@xn.com.au>.
Gary L Peskin wrote:
> 
> Gary L Peskin wrote:
> > Michael, I'll work up a little example to see if I can duplicate your
> > problem and I'll let you know.
> 
> Michael --
> 
> I've worked up my example and it seems to work just fine so I'm really
> confused about why yours is not working.  There was a change in
> parameter handling so please be sure that you are, in fact, on Xalan
> 2.0.1 and that you don't have the old jar lying around somewhere.

Thanks for the assistance Gary.
It turns out to have been a stupid mistake on my part - unrelated to the
actual parameter passing. 
Most of my trouble was that the requirement for the <xsl:param> call
isn't clearly documented anywhere that I could find - that'd be a nice
thing to add somewhere, since there isn't a mailing list archive that I
can find which is usable (there is one, but it doesn't seem to be up to
date, and it's unsearchable), and things like this should really be
documented more directly than that anyway.

Once I'd figured that out (well, found that from the list archives),
things would have worked fine had I not done something rather stupid.
Anyway, it's all working well now, so thankyou.

Re: passing arbitrary objects to extension functions

Posted by Gary L Peskin <ga...@firstech.com>.
Gary L Peskin wrote:
> Michael, I'll work up a little example to see if I can duplicate your
> problem and I'll let you know.

Michael --

I've worked up my example and it seems to work just fine so I'm really
confused about why yours is not working.  There was a change in
parameter handling so please be sure that you are, in fact, on Xalan
2.0.1 and that you don't have the old jar lying around somewhere.

Here is my example:

----------------------- XalanTest1.java ------------------------------
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import org.apache.xalan.transformer.TransformerImpl;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import java.io.FileOutputStream;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.xml.utils.QName;
import java.io.IOException;
import java.util.Hashtable;

public class XalanTest1 {

  public static void main(String[] argv) 
    throws TransformerConfigurationException, TransformerException,
IOException
  {

    TransformerFactory tFactory = TransformerFactory.newInstance();

    Transformer transformer = tFactory.newTransformer(new
StreamSource("foo.xsl"));

    transformer.setParameter("myParam", new Hashtable());

    transformer.transform(new StreamSource("foo.xml"), new
StreamResult(System.out));

  }
}

----------------------------------- foo.xml ----------------------
<?xml version="1.0"?>
<doc>Hello</doc>


----------------------------------- foo.xsl ----------------------
<?xml version="1.0"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
	xmlns:java="http://xml.apache.org/xslt/java">

<xsl:param name="myParam" select="'default value'"/>

<xsl:template match="doc">
   <xsl:value-of select="java:extensionGetInfo.invoke($myParam)"/>
</xsl:template>

</xsl:stylesheet>

-------------------------------- extensionGetInfo.java ------------
import java.util.Hashtable;

public class extensionGetInfo {
  public static String invoke1(Hashtable myHash) {
    System.err.println("Reached the invoke method");
    System.err.println("myHash = " + myHash);
    System.err.println("class is " + myHash.getClass().getName());
    return "Result String";
  }


Perhaps you could send along a complete working example so that we can
try to reproduce it.

Also, I'm assuming that TestObject doesn't extend any Xalan classes that
might cause setParameters() to treat it like some kind of special case
internal object.

Gary

Re: passing arbitrary objects to extension functions

Posted by Gary L Peskin <ga...@firstech.com>.
Michael Smith wrote:
> So, it's trying to call it with a String instead of with my TestObject -
> what's going wrong here, and why is it doing this? (Note that if I
> provide another invoke method taking a string, it DOES work (or at least
> gets called) - but that doesn't help me since I don't want to pass a
> string).

Michael --

This is really confusing to me.  It might be a bug in Xalan.  Can you
please do the following?  After your transformer.setParameter call,
insert:

  Object myParam = transformer.getParameter("DocInfo");
  System.err.println("myParam = " + myParam);
  System.err.println("class is " + myParam.getClass().getName());

Then, at least we should see what the parameter looks like after it's
been pushed and popped from the stack.

> 
> I found something in the mailing list archives from Gary Peskin:
> > that parameter by including
> >    <xsl:param name="mystuff" select="Passed in by processor"/>
> > as a top-level element. Then, you can pass $mystuff to your various
> > extension functions and retrieve things from there.
> 
> So, this implies that I'm doing mostly the right thing but that I need
> this <xsl:param/> as well. This doesn't work (making the obvious
> substitutions). Also, why is it (supposedly) needed?

Are the symptoms (ie the error message) the same or different?  The
reason that you need this is that, for template parameters, the XSLT 1.0
Recommendation states:  "It is not an error to pass a parameter x to a
template that does not have an xsl:param element for x; the parameter is
simply ignored."

Although I cannot find a part in the spec where this is explicitly
talked about one way or the other for top-level variables, this
consistency is something that we enforce.  So you need the "xsl:param"
at the top-level to receive the parameter passed in the setParameter()
call.

Michael, I'll work up a little example to see if I can duplicate your
problem and I'll let you know.

Gary