Не удается найти подходящую функцию с 0 аргументами под названием {NAME}METHOD() во встроенном правиле шаблона.

Я зарегистрировал ExtensionFunctionDefinition без параметров, но не могу его вызвать.
Что не так и как это можно исправить?
Похоже, что функция не зарегистрирована.
Вот код:

саксонский

     ...<saxon.he.version>9.7.0-3</saxon.he.version>...
        <groupId>net.sf.saxon</groupId>
        <artifactId>Saxon-HE</artifactId>...

Исключение

Error at char 29 in xsl:value-of/@select on line 23 column 71 
XTDE1425: Cannot find a matching 0-argument function named {http://date.com}getFormattedNow()
in built-in template rule

XSLT

<xsl:stylesheet ...
            xmlns:dateService="http://date.com"
            exclude-result-prefixes="dateService" version="1.0">
...
            <xsl:value-of select="dateService:getFormattedNow()"/>

ExtensionFunctionDefinition

public class DateExtensionFunction extends ExtensionFunctionDefinition {
public StructuredQName getFunctionQName() {
    return new StructuredQName("", "http://date.com", "getFormattedNow");
}

public SequenceType[] getArgumentTypes() {
    return new SequenceType[]{SequenceType.OPTIONAL_STRING};
}

public SequenceType getResultType(SequenceType[] sequenceTypes) {
    return SequenceType.SINGLE_STRING;
}

public boolean trustResultType() {
    return true;
}

public int getMinimumNumberOfArguments() {
    return 0;
}

public int getMaximumNumberOfArguments() {
    return 1;
}

public ExtensionFunctionCall makeCallExpression() {
    return new ExtensionFunctionCall() {

        public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
                return new StringValue("TEST");
        }
    };
}
}

Трансформер

    Processor processor = new Processor(false);
    Configuration configuration = new Configuration();
    TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
    processor.registerExtensionFunction(new DateExtensionFunction());
    configuration.setProcessor(processor);
    transformerFactory.setConfiguration(configuration);
    //...newTransformer

person Arthur    schedule 15.03.2016    source источник


Ответы (3)


Отношения между вашим процессором, конфигурацией и TransformerFactory неверны.

Лучше всего думать о конфигурации как о хранении всех важных данных, а о процессоре и TransformerFactory как о внешнем API поверх конфигурации.

Когда вы создаете процессор, под ним создается собственная конфигурация. То же самое для TransformerFactoryImpl. Итак, у вас есть три объекта конфигурации: два, которые создал Саксон, и один, который создали вы. Функция расширения регистрируется в конфигурации, лежащей в основе процессора (s9api), которая не имеет никакого отношения к той, которую вы используете с JAXP TransformerFactory.

Я бы порекомендовал вам использовать либо JAXP, либо s9api, но избегайте их смешивания. Если вы хотите использовать JAXP, выполните:

    TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
    Configuration config = transformerFactory.getConfiguration();
    config.registerExtensionFunction(new DateExtensionFunction());

Обратите внимание, что начиная с Saxon 9.7 интерфейс JAXP реализуется как слой поверх интерфейса s9api.

person Michael Kay    schedule 15.03.2016
comment
Большое спасибо! Но он по-прежнему не видит функцию: TransformerFactoryImpl transformFactory = new TransformerFactoryImpl(); transformFactory.getConfiguration().registerExtensionFunction (new DateExtensionFunctionDefinition()); - person Arthur; 15.03.2016

Вот некоторый работающий код (проверено на Saxon 9.7 HE). Я не знаю, почему у вас нет: пожалуйста, составьте полную программу, иллюстрирующую проблему.

import ....;
public class ExtensionTest extends TestCase {

public class DateExtensionFunction extends ExtensionFunctionDefinition {
    public StructuredQName getFunctionQName() {
        return new StructuredQName("", "http://date.com", "getFormattedNow");
    }

    public net.sf.saxon.value.SequenceType[] getArgumentTypes() {
        return new net.sf.saxon.value.SequenceType[]{net.sf.saxon.value.SequenceType.OPTIONAL_STRING};
    }

    public net.sf.saxon.value.SequenceType getResultType(net.sf.saxon.value.SequenceType[] sequenceTypes) {
        return net.sf.saxon.value.SequenceType.SINGLE_STRING;
    }

    public boolean trustResultType() {
        return true;
    }

    public int getMinimumNumberOfArguments() {
        return 0;
    }

    public int getMaximumNumberOfArguments() {
        return 1;
    }

    public ExtensionFunctionCall makeCallExpression() {
        return new ExtensionFunctionCall() {

            public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
                return new StringValue("TEST");
            }
        };
    }
}

public void testIntrinsicExtension() {
    try {
        TransformerFactoryImpl factory = new TransformerFactoryImpl();
        factory.getConfiguration().registerExtensionFunction(new DateExtensionFunction());
        String xsl = "<e xsl:version='3.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' " +
                "result='{Q{http://date.com}getFormattedNow()}'/>";
        Templates t = factory.newTemplates(new StreamSource(new StringReader(xsl)));
        StringWriter sw = new StringWriter();
        t.newTransformer().transform(new StreamSource(new StringReader("<a/>")), new StreamResult(sw));
        System.err.println(sw.toString());
    } catch (TransformerConfigurationException tce) {
        tce.printStackTrace();
        fail();
    } catch (TransformerException e) {
        e.printStackTrace();
        fail();
    }
    }
}

Результат:

<?xml version="1.0" encoding="UTF-8"?><e result="TEST"/>
person Michael Kay    schedule 15.03.2016

Решение (работает только для Saxon 9.4):

@Override
public ExtensionFunctionCall makeCallExpression() {
    return new ExtensionFunctionCall() {
        @Override
        @SuppressWarnings("unchecked")
        public SequenceIterator call(SequenceIterator[] arguments, XPathContext context) throws XPathException {
            return SingletonIterator.makeIterator(StringValue.makeStringValue("TEST"));
        }
    };
}
person Arthur    schedule 16.03.2016