英文:
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();
}
makeSomeDom
method 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论