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

How to apply for-each-group in XSLT with Apache Camel

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

<?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>

您没有显示您的路由代码如何调用 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")

当然你也必须添加撒克逊作为依赖。

这是适用于我的用例的 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>

谢谢!