Thank you Scott, I've now managed to sort the problem out.

> > v) How do I get Xalan compiled with variable information intact?
> 
> If you do "build clean" and then "build jar" you should get a jar with
> debugging information.

For reasons I don't understand, the variable information is _still_ being
stripped out.  I'm wondering whether ant switches on optimisation.  In any
event, it's driving me crazy, but isn't really xalan-related.  I may end up
getting a commercial Java package.

> > i) What does the error message mean?
> 
> If you pass -edump to the Process program, you'll get more 
> information.  I can't tell anything either from just the error message.

This actually was the hint I needed.  Looking at the full stack trace I got:

Caused by: java.lang.ClassCastException: Iterator
        at
org.apache.xalan.templates.ElemForEach.transformSelectedNodes(ElemForEach.ja
va:411)

Looking up the line, it read:
xctxt.pushContextNodeList((ContextNodeList) sourceNodes);

In other words, anything dealt with in xsl:for-each has to implement
org.apache.xpath.axes.ContextNodeList as well as NodeIterator.  If you write
a wrapper class (I've included one at the bottom) it works.

Incidentally, the original poor error is actually a consequence of Sun's
poor diagnostics on ClassCastExceptions, but there you go.

All of this said, I do believe the original code should work as it shouldn't
be necessary to refer to org.apache.* when writing an extension.  Looking at
it, it looks like the issue is that the XPathContext object should allow for
the pushing of arbitrary org.w3c.dom.traversal.NodeIterator or
org.w3c.dom.NodeList objects and should sort the interface details out
itself.  

So:
i) Do people agree that this is a bug?  If so, I'll log it.
ii) Do people agree that the proposed solution is correct?  If so, I'll try
to implement it and submit the change back to here.  (This might take a bit
longer.)

As a side note, I don't believe I should have needed the getNodeList
function, it should have been possible to just call new, but this is small
potatoes.

Incidentally, the reason for wanting to do this is to allow Xalan to process
message queues directly.

Thank you for listening,

Julian.

P.S.  The promised wrapper class:
// StreamableContextNodeList
package spong;

import org.apache.xpath.axes.ContextNodeList;
import org.w3c.dom.traversal.NodeIterator;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.DOMException;

// Wraps an iterator as a ContextNodeList
public class StreamableContextNodeList implements
org.w3c.dom.traversal.NodeIterator, org.apache.xpath.axes.ContextNodeList {
  private NodeIterator mobjIterator;    // The wrapped iterator
  private int mlngCurrentPosition;      // The current position
  private Node mobjCurrentNode;         // The current node


  public StreamableContextNodeList(NodeIterator objIterator) {
    mobjIterator = objIterator;
  }
  
  public Node getCurrentNode() {
    return mobjCurrentNode;
  }

  public int getCurrentPos() {
    return mlngCurrentPosition;
  }

  public void reset() {
    // Ignore
  }

  public void setShouldCacheNodes(boolean parm1) {
    // Ignore
  }

  public void runTo(int parm1) {
    try {
      if (parm1 == -1) {    // run to end
        while (this.nextNode() != null) {
          // Empty loop
        }
      } else {
        while (mlngCurrentPosition < parm1) {
          this.nextNode();
        }
      }
    } catch (DOMException e) {
      // Ignore
    }
  }

  public void setCurrentPos(int parm1) {
    runTo(parm1);
  }

  public int size() {
    return mlngCurrentPosition;  // Have yet to receive any more records
  }

  public boolean isFresh() {
    return mlngCurrentPosition == 0;
  }

  public NodeIterator cloneWithReset() throws CloneNotSupportedException {
    return (NodeIterator) clone();
  }

  public Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException("The streaming NodeIterator could
not be cloned.");
  }

  // I have _no_ idea what the next two methods do, so I've ganked the code
from org.apache.xpath.NodeSet
  transient private int m_last = 0;
  
  public int getLast()
  {
    return m_last;
  }
  
  public void setLast(int last)
  {
    m_last = last;
  }

  public Node getRoot() {
    return mobjIterator.getRoot();
  }

  public int getWhatToShow() {
    return mobjIterator.getWhatToShow();
  }

  public NodeFilter getFilter() {
    return mobjIterator.getFilter();
  }

  public boolean getExpandEntityReferences() {
    return mobjIterator.getExpandEntityReferences();
  }

  public Node nextNode() throws DOMException {
    mlngCurrentPosition++;
    return mobjCurrentNode = mobjIterator.nextNode();
  }

  public Node previousNode() throws DOMException {
    mlngCurrentPosition--;
    return mobjCurrentNode = mobjIterator.previousNode();

  }

  public void detach() {
    mobjIterator.detach();
  }
}
===========================================================================
The information in this E-mail (which includes any files transmitted with
it), is confidential and may also be legally privileged. It is intended for
the addressee only. Access to this E-mail by anyone else is unauthorised. If
you have received it in error, please destroy any copies and delete it from
your system notifying the sender immediately. Any use, dissemination,
forwarding, printing or copying of this E-mail is prohibited. E-mail
communications are not secure and therefore Rolfe & Nolan does not accept
legal responsibility for the contents of this message. Any views or opinions
presented are solely those of the author and do not necessarily represent
those of Rolfe & Nolan.
===========================================================================

Reply via email to