Re: Can't access a variable's children in extension element
Peter Carberry <[email protected]>
| Newsgroups | gmane.text.xml.xalan.java.user |
|---|---|
| Message-ID | <[email protected]> |
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 >
test.xml
(text/xml, 508 B)
<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>
test.xsl
(text/xml, 3.7 KB)
<?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>
XalanTest.java
(text/x-java, 3.2 KB)
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;
}
}