Hi Michael, Sorry for the delay (been a busy week!), but here's a trivial example that exposes the issue. Run it and open the created file (result.html) in the browser to see the issue - the variable used can only be accessed once by the extension element, and so only the first amount is doubled in each case.
Peter. 2009/4/20 Michael Ludwig <mil...@gmx.de> > Peter Carberry schrieb am 16.04.2009 um 15:03:03 (+0100): > > Hi Michael, > > > > I'm not using any of the conversion functions, just creating a > > standard XPath object and calling its execute method. I know from > > debugging that the XObject returned is a nodeset, in the case of every > > call after the first however it is empty. > > > > It seems as if whatever way I'm using XPath it's only allowing me to > > resolve the variable the first time. If I replace all instances of the > > variable in the stylesheet with the key statement that generates it > > (ie switching "key('myKeyResolvesToBlah', 'blah')" for "$blahVar") > > then the XPath queries all resolve OK. There's something that > > <xsl:value-of select="" /> is doing that I am not, but I don't know > > what it is. > > Hi Peter, > > maybe the best way to solve this is to post a small, self-contained > example that exposes the problem, so others can reproduce it or debug it > in their environments. > > Best, > > Michael >
<root> <amounttypes> <amounttype code="beginning" name="Beginning Amount" /> <amounttype code="ending" name="Ending Amount" /> </amounttypes> <amounts> <amount code="beginning"> <q1>1</q1> <q2>2</q2> </amount> <amount code="ending"> <q1>3</q1> <q2>4</q2> </amount> </amounts> </root>
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:tst="xalan://XalanTest" extension-element-prefixes="tst"> <xsl:output method="xml" omit-xml-declaration="yes" indent="no" encoding="UTF-8" /> <xsl:key name="retrieveAmounts" match="/root/amounts/amount" use="@code" /> <xsl:template match="/"> <html> <body> <div> Should display the original amount using "xsl:value-of select", then that amount doubled by the test<br /> extension. Works the first time for Q1, doesn't work the second time. </div> <div> <table> <tr> <th width="300px">Name</th> <th width="100px">Original Val</th> <th width="100px">Doubled</th> </tr> <xsl:for-each select="/root/amounttypes/amounttype"> <xsl:variable name="amountName" select="@name" /> <xsl:variable name="singleAmount" select="key('retrieveAmounts', @code)" /> <tr> <td colspan="3"> <b><xsl:value-of select="$amountName" /></b> </td> </tr> <tr> <td>Q1</td> <td align="right"> <xsl:value-of select="$singleAmount/q1" /> </td> <td align="right"> <tst:doubler value="$singleAmount/q1" /> </td> </tr> <tr> <td>Q2</td> <td align="right"> <xsl:value-of select="$singleAmount/q2" /> </td> <td align="right"> <tst:doubler value="$singleAmount/q2" /> </td> </tr> </xsl:for-each> </table> </div> </body> </html> </xsl:template> </xsl:stylesheet>
import java.io.File; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.xalan.extensions.ExpressionVisitor; import org.apache.xalan.extensions.XSLProcessorContext; import org.apache.xalan.templates.ElemExtensionCall; import org.apache.xalan.transformer.TransformerImpl; import org.apache.xpath.Expression; import org.apache.xpath.XPath; import org.apache.xpath.XPathContext; import org.apache.xpath.objects.XObject; public class XalanTest { private static String XSL_SOURCE = "test.xsl"; private static String XML_SOURCE = "test.xml"; private static String RESULTING_FILE = "result.html"; public static void main(String[] args) throws TransformerConfigurationException, TransformerException { TransformerFactory tFactory = TransformerFactory.newInstance(); StreamSource xslStreamSource = new StreamSource(new File(XSL_SOURCE)); Templates xslTemplate = tFactory.newTemplates(xslStreamSource); Transformer transformer = xslTemplate.newTransformer(); transformer.transform( new StreamSource(new File(XML_SOURCE)), new StreamResult(RESULTING_FILE)); } public static String doubler(XSLProcessorContext context, ElemExtensionCall call) throws TransformerException { String expression = call.getAttribute("value"), doubledValue = ""; String numberValueString = xpathLookup(context, call, expression); try { int numberValue = Integer.parseInt(numberValueString); doubledValue = Integer.valueOf(numberValue * 2).toString(); } catch(NumberFormatException e) { } return doubledValue; } protected static String xpathLookup(XSLProcessorContext context, ElemExtensionCall call, String exp) throws TransformerException { String nodeText = ""; if ((exp != null && exp.length() != 0)) { TransformerImpl transformer = context.getTransformer(); XPathContext xpContext = transformer.getXPathContext(); try { xpContext.pushNamespaceContext(call); int current = xpContext.getCurrentNode(); xpContext.pushCurrentNodeAndExpression(current,current); XPath dynamicXPath = new XPath( exp, xpContext.getSAXLocator(), xpContext.getNamespaceContext(), XPath.SELECT, transformer.getErrorListener()); dynamicXPath.callVisitors(dynamicXPath, new ExpressionVisitor(context.getStylesheet().getStylesheetRoot())); Expression expression = dynamicXPath.getExpression(); XObject xobj1 = expression.execute(xpContext); xpContext.popCurrentNodeAndExpression(); xpContext.popNamespaceContext(); nodeText = xobj1.toString(); } catch(TransformerException te) {} } return nodeText; } }