2017-01-31 43 views
0

我正在嘗試評估由Xalan 2.7.1提供給擴展函數的上下文中的XPath表達式。出於某種原因,這總是會因Xalan中的內部異常而失敗。如何評估Xalan擴展函數實現中的XPath表達式?

注意:您需要在類路徑中使用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 &gt; 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的擴展功能implmentation內的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 &gt; 5</test> 
</tests> 

注:我很清楚dyn:evaluate功能。這個問題與它無關。

+0

所以你試圖評估一個布爾表達式'../foo:a > 5',但想要返回一個節點集/ NodeList?這是否在擴展函數環境之外工作? –

+0

@MartinHonnen,是的。它應該返回任何對象。請注意,這個錯誤不是問題。 – predi

回答

0

我太快問這個問題。在看看一些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 &gt; 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.xalanorg.apache.xpath包。依靠標準的JAXP解決方案,您可能無法實現這一點,就像我最初的嘗試一樣。