如何使用 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&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&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&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&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&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&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 更改为 <xsl:for-each select="current-group()[WebOrderId = current-grouping-key()]">
它应该可以工作。但你也应该删除所有这些绝对路径。
非常感谢,成功了【参考方案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&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 中为每个组申请的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Apache Camel 从 Java 类访问 JMS 队列?