如何注册 Saxon/XSLT 扩展函数以便在 BaseX/XQuery 中访问它们(JAXP API)

How to register Saxon/XSLT extension functions such that they accessible in BaseX/XQuery (JAXP APIs)

我有几个 Saxon/XSLT 扩展函数,它们是通过 simple interface 创建的,我这样注册:

Processor proc = new Processor(false);
proc.registerExtensionFunction(myExtensionFunctionInstance);

现在我想将它与 BaseX 一起使用,但我看到 BaseX instantiates its own Processor instance through JAXP APIs:

// Somewhere inside basex's XSLT transformer instantiation (see link above).
final TransformerFactory tf = TransformerFactory.newInstance();

看来我需要找到一种方法来更改 BaseX 使用的工厂,以便我可以注册我的函数。

如果我做对了,我需要创建自己的工厂实现。改编自撒克逊人的 net.sf.saxon.TransformerFactoryImpl:

package my.package;
public class MyOwnTrasnformerFactory extends SaxonTransformerFactory {
    public TransformerFactoryImpl() {
        super();
        ExtensionFunction myFunction = new MyExtFunction(...);
        this.processor.registerExtensionFunction(myFunction);
    }

    public TransformerFactoryImpl(Configuration config) {
        super(config);
        ExtensionFunction myFunction = new MyExtFunction(...);
        this.processor.registerExtensionFunction(myFunction);
    }
}

然后我可以做:

System.setProperty(
  "javax.xml.transform.TransformerFactory",
  "my.package.MyOwnTrasnformerFactory");

我最终实施了我的问题中描述的解决方案...这是一个完整的要点:

https://gist.github.com/EmmanuelOga/018ece8b4776636ce1ab3f73e215ce75

相关部分:

(ns rainbowfish.xslt-factory
  (:import [net.sf.saxon Configuration]
           [net.sf.saxon.lib Feature])
  (:gen-class
   :name rainbowfish.XsltFactory
   :extends net.sf.saxon.jaxp.SaxonTransformerFactory
   :post-init configure))

(defn -configure
  "Generated Java class will call this method right after
  construction. Here we get a chance to grab Saxon's processor for
  configuration purposes (for example, adding extension functions)."
  [this & args]
  (let [processor (.getProcessor this)]
    ;; Here we can do whatever we want to the processor,
    ;; For instance, register some extension functions.
    (doto processor
      (.registerExtensionFunction some-function))))

即使用clojure定义了Javaclassrainbowfish.XsltFactory。由于使用了gen-class,所以需要通过调用compile('rainbowfish.xslt-factory)或者让lein编译等方式编译

现在我们有一个配置 XSLT 处理器的 class,我们需要通知 BaseX 它应该使用它。 BaseX 为此读取 JAXP 配置。配置可以这样设置:

(System/setProperty
     "javax.xml.transform.TransformerFactory",
     "rainbowfish.XsltFactory")

...这应该在创建 BaseX 服务器实例之前调用。有关更多详细信息,请参阅要点!