限制输出(XSLT 2.0临时树)

时间:2014-02-28 22:13:22

标签: xslt-2.0

我和一位同事获得了新的要求。请查看以下内容。

我们需要转换XML源文档,同时对结果文档中的某些项执行数字限制。下面复制源文档,XSLT样式表和结果文档。但是,此结果文档未反映所需的数字限制,因为此样式表无需任何限制即可转换源文档。

最后,我们的问题是:如何在样式表中强制执行所需的数字限制?

来源文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<T:Message xmlns="http://www.noname.com/Platform" xmlns:T="http://www.noname.com/Transportation">
   <T:ShipmentListMessage>
       <Shipment>
           <ShipmentNumber>ABC</ShipmentNumber>
           <PickupCommodityCode>Hazmat</PickupCommodityCode>
           <DeliveryCommodityCode>Hazmat</DeliveryCommodityCode>
           <ShipmentLine>
               <ShipmentLineNumber>ABC-1</ShipmentLineNumber>
               <OrderLineItemNumber>1</OrderLineItemNumber>
           </ShipmentLine>
           <ShipmentLine>
               <ShipmentLineNumber>ABC-2</ShipmentLineNumber>
               <OrderLineItemNumber>2</OrderLineItemNumber>
           </ShipmentLine>
           <ShipmentLine>
               <ShipmentLineNumber>ABC-3</ShipmentLineNumber>
               <OrderLineItemNumber>3</OrderLineItemNumber>
           </ShipmentLine>
       </Shipment>
       <Shipment>
           <ShipmentNumber>DEF</ShipmentNumber>
           <PickupCommodityCode>Hazmat</PickupCommodityCode>
           <DeliveryCommodityCode>Hazmat</DeliveryCommodityCode>
           <ShipmentLine>
               <ShipmentLineNumber>DEF-1</ShipmentLineNumber>
               <OrderLineItemNumber>1</OrderLineItemNumber>
           </ShipmentLine>
           <ShipmentLine>
               <ShipmentLineNumber>DEF-2</ShipmentLineNumber>
               <OrderLineItemNumber>2</OrderLineItemNumber>
           </ShipmentLine>
       </Shipment>
       <Shipment>
           <ShipmentNumber>GHI</ShipmentNumber>
           <PickupCommodityCode>Hazmat</PickupCommodityCode>
           <DeliveryCommodityCode>Hazmat</DeliveryCommodityCode>
           <ShipmentLine>
               <ShipmentLineNumber>GHI-1</ShipmentLineNumber>
               <OrderLineItemNumber>1</OrderLineItemNumber>
           </ShipmentLine>
           <ShipmentLine>
               <ShipmentLineNumber>GHI-2</ShipmentLineNumber>
               <OrderLineItemNumber>2</OrderLineItemNumber>
           </ShipmentLine>
           <ShipmentLine>
               <ShipmentLineNumber>GHI-3</ShipmentLineNumber>
               <OrderLineItemNumber>3</OrderLineItemNumber>
           </ShipmentLine>
           <ShipmentLine>
               <ShipmentLineNumber>GHI-4</ShipmentLineNumber>
               <OrderLineItemNumber>4</OrderLineItemNumber>
           </ShipmentLine>
       </Shipment>
   </T:ShipmentListMessage>
   <T:MovementListMessage>
       <Movement>
           <MovementStop>
               <StopSequenceNumber>0</StopSequenceNumber>
               <MovementStopLine>
                   <OperationType>Pickup</OperationType>
                   <ShipmentNumber>ABC</ShipmentNumber>
               </MovementStopLine>
               <MovementStopLine>
                   <OperationType>Pickup</OperationType>
                   <ShipmentNumber>DEF</ShipmentNumber>
               </MovementStopLine>
               <MovementStopLine>
                   <OperationType>Pickup</OperationType>
                   <ShipmentNumber>GHI</ShipmentNumber>
               </MovementStopLine>
           </MovementStop>
           <MovementStop>
               <StopSequenceNumber>1</StopSequenceNumber>
               <MovementStopLine>
                   <OperationType>Deliver</OperationType>
                   <ShipmentNumber>ABC</ShipmentNumber>
               </MovementStopLine>
           </MovementStop>
           <MovementStop>
               <StopSequenceNumber>2</StopSequenceNumber>
               <MovementStopLine>
                   <OperationType>Deliver</OperationType>
                   <ShipmentNumber>DEF</ShipmentNumber>
               </MovementStopLine>
               <MovementStopLine>
                   <OperationType>Deliver</OperationType>
                   <ShipmentNumber>GHI</ShipmentNumber>
               </MovementStopLine>
           </MovementStop>
       </Movement>
   </T:MovementListMessage>
</T:Message>

XSLT样式表:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://www.noname.com/Transportation" xmlns:vc="http://www.noname.com/Platform"> 
 <xsl:output method="text" indent="no"/>
 <xsl:template match="t:Message">
   <xsl:variable name="shipmentPath" select="t:ShipmentListMessage/vc:Shipment"/>
   <xsl:variable name="movementPath" select="t:MovementListMessage/vc:Movement"/>
   <xsl:variable name="numDeliverLocations" select="count($movementPath/vc:MovementStop/vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
   <xsl:variable name="numOffers" select="count($shipmentPath)"/>
   <xsl:for-each select="$movementPath/vc:MovementStop">
       <xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Deliver']">
           <xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
           <xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
           <xsl:if test="position() = 1">
S5*<xsl:value-of select="../vc:StopSequenceNumber+1"/>*UL<xsl:text>~</xsl:text>
           </xsl:if>
       </xsl:for-each>
       <xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Deliver']">
           <xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
           <xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
           <xsl:variable name="OfferPosition" select="if (position() lt 10) then position() else 0"/>
           <xsl:for-each select="$shipmentPath[vc:ShipmentNumber = $OfferNumber and vc:DeliveryCommodityCode != '']">
               <xsl:choose>
                   <xsl:when test="vc:DeliveryCommodityCode = 'Hazmat'">
                       <xsl:if test="$numOffers gt 1 or $numDeliverLocations = 1">
                           <xsl:for-each select="vc:ShipmentLine">
                               <xsl:variable name="ShipmentLine" select="vc:ShipmentLineNumber"/>
                               <xsl:choose>
                                   <xsl:when test="$OfferCount eq 1">
L5*<xsl:value-of select="vc:OrderLineItemNumber"/><xsl:text>~</xsl:text>
                                   </xsl:when>
                                   <xsl:when test="position() lt 10">
L5*<xsl:value-of select="concat($OfferPosition, '0', vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text>
                                   </xsl:when>
                                   <xsl:otherwise>
L5*<xsl:value-of select="concat($OfferPosition, vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text>
                                   </xsl:otherwise>
                               </xsl:choose>
                           </xsl:for-each>
                       </xsl:if>
                   </xsl:when>
               </xsl:choose>
           </xsl:for-each>
       </xsl:for-each>
       <xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Pickup']">
           <xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
           <xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Pickup'])"/>
           <xsl:if test="position() = 1">
S5*<xsl:value-of select="../vc:StopSequenceNumber+1"/>*LD<xsl:text>~</xsl:text>
           </xsl:if>
       </xsl:for-each>
       <xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Pickup']">
           <xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
           <xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Pickup'])"/>
           <xsl:variable name="OfferPosition" select="if (position() lt 10) then position() else 0"/>
           <xsl:for-each select="$shipmentPath[vc:ShipmentNumber = $OfferNumber and vc:PickupCommodityCode != '']">
               <xsl:choose>
                   <xsl:when test="vc:PickupCommodityCode = 'Hazmat'">
                       <xsl:for-each select="vc:ShipmentLine">
                           <xsl:variable name="ShipmentLine" select="vc:ShipmentLineNumber"/>
                           <xsl:choose>
                               <xsl:when test="$OfferCount eq 1">
L5*<xsl:value-of select="vc:OrderLineItemNumber"/><xsl:text>~</xsl:text>
                               </xsl:when>
                               <xsl:when test="position() lt 10">
L5*<xsl:value-of select="concat($OfferPosition, '0', vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text>
                               </xsl:when>
                               <xsl:otherwise>
L5*<xsl:value-of select="concat($OfferPosition, vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text>
                               </xsl:otherwise>
                           </xsl:choose>
                       </xsl:for-each>
                   </xsl:when>
               </xsl:choose>
           </xsl:for-each>
       </xsl:for-each>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

结果文件:

S5*1*LD~
L5*101~
L5*102~
L5*103~
L5*201~
L5*202~
L5*301~
L5*302~
L5*303~
L5*304~
S5*2*UL~
L5*1~
L5*2~
L5*3~
S5*3*UL~
L5*101~
L5*102~
L5*201~
L5*202~
L5*203~
L5*204~

为了满足我们的要求,数字限制必须以某种方式构建到样式表中。出于本讨论的目的,对于“S5”段之后的“L5”段的数量,期望的限制是5。在该示例中,限制将在“S5 * 1 * LD”和“S5 * 3 * UL”之后将“L5”段的数量减少到5。在“S5 * 2 * UL”的情况下,限制不会发挥作用。

应用了“L5”限制的所需结果文档:

S5*1*LD~
L5*101~
L5*102~
L5*103~
L5*201~
L5*202~
S5*2*UL~
L5*1~
L5*2~
L5*3~
S5*3*UL~
L5*101~
L5*102~
L5*201~
L5*202~
L5*203~

同样,我们的问题是:如何在样式表中编码所需的数字限制?

1 个答案:

答案 0 :(得分:0)

我认为您可以将第一个结果存储在变量中,然后根据需要进行分组和计数,以便于处理我选择将中间结果包装为XML:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://www.noname.com/Transportation" xmlns:vc="http://www.noname.com/Platform"
 exclude-result-prefixes="t vc"> 

 <xsl:output method="text"/>

 <xsl:template match="t:Message">
   <xsl:variable name="shipmentPath" select="t:ShipmentListMessage/vc:Shipment"/>
   <xsl:variable name="movementPath" select="t:MovementListMessage/vc:Movement"/>
   <xsl:variable name="numDeliverLocations" select="count($movementPath/vc:MovementStop/vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
   <xsl:variable name="numOffers" select="count($shipmentPath)"/>

   <xsl:variable name="items">
     <xsl:for-each select="$movementPath/vc:MovementStop">
         <xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Deliver']">
             <xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
             <xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
             <xsl:if test="position() = 1">
               <item>S5*<xsl:value-of select="../vc:StopSequenceNumber+1"/>*UL<xsl:text>~</xsl:text></item>
             </xsl:if>
         </xsl:for-each>
         <xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Deliver']">
             <xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
             <xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
             <xsl:variable name="OfferPosition" select="if (position() lt 10) then position() else 0"/>
             <xsl:for-each select="$shipmentPath[vc:ShipmentNumber = $OfferNumber and vc:DeliveryCommodityCode != '']">
                 <xsl:choose>
                     <xsl:when test="vc:DeliveryCommodityCode = 'Hazmat'">
                         <xsl:if test="$numOffers gt 1 or $numDeliverLocations = 1">
                             <xsl:for-each select="vc:ShipmentLine">
                                 <xsl:variable name="ShipmentLine" select="vc:ShipmentLineNumber"/>
                                 <xsl:choose>
                                     <xsl:when test="$OfferCount eq 1">
                                       <item>L5*<xsl:value-of select="vc:OrderLineItemNumber"/><xsl:text>~</xsl:text></item>
                                     </xsl:when>
                                     <xsl:when test="position() lt 10">
                                       <item>L5*<xsl:value-of select="concat($OfferPosition, '0', vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text></item>
                                     </xsl:when>
                                     <xsl:otherwise>
                                       <item>L5*<xsl:value-of select="concat($OfferPosition, vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text></item>
                                     </xsl:otherwise>
                                 </xsl:choose>
                             </xsl:for-each>
                         </xsl:if>
                     </xsl:when>
                 </xsl:choose>
             </xsl:for-each>
         </xsl:for-each>
         <xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Pickup']">
             <xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
             <xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Pickup'])"/>
             <xsl:if test="position() = 1">
               <item>S5*<xsl:value-of select="../vc:StopSequenceNumber+1"/>*LD<xsl:text>~</xsl:text></item>
             </xsl:if>
         </xsl:for-each>
         <xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Pickup']">
             <xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
             <xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Pickup'])"/>
             <xsl:variable name="OfferPosition" select="if (position() lt 10) then position() else 0"/>
             <xsl:for-each select="$shipmentPath[vc:ShipmentNumber = $OfferNumber and vc:PickupCommodityCode != '']">
                 <xsl:choose>
                     <xsl:when test="vc:PickupCommodityCode = 'Hazmat'">
                         <xsl:for-each select="vc:ShipmentLine">
                             <xsl:variable name="ShipmentLine" select="vc:ShipmentLineNumber"/>
                             <xsl:choose>
                                 <xsl:when test="$OfferCount eq 1">
                                   <item>L5*<xsl:value-of select="vc:OrderLineItemNumber"/><xsl:text>~</xsl:text></item>
                                 </xsl:when>
                                 <xsl:when test="position() lt 10">
                                   <item>L5*<xsl:value-of select="concat($OfferPosition, '0', vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text></item>
                                 </xsl:when>
                                 <xsl:otherwise>
                                   <item>L5*<xsl:value-of select="concat($OfferPosition, vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text></item>
                                 </xsl:otherwise>
                             </xsl:choose>
                         </xsl:for-each>
                     </xsl:when>
                 </xsl:choose>
             </xsl:for-each>
         </xsl:for-each>
     </xsl:for-each>
   </xsl:variable>

   <xsl:for-each-group select="$items/item" group-starting-with="item[starts-with(., 'S5*')]">
     <xsl:if test="position() gt 1"><xsl:text>&#10;</xsl:text></xsl:if>
     <xsl:value-of select="if (starts-with(., 'S5*1*LD') or starts-with(., 'S5*3*UL'))
                           then current-group()[position() le 6] else current-group()"
                   separator="&#10;"/>
    </xsl:for-each-group>
 </xsl:template>
</xsl:stylesheet>

使用该样式表和输入Saxon 9.5输出

S5*1*LD~
L5*101~
L5*102~
L5*103~
L5*201~
L5*202~
S5*2*UL~
L5*1~
L5*2~
L5*3~
S5*3*UL~
L5*101~
L5*102~
L5*201~
L5*202~
L5*203~