【问题标题】:How to add XSL resource dynamically (programatically) in xslt-transformer?如何在 xslt-transformer 中动态(以编程方式)添加 XSL 资源?
【发布时间】:2016-05-17 07:42:51
【问题描述】:

我正在使用 spring 集成的 xslt-transfomer 进行 xml 转换。 我的代码如下所示,

<int-xml:xslt-transformer id="xmlTransformer" input-channel="inputChannel" 
        output-channel="outputChannel"  xsl-resource="classpath:META-INF/OrderXslt.xsl" />

这里我想在运行时动态传递 xsl-resource="classpath:META-INF/OrderXslt.xsl"。我能够从上下文中获取 xmlTransformer bean,但无法弄清楚如何将 xsl-resource 设置为它。我的java代码是这样的,

File myFile = new File("D:\OrderXslt.xsl");
EventDrivenConsumer transformerConsumer =  (EventDrivenConsumer) ctx.getBean("xmlTransformer");

//I need to pass myFile to transformerConsumer instace.
//However I am unable to find any API of EventDrivenConsumer 
            which will accept xsl resource form here (i.e. myFile )

任何程序化的解释都将受到高度赞赏。 提前致谢。

编辑

    public class TempTransformer<Object, Obejct> extends AbstractTransformer  {

    private volatile XsltPayloadTransformer xslt;

    protected Object doTransform(Message<?> message) throws Exception {
        return (Object) findorBuildTransformerForMessage(message).transform(message); 
//Its throwing error here as
//org.springframework.integration.transformer.MessageTransformationException: failed to transform message; nested exception is java.lang.NullPointerException
    }

    private Transformer findorBuildTransformerForMessage(Message<?> message{
    xslt = new XsltPayloadTransformer(new ClassPathResource("/META-INF/OrderXslt2.xsl"));
    return xslt;
    }

编辑

我已经通过以下方式实现了XsltPayloadTransformer

protected Message<?> doTransform(Message<?> message) throws Exception {
    xsltTransformer = new XsltPayloadTransformer(new ClassPathResource("D:/sample.xsl"));

    this.xsltTransformer.setResultType("StringResult");
    this.xsltTransformer.afterPropertiesSet();
    return this.xsltTransformer.transform(message);

    }

但是我没有得到正确的输出。另一方面,我有一个简单的 java 程序,它使用 Saxon 实现并显示正确的输出。在这里……

 public static void main(String [] arr) {

    TransformerFactory tFactory = TransformerFactory.newInstance();
    StreamSource xmlInputFile = new StreamSource("D:/input.xml");
    StreamSource xslTransformationFile = new StreamSource("D:/sample.xsl");
    StreamResult xmlOutputFile = new StreamResult(new File("D:/output.xml"));
    Transformer transformer;
    try {
        transformer = tFactory.newTransformer(xslTransformationFile);  //gives instance of net.sf.saxon.jaxp.TransformerImpl 
        transformer.transform(xmlInputFile, xmlOutputFile);
    } 
    } catch (Exception e) {

    }

    }

我无法弄清楚我错过了什么。还有什么我需要设置为XsltPayloadTransformer的吗?或者我错过了什么? 我正在使用 XSL v2spring 4.1.7spring integration 4.1.8 版本。

【问题讨论】:

    标签: xml spring xslt spring-integration


    【解决方案1】:

    涉及 3 个类,EventDrivenConsumerMessageTransformingHandler(消费者的属性handler)和XsltPayloadTransformer - 处理程序的transformer 属性。

    XsltPayloadTransformer 目前没有用于更改资源的 API,它在构造函数参数中提供,因此您必须创建一个新的。

    MessageTransformingHandler 没有用于更改转换器的 API - 它是最终的和构造函数 arg。所以你必须创建一个新的。

    EventDrivenTransformer 没有用于更改处理程序的 API,它是 final 和构造函数 arg。

    因此,底线是您无法使用标准的开箱即用消费者做您想做的事情。

    但是,您可以创建自己的 bean,将其委托给 XsltPayloadTransformer,您可以根据需要将其替换为新的。请确保如果您以编程方式创建 XsltPayloadTransformer,则必须调用 afterPropertiesSet(),因为这是设置完成的地方。

    API for the EventDrivenConsumer is here,但由于上述原因,它对您没有帮助。

    您还可以使用Templates 选项并编写自己的包装器来动态更改资源。

    编辑

    <int:transformer ... ref="myTransformer" />
    
    public class Foo<Object, Object> extends AbstractTransformer<T, U> {
    
        private final ConcurrentMap<String, Transformer> xslts = new ConcurrentHashMap<>();
    
        protected Object doTransform(Message<?> message) throws Exception {
    
            return findorBuildTransformerForMessage(message).transform(message);
        }
    
        private Transformer findorBuildTransformerForMessage(Message<?> message) {
            // retrieve from map or create and add it to map
        }
    }
    

    【讨论】:

    • @GarryRussell 感谢您的解释,但我仍然对 XsltPayloadTransformer 的委托感到困惑,我应该如何将其替换为新的。
    • 以我的编辑为例,但我想我会使用模板方法。
    • @Garry 我需要一种线程安全的方法。使用 Transformer 注释怎么样是线程安全的,我可以使用该实现吗? (请查看最新编辑)
    • 您应该编辑您的问题,而不是我的答案,但是,不,添加 @Transformer 不会使其成为线程安全的,只有一个转换器实例。您需要维护一个Map&lt;String, XsltPayloadTransformer&gt;(可能是一个并发哈希映射),并且如果具有所需资源的转换器不在映射中,请创建一个并添加它 - 这样它将出现在下一条需要的消息中使用该资源。
    • @Garry 我试图实现您的解决方案,但找不到您指定的 API,即xslt.transformPayload(payload); 是的,还有另一个 API xslt.transform(Message&lt;?&gt;),但它也不起作用。我正在使用 4.1.8 版本的 Spring Integration
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    相关资源
    最近更新 更多