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 <[email protected]>
> 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;
}
}