user1490664
user1490664

Reputation: 27

Saxon-HE Java Extension - How to I access the value of a xsl-variable which is passed as a parameter?

I have created a function using the Saxon documentation which has 3 parameters. The function takes an input string and pads it out to a specific size using an integer and string values.

padStringLeft(inputStr,size,padChar)

If I put this in my XSLT and hard wire the parameters the function works.

<debug1><xsl:value-of select="c4j_XSLT_Ext_padStringLeft:padStringLeft('1',4,'0')" /></debug1>

The output from the above would be '0001'

When I pass the contents of a XSLT variable however and set a debug / break point in my java function I can see that I'm getting param0 as a lazysequence.

<debug2><xsl:value-of select="c4j_XSLT_Ext_padStringLeft:padStringLeft($myvar,4,'0')" /></debug2>

Java function

As my code is attempting to treat it as a string it does not work.

How should I be handling this scenario, how do I access the value or the xsl-variable/param and what if sometimes I want to use a literal string instead of a variable?

public class XSLT_Ext_padStringLeft extends ExtensionFunctionDefinition
{

    @Override
    public SequenceType[] getArgumentTypes()
    {
        return new SequenceType[]{SequenceType.SINGLE_STRING,SequenceType.SINGLE_INTEGER, SequenceType.SINGLE_STRING};
    }

    @Override
    public StructuredQName getFunctionQName()
    {
        return new StructuredQName("c4j_XSLT_Ext_padStringLeft", "http://com.commander4j.Transformation.XSLT_Ext_padStringLeft", "padStringLeft");
    }

    @Override
    public SequenceType getResultType(SequenceType[] arg0)
    {
         return SequenceType.SINGLE_STRING;
    }

    @Override
    public ExtensionFunctionCall makeCallExpression()
    {
           return new ExtensionFunctionCall() {
                @Override
                public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
                    
                    String inputStr;
                    try
                    {
                        inputStr = ((StringValue)arguments[0]).getStringValue();
                    } catch (ClassCastException ex)
                    {
                       inputStr = "";   
                    }

                    
                    long size;
                    try
                    {
                        String temp =arguments[1].toString();
                        size = Integer.valueOf(temp);
                    } catch (ClassCastException ex)
                    {
                        size = 1;   
                    }
                    
                    String padStr;
                    try
                    {
                        padStr = ((StringValue)arguments[2]).getStringValue();
                    } catch (ClassCastException ex)
                    {
                        padStr = "";    
                    }
                    
                    String result = inputStr;
                    
                    while (result.length() < size)
                    {
                        result = padStr + result;
                    }

                    return StringValue.makeStringValue(result);
                }
            };
    }

}

Thanks

Dave

Upvotes: 2

Views: 452

Answers (2)

user1490664
user1490664

Reputation: 27

Also note, Saxon uses lazy evaluation wherever possible, which means that the string might not actually be computed until someone asks for its value. This means that innocent-looking calls like head() and getStringValue() can actually throw exceptions, and you need to be prepared for this.

So if I understand you correctly - when I call Transform to process the XSLT transformation it will call each of my custom java external functions as needed but the reference to

inputStr = arguments[0].head().getStringValue();

could generate an exception?

I would then need to do something within the java function to force it to get the value - or would I let the exception propogate back to the calling Transformation and catch it there ?

Dave

Upvotes: 0

Michael Kay
Michael Kay

Reputation: 163312

In general the parameters are passed as instance of the class net.sf.saxon.om.Sequence, and you should only use the methods on the interface Sequence, rather than examining what particular kind of Sequence it is, because that could change in the future.

If you're expecting a singleton sequence (that is, a single item), call head() to get the first item in the sequence (this will return null if the sequence is empty). You will then have an instance of net.sf.saxon.om.Item. (The Sequence might already be an Item, because an item is a sequence, but you can't rely on that, and calling head() is safer than casting.) If you're expecting a string, you can safely call getStringValue() on this item to get the value as a string.

Also note, Saxon uses lazy evaluation wherever possible, which means that the string might not actually be computed until someone asks for its value. This means that innocent-looking calls like head() and getStringValue() can actually throw exceptions, and you need to be prepared for this.

So in short, you should replace

inputStr = ((StringValue)arguments[0]).getStringValue();

with

inputStr = arguments[0].head().getStringValue();

Upvotes: 1

Related Questions