【问题标题】:XSLT: filter and apply conditional logic while grouping/sortingXSLT:在分组/排序时过滤和应用条件逻辑
【发布时间】:2011-11-10 04:12:30
【问题描述】:

对于像这样的输入 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,我只需要保留几个 Fares/item 节点,在这些节点中我首先按 FareType(E 和 F)分组,并保留从最便宜的 Fare 开始的项目,但如果 Seats >= 9 则停止。例如,由于 A 只有 5 个座位​​,我需要选择次高票价 B,而不是 C。另外,如果 Seats >= 9,我需要将其限制为 9。

我能够进行分组和排序,但无法步行票价并应用逻辑来选择票价,只要该票价类型的座位

输出 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 节点一起保留)。

谢谢!

【问题讨论】:

  • 我对您的一些要求感到有些困惑。您应该粘贴您期望的上述 XML 的确切输出。
  • “最便宜的票价”是什么意思?我没有看到任何价格信息。请解释。想要的输出(对于给定的 XML 文档)的示例以及为什么会产生此输出的解释会很棒。
  • 项是航空公司座位的价格。所以这将被视为数字排序。输出 XML 将是我发布的输入 XML 的副本,除了额外的 Fares/item 节点将被删除,仅保留符合条件的 Fares,并保持整个项目的 Flight 节点完整
  • 抱歉,不清楚 - 这是我第一次在 stackoverflow 上发帖,所以我在 XML 格式上苦苦挣扎。我现在用所需的输出 XML 更新了原始帖子。希望这会有所帮助!
  • 您能否发布您当前使用的 XSLT,因为这也会有所帮助?谢谢!

标签: xslt


【解决方案1】:

在这种情况下,您可以不使用分组,因为实际上您所做的只是排序,并且只是排除了一些元素。

所以,当匹配 Fares 元素时,您对 item 元素进行排序,就像这样

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

接下来,当你匹配每一个这样的 item 元素时,你可以只测试之前任何具有相同 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 个。

【讨论】:

  • Tim - 很抱歉延迟回来 - 这绝对是一个救生员!我对 XSLT 以及实践它的大师们的理解和深深的赞赏已经变得多方面了!非常感谢。
  • 嗨,Tim C - 您的回答一直都非常有效。现在我们有一个小的改进,我正在尝试找出正确的方法。在这个问题中使用相同的 XML/XSL 信息,我们现在需要用 A、B、C 顺序替换“FareClass”字母...除了应该保留的 FareClass 字母 G 和 Y。我看过 stackoverflow 问题 #7011714 - 但无法确定如何调用它。
  • 您好!由于这个问题已经存在一年了,最好的办法是提出一个新问题。谢谢!
  • 当然,蒂姆 - 感谢您的及时回复!我将立即重新发布 XML 和 XSLT
猜你喜欢
  • 2011-10-30
  • 2022-11-29
  • 2014-02-06
  • 2022-01-10
相关资源
最近更新 更多