如何使用 Apache Camel 在 XSLT 中为每个组申请

Posted

技术标签:

【中文标题】如何使用 Apache Camel 在 XSLT 中为每个组申请【英文标题】:How to apply for-each-group in XSLT with Apache Camel 【发布时间】:2021-12-02 01:14:33 【问题描述】:

我正在尝试在 Apache Camel XSLT 中使用 group by,但是当使用带有 sytlesheet 版本 2.0 的 for-each-group 时出现异常“javax.xml.transform.TransformerException:xsl 上不允许使用“select”属性:为每个组元素!”。 下面是我更新的代码。

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:template match="/">
        <MESSAGES>
            <xsl:for-each-group
                select="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent"
                group-by="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId">
                <COMMANDSTATUS>
                    <xsl:attribute name="ID">SHIPPED</xsl:attribute>
                    <xsl:attribute name="DESCRIPTION">Goods Shipped</xsl:attribute>
                    <ORDER>
                        <xsl:attribute name="O_ID"><xsl:value-of
                            select='distinct-values(/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId)' /></xsl:attribute>
                        <xsl:choose>
                        <xsl:when
                            test="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderSource = 'STORE-ORDER'">
                            <xsl:attribute name="TRACKING_URL">https://www.fedex.com/apps/fedextrack/?tracknumbers=<xsl:value-of
                                select='distinct-values(/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderShipmentDetails/OrderShipmentDetail/ShippingTrackingNumber)' /></xsl:attribute>
                        </xsl:when>
                        <xsl:when
                            test="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderSource != 'STORE-ORDER'">
                            <xsl:attribute name="TRACKING_URL">http://wwwapps.<xsl:value-of
                                select='distinct-values(/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderShipmentDetails/OrderShipmentDetail/ShippingCarrier)' />.com/WebTracking/track?track=yes&amp;trackNums=<xsl:value-of
                                select='distinct-values(/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderShipmentDetails/OrderShipmentDetail/ShippingTrackingNumber)' /></xsl:attribute>
                        </xsl:when>
                        </xsl:choose>
                        <xsl:for-each
                            select="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent">
                            <ORDER_LINE>
                                <xsl:attribute name="OL_ID"><xsl:value-of
                                    select='OrderLineId' /></xsl:attribute>
                                <xsl:choose>
                                    <xsl:when test="substring(ItemId, 0, 6) = '88-00'">
                                        <xsl:attribute name="SKU"><xsl:value-of
                                            select='substring(ItemId, 6)' /></xsl:attribute>
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <xsl:attribute name="SKU"><xsl:value-of
                                            select='ItemId' /></xsl:attribute>
                                    </xsl:otherwise>
                                </xsl:choose>
                                <xsl:attribute name="QUANTITY"><xsl:value-of
                                    select='distinct-values(/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderStatusDetails/OrderStatusDetail/Qty)' /></xsl:attribute>
                            </ORDER_LINE>
                        </xsl:for-each>
                    </ORDER>
                </COMMANDSTATUS>
            </xsl:for-each-group>
        </MESSAGES>
    </xsl:template>
</xsl:stylesheet>

输入 XML:

<?xml version="1.0" encoding="utf-8"?>
<OrderStatusUpdate fileType="Order Status Update" fileStartTime="2021-10-13 06:20:18 " fileEndTime=" 2021-10-13 07:35:26">
    <MessageHeader>
        <Standard>eBay_Enterprise</Standard>
        <HeaderVersion>EWS_eb2c_1.1</HeaderVersion>
        <VersionReleaseNumber>EWS_eb2c_1.1</VersionReleaseNumber>
        <SourceData>
            <SourceId>OMS</SourceId>
            <SourceType>OrderManagementSystem</SourceType>
        </SourceData>
        <DestinationData>
            <DestinationId>EE_OrderRTStatusXML</DestinationId>
            <DestinationType>MAILBOX</DestinationType>
        </DestinationData>
        <EventType>OrderStatus</EventType>
        <MessageData>
            <MessageId>20211013073625</MessageId>
            <CorrelationId>0</CorrelationId>
        </MessageData>
        <CreateDateAndTime>2021-10-13 07:36:25</CreateDateAndTime>
    </MessageHeader>
    <OrderStatusEvents>
        <OrderStatusEvent>
            <StoreCode>R21_US</StoreCode>
            <OrderId>101425120920</OrderId>
            <ExternalOrderId/>
            <WebOrderId>002010003694706_1</WebOrderId>
            <OrderSource type=""/>
            <OrderLineId>1</OrderLineId>
            <OriginalOrderId/>
            <OriginalWebOrderId/>
            <OriginalOrderLineId/>
            <ItemId>88-0028547859</ItemId>
            <OrderStatusDetails>
                <OrderStatusDetail>
                    <OrderStatusEventTimeStamp>2021-10-13 07:20:23</OrderStatusEventTimeStamp>
                    <StatusName>Fulfilled and Invoiced</StatusName>
                    <ReturnReason/>
                    <Qty>1</Qty>
                    <CancelReason/>
                    <CancelReasonText/>
                </OrderStatusDetail>
            </OrderStatusDetails>
            <OrderShipmentDetails>
                <OrderShipmentDetail>
                    <ShippingCarrier>UPS</ShippingCarrier>
                    <ShippingServiceLevel>PBX01</ShippingServiceLevel>
                    <ShippingTrackingNumber>1ZEW3567YW46706215</ShippingTrackingNumber>
                    <ShippingTimestamp>2021-10-13 07:12:00</ShippingTimestamp>
                </OrderShipmentDetail>
            </OrderShipmentDetails>
        </OrderStatusEvent>
        <OrderStatusEvent>
            <StoreCode>R21_US</StoreCode>
            <OrderId>101425120920</OrderId>
            <ExternalOrderId/>
            <WebOrderId>002010003694706_1</WebOrderId>
            <OrderSource type=""/>
            <OrderLineId>3</OrderLineId>
            <OriginalOrderId/>
            <OriginalWebOrderId/>
            <OriginalOrderLineId/>
            <ItemId>88-0028461473</ItemId>
            <OrderStatusDetails>
                <OrderStatusDetail>
                    <OrderStatusEventTimeStamp>2021-10-13 07:20:23</OrderStatusEventTimeStamp>
                    <StatusName>Fulfilled and Invoiced</StatusName>
                    <ReturnReason/>
                    <Qty>1</Qty>
                    <CancelReason/>
                    <CancelReasonText/>
                </OrderStatusDetail>
            </OrderStatusDetails>
            <OrderShipmentDetails>
                <OrderShipmentDetail>
                    <ShippingCarrier>UPS</ShippingCarrier>
                    <ShippingServiceLevel>PBX01</ShippingServiceLevel>
                    <ShippingTrackingNumber>1ZEW3567YW46706215</ShippingTrackingNumber>
                    <ShippingTimestamp>2021-10-13 07:12:00</ShippingTimestamp>
                </OrderShipmentDetail>
            </OrderShipmentDetails>
        </OrderStatusEvent>
        <OrderStatusEvent>
            <StoreCode>R21_US</StoreCode>
            <OrderId>101425254810</OrderId>
            <ExternalOrderId/>
            <WebOrderId>002010003698153_1</WebOrderId>
            <OrderSource type=""/>
            <OrderLineId>1</OrderLineId>
            <OriginalOrderId/>
            <OriginalWebOrderId/>
            <OriginalOrderLineId/>
            <ItemId>88-0028353647</ItemId>
            <OrderStatusDetails>
                <OrderStatusDetail>
                    <OrderStatusEventTimeStamp>2021-10-13 06:40:15</OrderStatusEventTimeStamp>
                    <StatusName>Fulfilled and Invoiced</StatusName>
                    <ReturnReason/>
                    <Qty>1</Qty>
                    <CancelReason/>
                    <CancelReasonText/>
                </OrderStatusDetail>
            </OrderStatusDetails>
            <OrderShipmentDetails>
                <OrderShipmentDetail>
                    <ShippingCarrier>UPS</ShippingCarrier>
                    <ShippingServiceLevel>PBX03</ShippingServiceLevel>
                    <ShippingTrackingNumber>1ZEW3571YW13958113</ShippingTrackingNumber>
                    <ShippingTimestamp>2021-10-13 06:30:00</ShippingTimestamp>
                </OrderShipmentDetail>
            </OrderShipmentDetails>
        </OrderStatusEvent>
        <OrderStatusEvent>
            <StoreCode>R21_US</StoreCode>
            <OrderId>101425254810</OrderId>
            <ExternalOrderId/>
            <WebOrderId>002010003698153_1</WebOrderId>
            <OrderSource type=""/>
            <OrderLineId>2</OrderLineId>
            <OriginalOrderId/>
            <OriginalWebOrderId/>
            <OriginalOrderLineId/>
            <ItemId>88-0028635431</ItemId>
            <OrderStatusDetails>
                <OrderStatusDetail>
                    <OrderStatusEventTimeStamp>2021-10-13 06:40:15</OrderStatusEventTimeStamp>
                    <StatusName>Fulfilled and Invoiced</StatusName>
                    <ReturnReason/>
                    <Qty>1</Qty>
                    <CancelReason/>
                    <CancelReasonText/>
                </OrderStatusDetail>
            </OrderStatusDetails>
            <OrderShipmentDetails>
                <OrderShipmentDetail>
                    <ShippingCarrier>UPS</ShippingCarrier>
                    <ShippingServiceLevel>PBX03</ShippingServiceLevel>
                    <ShippingTrackingNumber>1ZEW3571YW13958113</ShippingTrackingNumber>
                    <ShippingTimestamp>2021-10-13 06:30:00</ShippingTimestamp>
                </OrderShipmentDetail>
            </OrderShipmentDetails>
        </OrderStatusEvent>
    </OrderStatusEvents>
</OrderStatusUpdate>

预期的 XML:

<?xml version='1.0' encoding='UTF-8'?>
<MESSAGES>
  <COMMANDSTATUS ID="SHIPPED" DESCRIPTION="Goods Shipped">
    <ORDER O_ID="002010003694706_1" TRACKING_URL="http://wwwapps.UPS.com/WebTracking/track?track=yes&amp;trackNums=1ZEW3567YW46706215">
      <ORDER_LINE OL_ID="1" SKU="28547859" QUANTITY="1"/>
      <ORDER_LINE OL_ID="3" SKU="28461473" QUANTITY="1"/>
    </ORDER>
  </COMMANDSTATUS>
  <COMMANDSTATUS ID="SHIPPED" DESCRIPTION="Goods Shipped">
    <ORDER O_ID="002010003698153_1" TRACKING_URL="http://wwwapps.UPS.com/WebTracking/track?track=yes&amp;trackNums=1ZEW3571YW13958113">
      <ORDER_LINE OL_ID="1" SKU="28353647" QUANTITY="1"/>
      <ORDER_LINE OL_ID="2" SKU="28635431" QUANTITY="1"/>
    </ORDER>
  </COMMANDSTATUS>
</MESSAGES>

我也尝试了1.0版本,但没有通过,下面是相同的代码。

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:key name="webOrderId"
        match="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent"
        use="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId" />
    <xsl:variable name="uppercase"
        select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
    <xsl:variable name="lowercase"
        select="'abcdefghijklmnopqrstuvwxyz'" />
    <xsl:template match="/">
        <MESSAGES>
            <xsl:for-each
                select="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent[count(. | key('webOrderId', /OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId)[1]) = 1]">
                <xsl:for-each select="key('webOrderId', /OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId)">
                    <COMMANDSTATUS>
                        <xsl:attribute name="ID">SHIPPED</xsl:attribute>
                        <xsl:attribute name="DESCRIPTION">Goods Shipped</xsl:attribute>
                        <ORDER>
                            <xsl:choose>
                                <xsl:when
                                    test="substring(/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId, 0, 6) = '00201'">
                                    <xsl:attribute name="O_ID"><xsl:value-of
                                        select='substring(/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId, 6)' /></xsl:attribute>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:attribute name="O_ID"><xsl:value-of
                                        select='/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId' /></xsl:attribute>
                                </xsl:otherwise>
                            </xsl:choose>
                            <xsl:choose>
                                <xsl:when
                                    test="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderSource = 'STORE-ORDER'">
                                    <xsl:attribute name="TRACKING_URL">https://www.fedex.com/apps/fedextrack/?tracknumbers=<xsl:value-of
                                        select='/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderShipmentDetails/OrderShipmentDetail/ShippingTrackingNumber' /></xsl:attribute>
                                </xsl:when>
                                <xsl:when
                                    test="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderSource != 'STORE-ORDER'">
                                    <xsl:attribute name="TRACKING_URL">http://wwwapps.<xsl:value-of
                                        select='/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderShipmentDetails/OrderShipmentDetail/ShippingCarrier' />.com/WebTracking/track?track=yes&amp;trackNums=<xsl:value-of
                                        select='/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderShipmentDetails/OrderShipmentDetail/ShippingTrackingNumber' /></xsl:attribute>
                                </xsl:when>
                            </xsl:choose>
                            <xsl:for-each
                                select="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent">
                                <ORDER_LINE>
                                    <xsl:attribute name="OL_ID"><xsl:value-of
                                        select='OrderLineId' /></xsl:attribute>
                                    <xsl:choose>
                                        <xsl:when test="substring(ItemId, 0, 6) = '88-00'">
                                            <xsl:attribute name="SKU"><xsl:value-of
                                                select='substring(ItemId, 6)' /></xsl:attribute>
                                        </xsl:when>
                                        <xsl:otherwise>
                                            <xsl:attribute name="SKU"><xsl:value-of
                                                select='ItemId' /></xsl:attribute>
                                        </xsl:otherwise>
                                    </xsl:choose>
                                    <xsl:attribute name="QUANTITY"><xsl:value-of
                                        select='/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderStatusDetails/OrderStatusDetail/Qty' /></xsl:attribute>
                                </ORDER_LINE>
                            </xsl:for-each>
                        </ORDER>
                    </COMMANDSTATUS>
                </xsl:for-each>
            </xsl:for-each>
        </MESSAGES>
    </xsl:template>
</xsl:stylesheet>

以下是使用上述代码收到的输出,这是预期之外的。

<?xml version="1.0" encoding="UTF-8"?>
<MESSAGES>
   <COMMANDSTATUS ID="SHIPPED" DESCRIPTION="Goods Shipped">
      <ORDER O_ID="002010003694706_1 002010003698153_1"
             TRACKING_URL="http://wwwapps.UPS.com/WebTracking/track?track=yes&amp;trackNums=1ZEW3567YW46706215 1ZEW3571YW13958113">
         <ORDER_LINE OL_ID="1" SKU="28547859" QUANTITY="1"/>
         <ORDER_LINE OL_ID="3" SKU="28461473" QUANTITY="1"/>
         <ORDER_LINE OL_ID="1" SKU="28353647" QUANTITY="1"/>
         <ORDER_LINE OL_ID="2" SKU="28635431" QUANTITY="1"/>
      </ORDER>
   </COMMANDSTATUS>
   <COMMANDSTATUS ID="SHIPPED" DESCRIPTION="Goods Shipped">
      <ORDER O_ID="002010003694706_1 002010003698153_1"
             TRACKING_URL="http://wwwapps.UPS.com/WebTracking/track?track=yes&amp;trackNums=1ZEW3567YW46706215 1ZEW3571YW13958113">
         <ORDER_LINE OL_ID="1" SKU="28547859" QUANTITY="1"/>
         <ORDER_LINE OL_ID="3" SKU="28461473" QUANTITY="1"/>
         <ORDER_LINE OL_ID="1" SKU="28353647" QUANTITY="1"/>
         <ORDER_LINE OL_ID="2" SKU="28635431" QUANTITY="1"/>
      </ORDER>
   </COMMANDSTATUS>
</MESSAGES>

【问题讨论】:

查看 Camel 中 XSLT 的配置,有一些方法可以选择 Saxon 9(或者最近可能是 10 种)进行 XSLT 2(或 3)处理。 【参考方案1】:

您没有显示如何调用 XSL 的路由代码,但我想它是使用标准 Java XSL 处理器(不支持 XSL 2)执行的。

您需要明确告诉 Camel 使用 Saxon 作为 XSL 处理器才能使用 XSL 2。

在 Camel 3.x 中有一个专用的 Saxon 组件

to("xslt-saxon:path/to/yourStylesheet.xsl");

在 Camel 2.x 中,这是通过 URL 选项完成的

.to("xslt:path/to/yourStylesheet.xsl?saxon=true")

当然,您还必须将 Saxon 添加为依赖项。

【讨论】:

感谢您的回复,此异常 'javax.xml.transform.TransformerException: "select" attribute is not allowed on the xsl:for-each-group element' 已解决,现在使用 xslt-撒克逊而不是 xslt。 但是我仍然无法从 XML 中获得预期的输出,已经更新了上面提供的 XSLT。让我知道如何实现这一目标? 您会得到错误的结果,因为您在 for-each-group 中遍历所有 OrderStatusEvent 并且不检查它们是否属于当前组。您应该问一个新问题,这是一个纯粹的 XPath 问题。如果您将内部 for-each 更改为 &lt;xsl:for-each select="current-group()[WebOrderId = current-grouping-key()]"&gt; 它应该可以工作。但你也应该删除所有这些绝对路径。 非常感谢,成功了【参考方案2】:

这是适用于我的用例的 XSLT 代码。

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:template match="/">
        <MESSAGES>
            <xsl:for-each-group
                select="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent"
                group-by="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/WebOrderId">
                <COMMANDSTATUS>
                    <xsl:attribute name="ID">SHIPPED</xsl:attribute>
                    <xsl:attribute name="DESCRIPTION">Goods Shipped</xsl:attribute>
                    <ORDER>
                        <xsl:choose>
                            <xsl:when
                                test="substring(current-grouping-key(), 0, 6) = '00201'">
                                <xsl:attribute name="O_ID"><xsl:value-of
                                    select='substring(current-grouping-key(), 6)' /></xsl:attribute>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:attribute name="O_ID"><xsl:value-of
                                    select='current-grouping-key()' /></xsl:attribute>
                            </xsl:otherwise>
                        </xsl:choose>
                        <xsl:for-each
                            select="current-group()[WebOrderId = current-grouping-key()]">
                            <xsl:choose>
                                <xsl:when
                                    test="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderSource = 'STORE-ORDER'">
                                    <xsl:attribute name="TRACKING_URL">https://www.fedex.com/apps/fedextrack/?tracknumbers=<xsl:value-of
                                        select='./OrderShipmentDetails/OrderShipmentDetail/ShippingTrackingNumber' /></xsl:attribute>
                                </xsl:when>
                                <xsl:when
                                    test="/OrderStatusUpdate/OrderStatusEvents/OrderStatusEvent/OrderSource != 'STORE-ORDER'">
                                    <xsl:attribute name="TRACKING_URL">http://wwwapps.<xsl:value-of
                                        select='./OrderShipmentDetails/OrderShipmentDetail/ShippingCarrier' />.com/WebTracking/track?track=yes&amp;trackNums=<xsl:value-of
                                        select='./OrderShipmentDetails/OrderShipmentDetail/ShippingTrackingNumber' /></xsl:attribute>
                                </xsl:when>
                            </xsl:choose>
                        </xsl:for-each>
                        <xsl:for-each
                            select="current-group()[WebOrderId = current-grouping-key()]">
                            <ORDER_LINE>
                                <xsl:attribute name="OL_ID"><xsl:value-of
                                    select='OrderLineId' /></xsl:attribute>
                                <xsl:choose>
                                    <xsl:when test="substring(ItemId, 0, 6) = '88-00'">
                                        <xsl:attribute name="SKU"><xsl:value-of
                                            select='substring(ItemId, 6)' /></xsl:attribute>
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <xsl:attribute name="SKU"><xsl:value-of
                                            select='ItemId' /></xsl:attribute>
                                    </xsl:otherwise>
                                </xsl:choose>
                                <xsl:attribute name="QUANTITY"><xsl:value-of
                                    select='./OrderStatusDetails/OrderStatusDetail/Qty' /></xsl:attribute>
                            </ORDER_LINE>
                        </xsl:for-each>
                    </ORDER>
                </COMMANDSTATUS>
            </xsl:for-each-group>
        </MESSAGES>
    </xsl:template>
</xsl:stylesheet>

谢谢!

【讨论】:

以上是关于如何使用 Apache Camel 在 XSLT 中为每个组申请的主要内容,如果未能解决你的问题,请参考以下文章

Camel XSLT 转换

Apache Camel:如何存储变量以供以后使用

如何使用 Apache Camel 从 Java 类访问 JMS 队列?

Apache Camel使用spring DSL比较字符串与引号,如何逃脱?

如何在apache camel中附加速度文件内容

如何使用 Apache Camel 来监控文件更改?