XSLT:在分组/排序时过滤并应用条件逻辑

时间:2011-11-10 04:12:30

标签: xslt

对于输入XML,如:

<FlightOptions>
  <item>
     <Fares>
       <item>
         <FareClass>A</FareClass>
         <Fare>100</Fare>
         <FareType>E</FareType>
         <Seats>5</Seats>
       </item>
       <item>
         <FareClass>B</FareClass>
         <Fare>200</Fare>
         <FareType>E</FareType>
         <Seats>10</Seats>
       </item>
       <item>
         <FareClass>C</FareClass>
         <Fare>250</Fare>
         <FareType>E</FareType>
         <Seats>20</Seats>
       </item>
       <item>
         <FareClass>N</FareClass>
         <Fare>100</Fare>
         <FareType>F</FareType>
         <Seats>5</Seats>
       </item>
       <item>
         <FareClass>M</FareClass>
         <Fare>200</Fare>
         <FareType>F</FareType>
         <Seats>50</Seats>
       </item>
       <item>
         <FareClass>O</FareClass>
         <Fare>300</Fare>
         <FareType>F</FareType>
         <Seats>20</Seats>
       </item>
     </Fares>
     <Flight>
         <FlightNumber>YY232</FlightNumber>
         <Origin>JFK</Origin>
         <Destination>LHR</Destination>
         <DepTime>1300</DepTime>
         <ArrTime>2000</ArrTime>
     </Flight>
    </item>
</FlightOptions>

对于上面的XML,我需要只保留几个票价/项目节点,我首先按FareType(E和F)分组,并保持项目从最便宜的票价开始,但如果座位是&gt; = 9则停止例如,由于A只有5个席位,我需要选择下一个最高票价B,但不是C.另外,如果Seats&gt; = 9,我需要将其限制为9个。

我可以进行分组和排序,但无法行走票价并应用逻辑来选择票价,只要该票价类型的座位<= 9。另一个复杂因素是输出XML必须重新排序Fares /项目,使得FareType E节点首先按Fare的降序排列,然后是N节点(如果存在于源中),然后其他FareType F节点按降序排列车费。

输出XML将是:

<FlightOptions>
  <item>
     <Fares>
       <item>
         <FareClass>B</FareClass>
         <Fare>200</Fare>
         <FareType>E</FareType>
         <Seats>9</Seats>
       </item>
       <item>
         <FareClass>A</FareClass>
         <Fare>100</Fare>
         <FareType>E</FareType>
         <Seats>5</Seats>
       </item>
       <item>
         <FareClass>N</FareClass>
         <Fare>100</Fare>
         <FareType>F</FareType>
         <Seats>5</Seats>
       </item>
       <item>
         <FareClass>M</FareClass>
         <Fare>200</Fare>
         <FareType>F</FareType>
         <Seats>9</Seats>
       </item>
     </Fares>
     <Flight>
         <FlightNumber>YY232</FlightNumber>
         <Origin>JFK</Origin>
         <Destination>LHR</Destination>
         <DepTime>1300</Deptime>
         <ArrTime>2000</ArrTime>
     </Flight>
    </item>
<FlightOptions>

一直试图阅读Muenchian分组示例,但我无法理解如何应用身份变换(因为我必须保持Flight结构以及Fares / item节点)。

谢谢!

1 个答案:

答案 0 :(得分:0)

你可以在这个例子中不使用分组,因为你所做的一切都是排序,只是排除了一些元素。

因此,在匹配票价元素时,您可以对元素进行排序,如此

     <xsl:apply-templates select="item">
        <xsl:sort select="FareType"/>
        <xsl:sort select="Fare"/>
     </xsl:apply-templates>

接下来,当您匹配每个商品元素时,您只需测试具有相同 FareType 的任何先前元素是否已大于9.如果没有这样的节点,然后因为你已经按票价排序,你知道要包含节点。

<xsl:template match="Fares/item">
    <xsl:if test="not(preceding-sibling::item[FareType=current()/FareType][Seats > 9])">
       <!-- copy node -->
    </xsl:if>

这是完整的XSLT ......

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:template match="Fares">
      <xsl:copy>
         <xsl:apply-templates select="item">
            <xsl:sort select="FareType"/>
            <xsl:sort select="Fare"/>
         </xsl:apply-templates>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="Fares/item">
      <xsl:if test="not(preceding-sibling::item[FareType=current()/FareType][Seats > 9])">
         <xsl:call-template name="identity"/>
      </xsl:if>
   </xsl:template>

   <xsl:template match="Seats[. > 9]">
      <xsl:copy>9</xsl:copy>
   </xsl:template>

   <xsl:template match="@*|node()">
      <xsl:call-template name="identity"/>
   </xsl:template>

   <xsl:template name="identity">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

</xsl:stylesheet>

当应用于您的示例XML时,输出以下内容:

<FlightOptions>
   <item>
      <Fares>
         <item>
            <FareClass>A</FareClass>
            <Fare>100</Fare>
            <FareType>E</FareType>
            <Seats>5</Seats>
         </item>
         <item>
            <FareClass>B</FareClass>
            <Fare>200</Fare>
            <FareType>E</FareType>
            <Seats>9</Seats>
         </item>
         <item>
            <FareClass>N</FareClass>
            <Fare>100</Fare>
            <FareType>F</FareType>
            <Seats>5</Seats>
         </item>
         <item>
            <FareClass>M</FareClass>
            <Fare>200</Fare>
            <FareType>F</FareType>
            <Seats>9</Seats>
         </item>
      </Fares>
      <Flight>
         <FlightNumber>YY232</FlightNumber>
         <Origin>JFK</Origin>
         <Destination>LHR</Destination>
         <DepTime>1300</DepTime>
         <ArrTime>2000</ArrTime>
      </Flight>
   </item>
</FlightOptions>

还要注意席位的模板匹配,然后将其限制为9。