如何编写一个返回节点的Saxon ExtensionFunctionDefinition

huangapple go评论70阅读模式
英文:

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 创建转换器,HelloNodeExtensionFunctionDefinition

转换的代码如下:

        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.

huangapple
  • 本文由 发表于 2023年7月27日 19:55:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76779478.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定