用xslt聚合 [英] Aggregate with xslt

查看:51
本文介绍了用xslt聚合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从数据库中获取数据后汇总消息.似乎很难向我解释一下.

I am trying to aggregate message after getting data from database. It seems to be hard to explain to I will draw a flow firstly.

[ORIGINAL_DOCUMENT] --> SPLIT[GET SOME IDs from ORIGINAL_DOCUMENT] --> [GET DATA FROM DATABASE USING MYBATIS] --> [ENRICH ORIGINAL_DOCUMENT BY GOT DATA FROM DATABASE]

第一条路线:

 <route id="enrich-zamowienie">
        <from uri="activemq:queue:original-document"/>

        <setHeader headerName="pure-xml">
            <simple>${body}</simple>
        </setHeader>

        <split>
            <xpath>original-document/entry</xpath>

            <unmarshal>
                <jaxb contextPath="com.original-document"/>
            </unmarshal>

            <setBody>
                <simple>${body.getEntryId()}</simple>
            </setBody>

            <to uri="activemq:queue:getAdditionalsByID" />

            <marshal>
                <jaxb contextPath="com.additionals"
                      encoding="utf-8" prettyPrint="true"/>
            </marshal>

            <setHeader headerName="entry">
                <simple>${body}</simple>
            </setHeader>

            <setBody>
                <simple>${header.pure-xml}</simple>
            </setBody>

            <to uri="direct:aggregate" />
        </split>
    </route>

第二条路线:

    <route>
        <from uri="direct:aggregate" />

        <aggregate strategyRef="aggregator">
            <correlationExpression>
                <xpath>?</xpath>
            </correlationExpression>
        </aggregate>

        <log message="${body}" />
    </route>

    (...)
    <bean id="aggregator" class="org.apache.camel.util.toolbox.XsltAggregationStrategy">
    <constructor-arg value="com/transformXSLT.xsl" />

我从actimvemq得到的原始xml:

my original xml that I get fromy actimvemq:

<document>
    <header>
        <header_id>1</header_id>
    </header>
    <body>
        <entry>
            <entryId>1</entryId>
            <fieldToEnrich1></fieldToEnrich1>
            <fieldToEnrich2></fieldToEnrich2>
            <fieldToEnrich3></fieldToEnrich3>
        </entry>
        <entry>
            <entryId>2</entryId>
            <fieldToEnrich1></fieldToEnrich1>
            <fieldToEnrich2></fieldToEnrich2>
            <fieldToEnrich3></fieldToEnrich3>
        </entry>
        <entry>
            <entryId>3</entryId>
            <fieldToEnrich1></fieldToEnrich1>
            <fieldToEnrich2></fieldToEnrich2>
            <fieldToEnrich3></fieldToEnrich3>
        </entry>
    </body>
</document>

当然,对于每个id附加项,它看起来都像这样:

And of coure for every id addtional looks like it:

<document>
    <additionals>
        <fieldToEnrich1>131</fieldToEnrich1>
        <fieldToEnrich2>3232</fieldToEnrich2>
        <fieldToEnrich3>3213</fieldToEnrich3>
    </additionals>
</document>

我的目标是通过使用数据库中的额外数据来创建类似于original_document的文档.我不知道第二条路线应该看起来如何.我希望这是可以理解的.

My aim is to create document like original_document by with extra data from database. I don't know how to second route should looks. I hope it is understandable.

推荐答案

@pcoates具有使用XsltAggregationStrategy的好主意.因此,我使用xslt模板和经过修改的策略为您制作了工作示例. 路线:

@pcoates have good idea to use XsltAggregationStrategy. So i make working example for you with xslt templates and modified strategy. Route:

        XsltAggregationStrategy aggregationStrategy = new CustomXsltAggregationStrategy("xslt/aggregate.xsl");
    from("timer://foo?period=30s")
            .setBody(constant("<document>\n" +
                    "    <header>\n" +
                    "        <header_id>1</header_id>\n" +
                    "    </header>\n" +
                    "    <body>\n" +
                    "        <entry>\n" +
                    "            <entryId>1</entryId>\n" +
                    "            <fieldToEnrich1></fieldToEnrich1>\n" +
                    "            <fieldToEnrich2></fieldToEnrich2>\n" +
                    "            <fieldToEnrich3></fieldToEnrich3>\n" +
                    "        </entry>\n" +
                    "        <entry>\n" +
                    "            <entryId>2</entryId>\n" +
                    "            <fieldToEnrich1></fieldToEnrich1>\n" +
                    "            <fieldToEnrich2></fieldToEnrich2>\n" +
                    "            <fieldToEnrich3></fieldToEnrich3>\n" +
                    "        </entry>\n" +
                    "        <entry>\n" +
                    "            <entryId>3</entryId>\n" +
                    "            <fieldToEnrich1></fieldToEnrich1>\n" +
                    "            <fieldToEnrich2></fieldToEnrich2>\n" +
                    "            <fieldToEnrich3></fieldToEnrich3>\n" +
                    "        </entry>\n" +
                    "    </body>\n" +
                    "</document>"))
            .convertBodyTo(Document.class)
            .setProperty("updated-xml", simple("body"))
            .split().xpath("//entry").aggregationStrategy(aggregationStrategy)
            .setHeader("key", xpath("//entryId/text()", String.class))
            .setProperty("update-node", simple("body"))
        // <to uri="activemq:queue:getAdditionalsByID" />
            // like you receive your data
            .process(exchange -> {
                String data = "enrich data for key:"+exchange.getIn().getHeader("key");
                exchange.getIn().setBody(String.format("<document><additionals><fieldToEnrich1>%s</fieldToEnrich1><fieldToEnrich2>%s</fieldToEnrich2><fieldToEnrich3>%s</fieldToEnrich3></additionals></document>",
                        data,data,data));
            })
            .convertBodyTo(Document.class)
            .setProperty("additional", simple("body"))
            .setBody(exchangeProperty("update-node"))
            .to("xslt:xslt/updateNode.xsl")//create modified node
            .end()
            .convertBodyTo(String.class)
            .log(LoggingLevel.INFO, "Body:${body}");

updateNode.xsl:

updateNode.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8"/>
<xsl:strip-space elements='*'/>

<xsl:param name="additional"/>

<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="entry">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()[name()='entryId']"/>
        <xsl:apply-templates select="$additional/document/additionals/*"/>
    </xsl:copy>
</xsl:template>

aggregate.xsl:

aggregate.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:exslt="http://exslt.org/common"
            exclude-result-prefixes="exslt">
<xsl:output method="xml" version="1.0" encoding="UTF-8"/>
<xsl:strip-space elements='*'/>

<xsl:param name="new-exchange"/>

<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="//entry">
        <xsl:choose>
            <xsl:when test="./entryId/text()=$new-exchange/entry/entryId/text()">
                <xsl:copy-of select="$new-exchange"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
</xsl:template>

CustomXsltAggregationStrategy类:

CustomXsltAggregationStrategy class :

public class CustomXsltAggregationStrategy extends XsltAggregationStrategy {
/**
 * Constructor.
 *
 * @param xslFileLocation location of the XSL transformation
 */
public CustomXsltAggregationStrategy(String xslFileLocation) {
    super(xslFileLocation);
}

@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
    //by default result body of first split iteration become document that will be transformed by another iterations
    //but we need original document to be transformable, so we make pseudo first body and setting there our original document
    //others iteration will change only our document
    if (oldExchange == null) {
        oldExchange = newExchange.copy();
        oldExchange.getIn().setBody(oldExchange.getProperty("updated-xml"));
    }

    return super.aggregate(oldExchange, newExchange);
}

输出:

2018-12-13 14:32:24,643 | INFO  | 62 - timer://foo | route82                          | 98 - org.apache.camel.camel-core - 2.16.3 | Body:<?xml version="1.0" encoding="UTF-8"?><document><header><header_id>1</header_id></header><body><entry><entryId>1</entryId><fieldToEnrich1>enrich data for key:1</fieldToEnrich1><fieldToEnrich2>enrich data for key:1</fieldToEnrich2><fieldToEnrich3>enrich data for key:1</fieldToEnrich3></entry><entry><entryId>2</entryId><fieldToEnrich1>enrich data for key:2</fieldToEnrich1><fieldToEnrich2>enrich data for key:2</fieldToEnrich2><fieldToEnrich3>enrich data for key:2</fieldToEnrich3></entry><entry><entryId>3</entryId><fieldToEnrich1>enrich data for key:3</fieldToEnrich1><fieldToEnrich2>enrich data for key:3</fieldToEnrich2><fieldToEnrich3>enrich data for key:3</fieldToEnrich3></entry></body></document>

还有一点建议,如果您需要保存临时正文或一些计算数据,请使用属性代替标头,因为标头可以由端点处理.

And a little advice, if you need to save temporary body or some computed data, use properties instead of headers, cause headers can be processed by endpoints.

这篇关于用xslt聚合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆