如何计算 Xalan 扩展函数实现中的 XPath 表达式?
How do I evaluate an XPath expression within a Xalan extension function implementation?
我正在尝试在 Xalan 2.7.1 提供给扩展函数的上下文中计算 XPath 表达式。出于某种原因,这在 Xalan 中总是失败并出现内部异常。
注意:您需要在类路径中 xalan-j 才能 运行 这个。
package org.example;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import javax.xml.namespace.NamespaceContext;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.w3c.dom.traversal.NodeIterator;
import org.apache.xalan.extensions.ExpressionContext;
public class XalanExtension {
public static final String NS = "org:example:foo";
public static final String XSLT = "" +
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<xsl:stylesheet \n" +
" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n" +
" xmlns:foo=\"org:example:foo\"\n" +
" xmlns:fun=\"xalan://org.example.XalanExtension\"\n" +
" version=\"1.0\"> \n" +
" \n" +
" <xsl:template match=\"*|@*\">\n" +
" <xsl:apply-templates select=\"*|@*\"/>\n" +
" </xsl:template>\n" +
" \n" +
" <xsl:template match=\"foo:test\">\n" +
" <xsl:variable name=\"result\" select=\"fun:evaluate(.)\"/>\n" +
" <xsl:message>\n" +
" Test: <xsl:value-of select=\".\"/> Result: <xsl:value-of select=\"$result\"/>\n" +
" </xsl:message>\n" +
" </xsl:template>\n" +
" \n" +
"</xsl:stylesheet>";
public static final String XML = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<tests xmlns=\"org:example:foo\">\n" +
" <a>1</a>\n" +
" <b>2</b>\n" +
" <c>3</c>\n" +
" <test>../foo:a > 5</test>\n" +
"</tests>";
private TransformerFactory xalanTransFact;
public XalanExtension() {
xalanTransFact = new org.apache.xalan.processor.TransformerFactoryImpl();
}
public void transform() {
try {
StringWriter writer;
writer = new StringWriter();
System.out.println(org.apache.xalan.Version.getVersion());
Transformer transformer = xalanTransFact.newTransformer(new StreamSource(new StringReader(XSLT)));
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "text");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.transform(
new StreamSource(new StringReader(XML)),
new StreamResult(writer));
System.out.println(writer.toString());
} catch (TransformerConfigurationException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
XalanExtension instance = new XalanExtension();
instance.transform();
}
public static final NodeList evaluate(ExpressionContext ctx, NodeIterator nodes) {
// first node in document order
Node node = nodes.nextNode();
if (node != null && node.hasChildNodes()) {
try {
String xpathExpression = node.getFirstChild().getNodeValue();
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if ("foo".equals(prefix)) {
return NS;
}
return null;
}
@Override
public String getPrefix(String namespaceURI) {
if (NS.equals(namespaceURI)) {
return "foo";
}
return null;
}
@Override
public Iterator getPrefixes(String namespaceURI) {
return null;
}
});
return (NodeList) xpath.evaluate(xpathExpression, ctx.getContextNode(), XPathConstants.NODESET);
} catch (XPathExpressionException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, "xpath evaluation failed", ex);
}
}
return null;
}
}
扩展功能在org.example.XalanExtension.evaluate(ExpressionContext, NodeIterator)
实现。它确实被 Xalan 调用,但是我正在使用的 XPath 评估代码不起作用。该程序只是找到一个具有众所周知值的特定元素,该元素实际上是一个 XPath 表达式,要在它出现的上下文中进行计算。
我从程序中得到以下输出:
Xalan Java 2.7.1
jan. 31, 2017 3:09:10 PM org.example.XalanExtension evaluate
SEVERE: xpath evaluation failed
javax.xml.transform.TransformerException: Unknown error in XPath.
at org.apache.xpath.XPath.execute(XPath.java:365)
at org.apache.xpath.XPath.execute(XPath.java:303)
at org.apache.xpath.jaxp.XPathImpl.eval(XPathImpl.java:216)
at org.apache.xpath.jaxp.XPathImpl.evaluate(XPathImpl.java:281)
at org.example.XalanExtension.evaluate(XalanExtension.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:367)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:440)
at org.apache.xalan.extensions.ExtensionsTable.extFunction(ExtensionsTable.java:222)
at org.apache.xalan.transformer.TransformerImpl.extFunction(TransformerImpl.java:473)
at org.apache.xpath.functions.FuncExtFunction.execute(FuncExtFunction.java:208)
at org.apache.xpath.XPath.execute(XPath.java:337)
at org.apache.xalan.templates.ElemVariable.getValue(ElemVariable.java:280)
at org.apache.xalan.templates.ElemVariable.execute(ElemVariable.java:248)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2400)
at org.apache.xalan.transformer.TransformerImpl.applyTemplateToNode(TransformerImpl.java:2270)
at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1356)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:709)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1273)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1251)
at org.example.XalanExtension.transform(XalanExtension.java:67)
at org.example.XalanExtension.main(XalanExtension.java:81)
Caused by: java.lang.NullPointerException
at org.apache.xpath.axes.AxesWalker.setRoot(AxesWalker.java:221)
at org.apache.xpath.axes.ReverseAxesWalker.setRoot(ReverseAxesWalker.java:53)
at org.apache.xpath.axes.WalkingIterator.setRoot(WalkingIterator.java:157)
at org.apache.xpath.axes.NodeSequence.setRoot(NodeSequence.java:265)
at org.apache.xpath.axes.LocPathIterator.execute(LocPathIterator.java:212)
at org.apache.xpath.Expression.execute(Expression.java:155)
at org.apache.xpath.operations.Operation.execute(Operation.java:109)
at org.apache.xpath.XPath.execute(XPath.java:337)
... 28 more
---------
java.lang.NullPointerException
at org.apache.xpath.axes.AxesWalker.setRoot(AxesWalker.java:221)
at org.apache.xpath.axes.ReverseAxesWalker.setRoot(ReverseAxesWalker.java:53)
at org.apache.xpath.axes.WalkingIterator.setRoot(WalkingIterator.java:157)
at org.apache.xpath.axes.NodeSequence.setRoot(NodeSequence.java:265)
at org.apache.xpath.axes.LocPathIterator.execute(LocPathIterator.java:212)
at org.apache.xpath.Expression.execute(Expression.java:155)
at org.apache.xpath.operations.Operation.execute(Operation.java:109)
at org.apache.xpath.XPath.execute(XPath.java:337)
at org.apache.xpath.XPath.execute(XPath.java:303)
at org.apache.xpath.jaxp.XPathImpl.eval(XPathImpl.java:216)
at org.apache.xpath.jaxp.XPathImpl.evaluate(XPathImpl.java:281)
at org.example.XalanExtension.evaluate(XalanExtension.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:367)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:440)
at org.apache.xalan.extensions.ExtensionsTable.extFunction(ExtensionsTable.java:222)
at org.apache.xalan.transformer.TransformerImpl.extFunction(TransformerImpl.java:473)
at org.apache.xpath.functions.FuncExtFunction.execute(FuncExtFunction.java:208)
at org.apache.xpath.XPath.execute(XPath.java:337)
at org.apache.xalan.templates.ElemVariable.getValue(ElemVariable.java:280)
at org.apache.xalan.templates.ElemVariable.execute(ElemVariable.java:248)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2400)
at org.apache.xalan.transformer.TransformerImpl.applyTemplateToNode(TransformerImpl.java:2270)
at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1356)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:709)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1273)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1251)
at org.example.XalanExtension.transform(XalanExtension.java:67)
at org.example.XalanExtension.main(XalanExtension.java:81)
--------------- linked to ------------------
javax.xml.xpath.XPathExpressionException: javax.xml.transform.TransformerException: Unknown error in XPath.
at org.apache.xpath.jaxp.XPathImpl.evaluate(XPathImpl.java:295)
at org.example.XalanExtension.evaluate(XalanExtension.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:367)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:440)
at org.apache.xalan.extensions.ExtensionsTable.extFunction(ExtensionsTable.java:222)
at org.apache.xalan.transformer.TransformerImpl.extFunction(TransformerImpl.java:473)
at org.apache.xpath.functions.FuncExtFunction.execute(FuncExtFunction.java:208)
at org.apache.xpath.XPath.execute(XPath.java:337)
at org.apache.xalan.templates.ElemVariable.getValue(ElemVariable.java:280)
at org.apache.xalan.templates.ElemVariable.execute(ElemVariable.java:248)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2400)
at org.apache.xalan.transformer.TransformerImpl.applyTemplateToNode(TransformerImpl.java:2270)
at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1356)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:709)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1273)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1251)
at org.example.XalanExtension.transform(XalanExtension.java:67)
at org.example.XalanExtension.main(XalanExtension.java:81)
Caused by: javax.xml.transform.TransformerException: Unknown error in XPath.
at org.apache.xpath.XPath.execute(XPath.java:365)
at org.apache.xpath.XPath.execute(XPath.java:303)
at org.apache.xpath.jaxp.XPathImpl.eval(XPathImpl.java:216)
at org.apache.xpath.jaxp.XPathImpl.evaluate(XPathImpl.java:281)
... 25 more
Caused by: java.lang.NullPointerException
at org.apache.xpath.axes.AxesWalker.setRoot(AxesWalker.java:221)
at org.apache.xpath.axes.ReverseAxesWalker.setRoot(ReverseAxesWalker.java:53)
at org.apache.xpath.axes.WalkingIterator.setRoot(WalkingIterator.java:157)
at org.apache.xpath.axes.NodeSequence.setRoot(NodeSequence.java:265)
at org.apache.xpath.axes.LocPathIterator.execute(LocPathIterator.java:212)
at org.apache.xpath.Expression.execute(Expression.java:155)
at org.apache.xpath.operations.Operation.execute(Operation.java:109)
at org.apache.xpath.XPath.execute(XPath.java:337)
... 28 more
SystemId Unknown; Line #14; Column #22;
Test: ../foo:a > 5 Result:
如何在 Xalan 扩展函数实现中(在提供给它的上下文中)评估 XPath 表达式?我没有正确初始化 XPathFactory
/XPath instance
吗?
这是上面代码中的两个文档:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:foo="org:example:foo"
xmlns:fun="xalan://org.example.XalanExtension"
version="1.0">
<xsl:template match="*|@*">
<xsl:apply-templates select="*|@*"/>
</xsl:template>
<xsl:template match="foo:test">
<xsl:variable name="result" select="fun:evaluate(.)"/>
<xsl:message>
Test: <xsl:value-of select="."/> Result: <xsl:value-of select="$result"/>
</xsl:message>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<tests xmlns="org:example:foo">
<a>1</a>
<b>2</b>
<c>3</c>
<test>../foo:a > 5</test>
</tests>
注意:我很了解 dyn:evaluate
功能。本题与此无关
我问得太快了。在查看了一些 Xalan 扩展函数的实现方式后,我找到了实现 XPath 求值的 Xalan 特定代码(是的,对于 dyn:evaluate
)。
package org.example;
import java.io.*;
import java.util.logging.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
import org.w3c.dom.traversal.NodeIterator;
import org.apache.xalan.extensions.ExpressionContext;
import org.apache.xpath.XPathContext;
import org.apache.xpath.objects.XNodeSet;
public class XalanExtension {
public static final String NS = "org:example:foo";
public static final String XSLT = "" +
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<xsl:stylesheet \n" +
" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n" +
" xmlns:foo=\"org:example:foo\"\n" +
" xmlns:fun=\"xalan://org.example.XalanExtension\"\n" +
" version=\"1.0\"> \n" +
" \n" +
" <xsl:template match=\"*|@*\">\n" +
" <xsl:apply-templates select=\"*|@*\"/>\n" +
" </xsl:template>\n" +
" \n" +
" <xsl:template match=\"foo:test\">\n" +
" <xsl:variable name=\"result\" select=\"fun:evaluate(.)\"/>\n" +
" <xsl:message>\n" +
" Test: <xsl:value-of select=\".\"/> Result: <xsl:value-of select=\"$result\"/>\n" +
" </xsl:message>\n" +
" </xsl:template>\n" +
" \n" +
"</xsl:stylesheet>";
public static final String XML = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<tests xmlns=\"org:example:foo\">\n" +
" <a>1</a>\n" +
" <b>2</b>\n" +
" <c>3</c>\n" +
" <test>../foo:a > 5</test>\n" +
"</tests>";
private TransformerFactory xalanTransFact;
public XalanExtension() {
xalanTransFact = new org.apache.xalan.processor.TransformerFactoryImpl();
}
public void transform() {
try {
StringWriter writer;
writer = new StringWriter();
System.out.println(org.apache.xalan.Version.getVersion());
Transformer transformer = xalanTransFact.newTransformer(new StreamSource(new StringReader(XSLT)));
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "text");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.transform(
new StreamSource(new StringReader(XML)),
new StreamResult(writer));
System.out.println(writer.toString());
} catch (TransformerConfigurationException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
XalanExtension instance = new XalanExtension();
instance.transform();
}
public static final Object evaluate(ExpressionContext myContext, NodeIterator nodes) {
if (myContext instanceof XPathContext.XPathExpressionContext) {
XPathContext xctxt = null;
Node node = nodes.nextNode();
if (node != null && node.hasChildNodes()) {
String xpathExpr = node.getFirstChild().getNodeValue();
try {
xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
org.apache.xpath.XPath dynamicXPath = new org.apache.xpath.XPath(xpathExpr, xctxt.getSAXLocator(),
xctxt.getNamespaceContext(),
org.apache.xpath.XPath.SELECT);
return dynamicXPath.execute(xctxt, myContext.getContextNode(), xctxt.getNamespaceContext());
} catch (TransformerException e) {
return new XNodeSet(xctxt.getDTMManager());
}
}
}
return null;
}
}
该代码依赖于 org.apache.xalan
和 org.apache.xpath
包中的几个 类。您可能无法通过依赖标准的 JAXP 解决方案来实现相同的目标,就像我最初的尝试一样。
我正在尝试在 Xalan 2.7.1 提供给扩展函数的上下文中计算 XPath 表达式。出于某种原因,这在 Xalan 中总是失败并出现内部异常。
注意:您需要在类路径中 xalan-j 才能 运行 这个。
package org.example;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import javax.xml.namespace.NamespaceContext;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.w3c.dom.traversal.NodeIterator;
import org.apache.xalan.extensions.ExpressionContext;
public class XalanExtension {
public static final String NS = "org:example:foo";
public static final String XSLT = "" +
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<xsl:stylesheet \n" +
" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n" +
" xmlns:foo=\"org:example:foo\"\n" +
" xmlns:fun=\"xalan://org.example.XalanExtension\"\n" +
" version=\"1.0\"> \n" +
" \n" +
" <xsl:template match=\"*|@*\">\n" +
" <xsl:apply-templates select=\"*|@*\"/>\n" +
" </xsl:template>\n" +
" \n" +
" <xsl:template match=\"foo:test\">\n" +
" <xsl:variable name=\"result\" select=\"fun:evaluate(.)\"/>\n" +
" <xsl:message>\n" +
" Test: <xsl:value-of select=\".\"/> Result: <xsl:value-of select=\"$result\"/>\n" +
" </xsl:message>\n" +
" </xsl:template>\n" +
" \n" +
"</xsl:stylesheet>";
public static final String XML = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<tests xmlns=\"org:example:foo\">\n" +
" <a>1</a>\n" +
" <b>2</b>\n" +
" <c>3</c>\n" +
" <test>../foo:a > 5</test>\n" +
"</tests>";
private TransformerFactory xalanTransFact;
public XalanExtension() {
xalanTransFact = new org.apache.xalan.processor.TransformerFactoryImpl();
}
public void transform() {
try {
StringWriter writer;
writer = new StringWriter();
System.out.println(org.apache.xalan.Version.getVersion());
Transformer transformer = xalanTransFact.newTransformer(new StreamSource(new StringReader(XSLT)));
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "text");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.transform(
new StreamSource(new StringReader(XML)),
new StreamResult(writer));
System.out.println(writer.toString());
} catch (TransformerConfigurationException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
XalanExtension instance = new XalanExtension();
instance.transform();
}
public static final NodeList evaluate(ExpressionContext ctx, NodeIterator nodes) {
// first node in document order
Node node = nodes.nextNode();
if (node != null && node.hasChildNodes()) {
try {
String xpathExpression = node.getFirstChild().getNodeValue();
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if ("foo".equals(prefix)) {
return NS;
}
return null;
}
@Override
public String getPrefix(String namespaceURI) {
if (NS.equals(namespaceURI)) {
return "foo";
}
return null;
}
@Override
public Iterator getPrefixes(String namespaceURI) {
return null;
}
});
return (NodeList) xpath.evaluate(xpathExpression, ctx.getContextNode(), XPathConstants.NODESET);
} catch (XPathExpressionException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, "xpath evaluation failed", ex);
}
}
return null;
}
}
扩展功能在org.example.XalanExtension.evaluate(ExpressionContext, NodeIterator)
实现。它确实被 Xalan 调用,但是我正在使用的 XPath 评估代码不起作用。该程序只是找到一个具有众所周知值的特定元素,该元素实际上是一个 XPath 表达式,要在它出现的上下文中进行计算。
我从程序中得到以下输出:
Xalan Java 2.7.1
jan. 31, 2017 3:09:10 PM org.example.XalanExtension evaluate
SEVERE: xpath evaluation failed
javax.xml.transform.TransformerException: Unknown error in XPath.
at org.apache.xpath.XPath.execute(XPath.java:365)
at org.apache.xpath.XPath.execute(XPath.java:303)
at org.apache.xpath.jaxp.XPathImpl.eval(XPathImpl.java:216)
at org.apache.xpath.jaxp.XPathImpl.evaluate(XPathImpl.java:281)
at org.example.XalanExtension.evaluate(XalanExtension.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:367)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:440)
at org.apache.xalan.extensions.ExtensionsTable.extFunction(ExtensionsTable.java:222)
at org.apache.xalan.transformer.TransformerImpl.extFunction(TransformerImpl.java:473)
at org.apache.xpath.functions.FuncExtFunction.execute(FuncExtFunction.java:208)
at org.apache.xpath.XPath.execute(XPath.java:337)
at org.apache.xalan.templates.ElemVariable.getValue(ElemVariable.java:280)
at org.apache.xalan.templates.ElemVariable.execute(ElemVariable.java:248)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2400)
at org.apache.xalan.transformer.TransformerImpl.applyTemplateToNode(TransformerImpl.java:2270)
at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1356)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:709)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1273)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1251)
at org.example.XalanExtension.transform(XalanExtension.java:67)
at org.example.XalanExtension.main(XalanExtension.java:81)
Caused by: java.lang.NullPointerException
at org.apache.xpath.axes.AxesWalker.setRoot(AxesWalker.java:221)
at org.apache.xpath.axes.ReverseAxesWalker.setRoot(ReverseAxesWalker.java:53)
at org.apache.xpath.axes.WalkingIterator.setRoot(WalkingIterator.java:157)
at org.apache.xpath.axes.NodeSequence.setRoot(NodeSequence.java:265)
at org.apache.xpath.axes.LocPathIterator.execute(LocPathIterator.java:212)
at org.apache.xpath.Expression.execute(Expression.java:155)
at org.apache.xpath.operations.Operation.execute(Operation.java:109)
at org.apache.xpath.XPath.execute(XPath.java:337)
... 28 more
---------
java.lang.NullPointerException
at org.apache.xpath.axes.AxesWalker.setRoot(AxesWalker.java:221)
at org.apache.xpath.axes.ReverseAxesWalker.setRoot(ReverseAxesWalker.java:53)
at org.apache.xpath.axes.WalkingIterator.setRoot(WalkingIterator.java:157)
at org.apache.xpath.axes.NodeSequence.setRoot(NodeSequence.java:265)
at org.apache.xpath.axes.LocPathIterator.execute(LocPathIterator.java:212)
at org.apache.xpath.Expression.execute(Expression.java:155)
at org.apache.xpath.operations.Operation.execute(Operation.java:109)
at org.apache.xpath.XPath.execute(XPath.java:337)
at org.apache.xpath.XPath.execute(XPath.java:303)
at org.apache.xpath.jaxp.XPathImpl.eval(XPathImpl.java:216)
at org.apache.xpath.jaxp.XPathImpl.evaluate(XPathImpl.java:281)
at org.example.XalanExtension.evaluate(XalanExtension.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:367)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:440)
at org.apache.xalan.extensions.ExtensionsTable.extFunction(ExtensionsTable.java:222)
at org.apache.xalan.transformer.TransformerImpl.extFunction(TransformerImpl.java:473)
at org.apache.xpath.functions.FuncExtFunction.execute(FuncExtFunction.java:208)
at org.apache.xpath.XPath.execute(XPath.java:337)
at org.apache.xalan.templates.ElemVariable.getValue(ElemVariable.java:280)
at org.apache.xalan.templates.ElemVariable.execute(ElemVariable.java:248)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2400)
at org.apache.xalan.transformer.TransformerImpl.applyTemplateToNode(TransformerImpl.java:2270)
at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1356)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:709)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1273)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1251)
at org.example.XalanExtension.transform(XalanExtension.java:67)
at org.example.XalanExtension.main(XalanExtension.java:81)
--------------- linked to ------------------
javax.xml.xpath.XPathExpressionException: javax.xml.transform.TransformerException: Unknown error in XPath.
at org.apache.xpath.jaxp.XPathImpl.evaluate(XPathImpl.java:295)
at org.example.XalanExtension.evaluate(XalanExtension.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:367)
at org.apache.xalan.extensions.ExtensionHandlerJavaClass.callFunction(ExtensionHandlerJavaClass.java:440)
at org.apache.xalan.extensions.ExtensionsTable.extFunction(ExtensionsTable.java:222)
at org.apache.xalan.transformer.TransformerImpl.extFunction(TransformerImpl.java:473)
at org.apache.xpath.functions.FuncExtFunction.execute(FuncExtFunction.java:208)
at org.apache.xpath.XPath.execute(XPath.java:337)
at org.apache.xalan.templates.ElemVariable.getValue(ElemVariable.java:280)
at org.apache.xalan.templates.ElemVariable.execute(ElemVariable.java:248)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:395)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:178)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2400)
at org.apache.xalan.transformer.TransformerImpl.applyTemplateToNode(TransformerImpl.java:2270)
at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1356)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:709)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1273)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1251)
at org.example.XalanExtension.transform(XalanExtension.java:67)
at org.example.XalanExtension.main(XalanExtension.java:81)
Caused by: javax.xml.transform.TransformerException: Unknown error in XPath.
at org.apache.xpath.XPath.execute(XPath.java:365)
at org.apache.xpath.XPath.execute(XPath.java:303)
at org.apache.xpath.jaxp.XPathImpl.eval(XPathImpl.java:216)
at org.apache.xpath.jaxp.XPathImpl.evaluate(XPathImpl.java:281)
... 25 more
Caused by: java.lang.NullPointerException
at org.apache.xpath.axes.AxesWalker.setRoot(AxesWalker.java:221)
at org.apache.xpath.axes.ReverseAxesWalker.setRoot(ReverseAxesWalker.java:53)
at org.apache.xpath.axes.WalkingIterator.setRoot(WalkingIterator.java:157)
at org.apache.xpath.axes.NodeSequence.setRoot(NodeSequence.java:265)
at org.apache.xpath.axes.LocPathIterator.execute(LocPathIterator.java:212)
at org.apache.xpath.Expression.execute(Expression.java:155)
at org.apache.xpath.operations.Operation.execute(Operation.java:109)
at org.apache.xpath.XPath.execute(XPath.java:337)
... 28 more
SystemId Unknown; Line #14; Column #22;
Test: ../foo:a > 5 Result:
如何在 Xalan 扩展函数实现中(在提供给它的上下文中)评估 XPath 表达式?我没有正确初始化 XPathFactory
/XPath instance
吗?
这是上面代码中的两个文档:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:foo="org:example:foo"
xmlns:fun="xalan://org.example.XalanExtension"
version="1.0">
<xsl:template match="*|@*">
<xsl:apply-templates select="*|@*"/>
</xsl:template>
<xsl:template match="foo:test">
<xsl:variable name="result" select="fun:evaluate(.)"/>
<xsl:message>
Test: <xsl:value-of select="."/> Result: <xsl:value-of select="$result"/>
</xsl:message>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<tests xmlns="org:example:foo">
<a>1</a>
<b>2</b>
<c>3</c>
<test>../foo:a > 5</test>
</tests>
注意:我很了解 dyn:evaluate
功能。本题与此无关
我问得太快了。在查看了一些 Xalan 扩展函数的实现方式后,我找到了实现 XPath 求值的 Xalan 特定代码(是的,对于 dyn:evaluate
)。
package org.example;
import java.io.*;
import java.util.logging.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
import org.w3c.dom.traversal.NodeIterator;
import org.apache.xalan.extensions.ExpressionContext;
import org.apache.xpath.XPathContext;
import org.apache.xpath.objects.XNodeSet;
public class XalanExtension {
public static final String NS = "org:example:foo";
public static final String XSLT = "" +
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<xsl:stylesheet \n" +
" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n" +
" xmlns:foo=\"org:example:foo\"\n" +
" xmlns:fun=\"xalan://org.example.XalanExtension\"\n" +
" version=\"1.0\"> \n" +
" \n" +
" <xsl:template match=\"*|@*\">\n" +
" <xsl:apply-templates select=\"*|@*\"/>\n" +
" </xsl:template>\n" +
" \n" +
" <xsl:template match=\"foo:test\">\n" +
" <xsl:variable name=\"result\" select=\"fun:evaluate(.)\"/>\n" +
" <xsl:message>\n" +
" Test: <xsl:value-of select=\".\"/> Result: <xsl:value-of select=\"$result\"/>\n" +
" </xsl:message>\n" +
" </xsl:template>\n" +
" \n" +
"</xsl:stylesheet>";
public static final String XML = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<tests xmlns=\"org:example:foo\">\n" +
" <a>1</a>\n" +
" <b>2</b>\n" +
" <c>3</c>\n" +
" <test>../foo:a > 5</test>\n" +
"</tests>";
private TransformerFactory xalanTransFact;
public XalanExtension() {
xalanTransFact = new org.apache.xalan.processor.TransformerFactoryImpl();
}
public void transform() {
try {
StringWriter writer;
writer = new StringWriter();
System.out.println(org.apache.xalan.Version.getVersion());
Transformer transformer = xalanTransFact.newTransformer(new StreamSource(new StringReader(XSLT)));
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "text");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.transform(
new StreamSource(new StringReader(XML)),
new StreamResult(writer));
System.out.println(writer.toString());
} catch (TransformerConfigurationException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerException ex) {
Logger.getLogger(XalanExtension.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
XalanExtension instance = new XalanExtension();
instance.transform();
}
public static final Object evaluate(ExpressionContext myContext, NodeIterator nodes) {
if (myContext instanceof XPathContext.XPathExpressionContext) {
XPathContext xctxt = null;
Node node = nodes.nextNode();
if (node != null && node.hasChildNodes()) {
String xpathExpr = node.getFirstChild().getNodeValue();
try {
xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
org.apache.xpath.XPath dynamicXPath = new org.apache.xpath.XPath(xpathExpr, xctxt.getSAXLocator(),
xctxt.getNamespaceContext(),
org.apache.xpath.XPath.SELECT);
return dynamicXPath.execute(xctxt, myContext.getContextNode(), xctxt.getNamespaceContext());
} catch (TransformerException e) {
return new XNodeSet(xctxt.getDTMManager());
}
}
}
return null;
}
}
该代码依赖于 org.apache.xalan
和 org.apache.xpath
包中的几个 类。您可能无法通过依赖标准的 JAXP 解决方案来实现相同的目标,就像我最初的尝试一样。