xslt:撒克逊 9.4 与撒克逊 9.6 中的消息

Posted

技术标签:

【中文标题】xslt:撒克逊 9.4 与撒克逊 9.6 中的消息【英文标题】:xslt:message in Saxon 9.4 vs Saxon 9.6 【发布时间】:2016-01-25 18:43:39 【问题描述】:

我正在尝试从 java 代码中抛出异常,该异常将在使用 Saxon 时包含来自 xsl:message 标记的消息。

使用下面的 xslt 文件

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:message terminate="yes">exception message</xsl:message>
    </xsl:template>
</xsl:stylesheet>

在 Saxon 9.4 上使用以下代码

public static void main(String[] args) throws TransformerException 
    try 
        TransformerFactory fact = new net.sf.saxon.TransformerFactoryImpl();
        Transformer newTransformer = fact.newTransformer(new StreamSource(new File("throw.xslt")));
        ((net.sf.saxon.Controller)newTransformer).setRecoveryPolicy(Configuration.DO_NOT_RECOVER);
        ((net.sf.saxon.Controller)newTransformer).setMessageEmitter(new MessageWarner());
        newTransformer.transform(new StreamSource(new File("input.xml")), new StreamResult(new File("output.xml")));
     catch (TransformerException e) 
        System.out.println("THIS IS EXCEPTION: " + e.getMessage() + " <<<");
        throw e;
    
   

它给出THIS IS EXCEPTION: exception message &lt;&lt;&lt;,这是我所期待的行为。

但在 Saxon 9.6 上,由于 API 更改,代码略有调整

public static void main(String[] args) throws TransformerException 
    try 
        TransformerFactory fact = new net.sf.saxon.TransformerFactoryImpl();
        Transformer newTransformer = fact.newTransformer(new StreamSource(new File("throw.xslt")));
        ((net.sf.saxon.jaxp.TransformerImpl)newTransformer).getUnderlyingController().setRecoveryPolicy(Configuration.DO_NOT_RECOVER);
        ((net.sf.saxon.jaxp.TransformerImpl)newTransformer).getUnderlyingController().setMessageEmitter(new MessageWarner());
        newTransformer.transform(new StreamSource(new File("input.xml")), new StreamResult(new File("output.xml")));
     catch (TransformerException e) 
        System.out.println("THIS IS EXCEPTION: " + e.getMessage() + " <<<");
        throw e;
    

它给出了THIS IS EXCEPTION: Processing terminated by xsl:message at line 4 in throw.xslt &lt;&lt;&lt;,而 xsl:message 在某处丢失了。

如何在“9.6”上实现“9.4”行为?

【问题讨论】:

【参考方案1】:

不幸的是,新的Processing terminated... 消息在 net.sf.saxon.expr.instruct.Message 中硬编码(9.6.0-7 中的 Message.java:253)。以下是一种解决方法,可能会满足您的需求:

public static void main(String[] args) throws TransformerException 
    final StringWriter messageOut = new StringWriter();
    try 
        TransformerFactory fact = new net.sf.saxon.TransformerFactoryImpl();
        Transformer newTransformer = fact.newTransformer(new StreamSource(new File("throw.xslt")));
        ((net.sf.saxon.jaxp.TransformerImpl)newTransformer).getUnderlyingController().setRecoveryPolicy(Configuration.DO_NOT_RECOVER);
        ((net.sf.saxon.jaxp.TransformerImpl)newTransformer).getUnderlyingController().setMessageEmitter(new MessageEmitter() 
                @Override
                public void open() throws XPathException 
                    setWriter(messageOut);
                    super.open();
                
        );

        newTransformer.transform(new StreamSource(new File("input.xml")), new StreamResult(new File("output.xml")));
     catch (TransformerException e) 
        System.out.println("THIS IS EXCEPTION: " + e.getMessage() + " <<<");
        String message = messageOut.toString(); // this is the "exception message\n" that you want
        // not sure why it has a \n on it
        System.out.println("THIS IS THE MESSAGE WE WANT: " + message);
        throw new TransformerException(message, e); // rethrow using the captured message, if you really want that "exception message" available to a caller in e.getMessage()
    

【讨论】:

【参考方案2】:

这是由于 MessageEmitter 正在向其发送消息的消息侦听器。在 saxon 9.6 中,默认侦听器正在实现 UnfailingErrorListener,它不能抛出异常(与 9.6 中的所有其他侦听器一样),但在 9.4 中,可以从侦听器中抛出异常。

但是,您可以实现自己的消息发射器,当遇到终止设置为 yes 的 xml:message 时会抛出异常,如下所示:

final class ExceptionThrowingMessageEmitter extends XMLEmitter 
  boolean abort = false;

  public void startDocument(int properties) throws XPathException 
    setWriter(new StringWriter());
    abort = (properties & ReceiverOptions.TERMINATE) != 0;
    super.startDocument(properties);
  

  public void endDocument() throws XPathException 
    XPathException de = new XPathException(getWriter().toString());
    de.setErrorCode("XTMM9000");
    if (abort) 
      throw de;
     else 
      //terminate set to no, do something like writing to the log file
    
  

  public void close() 
    // do nothing
  

然后,像这样注册它:

transformer.getUnderlyingController().setMessageEmitter(new ExceptionThrowingMessageEmitter());  

这样,当有终止 xml:message 时会抛出异常

【讨论】:

不知道有没有办法使用Emitter获取xsl:message行/列号?

以上是关于xslt:撒克逊 9.4 与撒克逊 9.6 中的消息的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 导入语句的撒克逊错误

在 python 中使用撒克逊语

如何在 Java 中选择撒克逊 TransformerFactory

如何区分空值字段与杰克逊库中的缺失字段

迈克尔·杰克逊介绍

迈克尔杰克逊的介绍?