英文:
How to write a Saxon ExtensionFunctionDefinition returning a Node
问题
使用Saxon HE 12,我成功创建了一个Saxon ExtensionFunctionDefinition,返回一个 SequenceType.SINGLE_STRING 并在XSLT转换中使用它;但是我很难创建一个返回节点的函数,例如 SequenceType.SINGLE_NODE。
扩展函数定义类的相关部分如下:
    @Override
    public ExtensionFunctionCall makeCallExpression() {
        return new ExtensionFunctionCall() {
            @Override
            public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
                Processor processor  = new Processor();
                net.sf.saxon.s9api.DocumentBuilder documentBuilder = processor.newDocumentBuilder();
                Document document = buildSomeDocument();
                XdmNode wrapped = documentBuilder.wrap(document.getFirstChild());
                return wrapped.getUnderlyingNode();
            }
        };
    }
其中,buildSomeDocument 返回一个 org.w3c.dom.Document。
代码可以编译,但是执行会抛出异常:
SXXP0004 Node returned by extension function was created with an incompatible Configuration
如何传递配置?
如何以最简单的方式返回(包装的)org.w3c.dom元素或节点?
-- 编辑:从 new Processor() 而不是 TransformerFactory 创建转换器,HelloNode 是 ExtensionFunctionDefinition。
转换的代码如下:
        Processor processor = new Processor();
        processor.registerExtensionFunction(new HelloNode());
        Path xslPath = Path.of("./some/path/to/testjavafunction.xsl");
        XsltCompiler xsltCompiler = processor.newXsltCompiler();
        XsltExecutable xsltExecutable = xsltCompiler.compile(xslPath.toFile());
        XsltTransformer xsltTransformer = xsltExecutable.load();
        // XML源
        Path xmlPath = Path.of("./some/path/to/testjavafunction.xml");
        InputStream inputStream = new FileInputStream(xmlPath.toFile());
        InputSource inputSource = new InputSource(inputStream);
        Source source = new SAXSource(inputSource);
        xsltTransformer.setSource(source);
        // 目标
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        Serializer serializerDestination = processor.newSerializer(byteArrayOutputStream);
        xsltTransformer.setDestination(serializerDestination);
        // 转换
        xsltTransformer.transform();
        // 调试打印
        System.out.println(byteArrayOutputStream.toString("UTF-8"));
call 方法现在已更新为:
   @Override
   public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
         Configuration.ApiProvider processor0 = context.getConfiguration().getProcessor();
         Processor processor = (Processor)processor0;
         net.sf.saxon.s9api.DocumentBuilder documentBuilder = processor.newDocumentBuilder();
         Document document = makeSomeDOM();
         XdmNode wrapped = documentBuilder.wrap(document.getFirstChild());
         return wrapped.getUnderlyingNode();
   }      
makeSomeDom 方法如下:
private static Document makeSomeDom() {
 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 DocumentBuilder db = dbf.newDocumentBuilder();
 Document document = db.newDocument();
 Element h1 = document.createElement("h1");
 h1.setTextContent("my-content");
 document.appendChild(h1);
 return document;
}
请注意,这些是您提供的代码和问题的翻译,不包括其他内容。
英文:
Using Saxon HE 12, I managed to create a Saxon ExtensionFunctionDefinition returning a SequenceType.SINGLE_STRING and using it in a XSLT transformation ; but I have a hard time making one returning a Node, let's say a SequenceType.SINGLE_NODE for this exemple.
Relevant part of the ExtensionFunctionDefinition extending class is :
    @Override
    public ExtensionFunctionCall makeCallExpression() {
        return new ExtensionFunctionCall() {
            @Override
            public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
                Processor processor  = new Processor();
                net.sf.saxon.s9api.DocumentBuilder documentBuilder = processor.newDocumentBuilder();
                Document document = buildSomeDocument();
                XdmNode wrapped = documentBuilder.wrap(document.getFirstChild());
                return wrapped.getUnderlyingNode();
            }
        };
    }
where buildSomeDocument returns a org.w3c.dom.Document
The code compiles fine but execution throws an exception :
 SXXP0004  Node returned by extension function was created with an incompatible Configuration
How to pass the configuration ?
What would be the simplest way to return a (wrapped) org.w3c.dom Element or Node ?
-- edit Creating the Transformer starting from new Processor() instead of TransformerFactory, HelloNode beeing the ExtensionFunctionDefinition
The code for the transformation is :
        Processor processor = new Processor();
        processor.registerExtensionFunction(new HelloNode());
        Path xslPath = Path.of("./some/path/to/testjavafunction.xsl");
        XsltCompiler xsltCompiler = processor.newXsltCompiler();
        XsltExecutable xsltExecutable = xsltCompiler.compile(xslPath.toFile());
        XsltTransformer xsltTransformer = xsltExecutable.load();
        // xml source
        Path xmlPath = Path.of("./some/path/to/testjavafunction.xml");
        InputStream inputStream = new FileInputStream(xmlPath.toFile());
        InputSource inputSource = new InputSource(inputStream);
        Source source = new SAXSource(inputSource);
        xsltTransformer.setSource(source);
        // destination
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        Serializer serializerDestination = processor.newSerializer(byteArrayOutputStream);
        xsltTransformer.setDestination(serializerDestination);
        // transform
        xsltTransformer.transform();
        // dbg print
        System.out.println(byteArrayOutputStream.toString("UTF-8"));
the call method is now updated to :
   @Override
   public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
         Configuration.ApiProvider processor0 = context.getConfiguration().getProcessor();
         Processor processor = (Processor)processor0;
         net.sf.saxon.s9api.DocumentBuilder documentBuilder = processor.newDocumentBuilder();
         Document document = makeSomeDOM();
         XdmNode wrapped = documentBuilder.wrap(document.getFirstChild());
         return wrapped.getUnderlyingNode();
   }      
makeSomeDommethod is :
private static Document makeSomeDom() {
 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 DocumentBuilder db = dbf.newDocumentBuilder();
 Document document = db.newDocument();
 Element h1 = document.createElement("h1");
 h1.setTextContent("my-content");
 document.appendChild(h1);
 return document;
}
答案1
得分: 2
以下是您要翻译的代码部分:
public ExtensionFunctionCall makeCallExpression() {
    return new ExtensionFunctionCall() {
        @Override
        public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
            Processor processor = (Processor)context.getConfiguration().getProcessor();
            DocumentBuilder documentBuilder = processor.newDocumentBuilder();
            Document document = null;
            try {
                document = buildSomeDocument();
            } catch (ParserConfigurationException e) {
                throw new RuntimeException(e);
            }
            XdmNode wrapped = documentBuilder.wrap(document);
            return wrapped.getUnderlyingNode();
        }
    };
}
关于设置处理器和注册扩展函数的代码:
Processor processor = new Processor();
processor.getUnderlyingConfiguration().setProcessor(processor);
processor.registerExtensionFunction(new MyExtensionFunctionDefinition());
这些代码可以在 https://github.com/martin-honnen/SaxonHE12ExtensionFunctionDomNodeExample1 中找到。
英文:
Spelling out my suggestion from the comment, the code is e.g.
public ExtensionFunctionCall makeCallExpression() {
      return new ExtensionFunctionCall() {
          @Override
          public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
              Processor processor = (Processor)context.getConfiguration().getProcessor();
              DocumentBuilder documentBuilder = processor.newDocumentBuilder();
              Document document = null;
              try {
                  document = buildSomeDocument();
              } catch (ParserConfigurationException e) {
                  throw new RuntimeException(e);
              }
              XdmNode wrapped = documentBuilder.wrap(document);
              return wrapped.getUnderlyingNode();
          }
      };
}
The code to set up the processor and register the extension function:
Processor processor = new Processor();
processor.getUnderlyingConfiguration().setProcessor(processor);
processor.registerExtensionFunction(new MyExtensionFunctionDefinition());
All visible in https://github.com/martin-honnen/SaxonHE12ExtensionFunctionDomNodeExample1.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论