使用 xslt 聚合 [英] Aggregate with xslt

查看:19
本文介绍了使用 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天全站免登陆