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;
    }
}

Reply via email to