/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.core.xslt.functions; import java.util.List; import com.google.common.collect.Lists; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.FunctionCall; import net.sf.saxon.expr.RoleLocator; import net.sf.saxon.expr.TypeChecker; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.StringValue; public abstract class AbstractXsltFunctionCall extends FunctionCall { protected SequenceType[] argumentTypes; protected int minArguments; protected int maxArguments; protected ItemType resultType; protected int resultCardinality; @Override protected final void checkArguments( final ExpressionVisitor visitor ) throws XPathException { checkArgumentCount( this.minArguments, this.maxArguments, visitor ); for ( int i = 0; i < this.argument.length; i++ ) { checkArgument( visitor, i ); } } private void checkArgument( final ExpressionVisitor visitor, final int arg ) throws XPathException { final RoleLocator role = new RoleLocator( RoleLocator.FUNCTION, getFunctionName(), arg ); final SequenceType requiredType = getRequiredType( arg ); final boolean backwardCompatibleMode = visitor.getStaticContext().isInBackwardsCompatibleMode(); this.argument[arg] = TypeChecker.staticTypeCheck( this.argument[arg], requiredType, backwardCompatibleMode, role, visitor ); } private SequenceType getRequiredType( final int arg ) { if ( this.argumentTypes == null ) { return SequenceType.ANY_SEQUENCE; } return this.argumentTypes[arg]; } @Override public final ItemType getItemType( final TypeHierarchy th ) { return this.resultType; } @Override protected final int computeCardinality() { return this.resultCardinality; } @Override public final Expression preEvaluate( final ExpressionVisitor visitor ) throws XPathException { return this; } @Override public final Item evaluateItem( final XPathContext context ) throws XPathException { final SequenceIterator[] items = new SequenceIterator[this.argument.length]; for ( int i = 0; i < this.argument.length; i++ ) { items[i] = this.argument[i].iterate( context ); } return call( context, items ); } protected abstract Item call( final XPathContext context, final SequenceIterator[] args ) throws XPathException; @Override public final Expression copy() { throw new UnsupportedOperationException(); } protected final Item createValue( final String value ) { return new StringValue( value ); } protected final Item createValue( final boolean value ) { return BooleanValue.get( value ); } protected final String toSingleString( final SequenceIterator it ) throws XPathException { final Item item = it.next(); if ( item == null ) { return null; } else { return item.getStringValue(); } } protected final String[] toStringArray( final SequenceIterator it ) throws XPathException { final List<String> list = Lists.newArrayList(); while ( true ) { final Item current = it.next(); if ( current == null ) { break; } list.add( current.getStringValue() ); } return list.toArray( new String[list.size()] ); } protected final Long toSingleInteger( final SequenceIterator it ) throws XPathException { final Item item = it.next(); if ( item == null ) { return null; } else if ( item instanceof NumericValue ) { return ( (NumericValue) item ).getDecimalValue().longValue(); } else { return Long.parseLong( item.getStringValue() ); } } }