2011-10-10 69 views
2

我有一個包含價格不同日期XSLT - 分組和排序屬性

<tour id="12314"> 
    <available date="2012-04-19" price="533" /> 
    <available date="2012-05-09" price="670" /> 
    <available date="2012-05-25" price="600" /> 
    <available date="2012-06-05" price="710" /> 
    <available date="2012-06-08" price="710" /> 
    <available date="2012-06-15" price="710" /> 
    <available date="2012-06-20" price="705" /> 
</tour> 

我的要求是使用XSLT 前獲得具有每個月的價格最便宜的節點的XML:所需的輸出是:

<available dt="2012-04-19" price="533" /> 
<available dt="2012-05-25" price="600" /> 
<available dt="2012-06-20" price="705" /> 

我開始整理的可用節點下面,但我不知道怎麼去通過一個月最便宜的價格

分組的節點

任何幫助將多使用Muenchian方法和簡單的排序理解

回答

1

我提供了總共三個替代解決方案每個簡短和簡單(沒有嵌套<xsl:for-each>和沒有排序)。如果可能的話,我建議使用XSLT 2.0解決方案。

I.兩種備選XSLT 1.0的解決方案:

1.在不鍵

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

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

<xsl:template match="available"> 
    <xsl:if test= 
    "not(@price 
     > 
     (preceding-sibling::available 
     | 
     following-sibling::available 
     ) 
      [substring(@date, 1, 7) 
      = 
      substring(current()/@date, 1, 7) 
      ] 
      /@price 
     )"> 
    <xsl:call-template name="identity"/> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

2.使用鍵

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kDateByMonth" match="available" 
      use="substring(@date, 1, 7)"/> 

<xsl:template match= 
    "available 
     [generate-id() 
     = 
     generate-id(key('kDateByMonth', 
         substring(@date, 1, 7) 
         )[1] 
        ) 
     ] 
    "> 
    <xsl:variable name="vsameMonth" select= 
    "key('kDateByMonth', 
     substring(@date, 1, 7) 
     ) 
    "/> 

    <xsl:copy-of select= 
    "$vsameMonth[not(@price > $vsameMonth/@price)][1] 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

當任何兩個的以上轉換適用於所提供的XML文檔

想要的,正確的結果產生

<tour id="12314"> 
    <available date="2012-04-19" price="533"/> 
    <available date="2012-05-25" price="600"/> 
    <available date="2012-06-20" price="705"/> 
</tour> 

注意:在這個問題它沒有指定什麼輸出如果一個月內不止一次巡迴賽的最低票數相同價錢。第一次轉換將輸出所有這樣的遊覽(並且可能會給讀者選擇),而第二次轉換每個月僅輸出一次這樣的遊覽。這兩種轉換都可以修改以實現其他行爲。

二,一個XSLT 2.0解決方案

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/*"> 
    <xsl:for-each-group select="*" 
         group-by="substring(@date, 1,7)"> 
    <xsl:copy-of select= 
    "current-group() 
     [@price 
     = 
     min(current-group()/@price/number()) 
     ] 
     [1]"/> 
    </xsl:for-each-group> 
</xsl:template> 
</xsl:stylesheet> 
2

XSLT 1.0解決方案:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:key name="months" match="available" use="substring(@date, 6, 2)"/> 

    <xsl:template match="/tour[@id = '12314']"> 
    <result> 
     <xsl:for-each select="./available[generate-id() = generate-id(key('months',substring(@date, 6, 2))[1])]"> 
     <xsl:for-each select="key('months',substring(@date, 6, 2))"> 
      <xsl:sort select="@price" order="ascending"/> 
      <xsl:if test="position() = 1"> 
      <xsl:copy-of select="current()"/> 
      </xsl:if> 
     </xsl:for-each> 
     </xsl:for-each> 
    </result> 
    </xsl:template> 
</xsl:stylesheet> 

當上述變換應用於此xml:

<tour id="12314"> 
    <available date="2012-04-19" price="533" /> 
    <available date="2012-05-09" price="670" /> 
    <available date="2012-05-25" price="600" /> 
    <available date="2012-06-05" price="710" /> 
    <available date="2012-06-08" price="710" /> 
    <available date="2012-06-15" price="710" /> 
    <available date="2012-06-20" price="705" /> 
</tour> 

輸出是:

<?xml version="1.0" encoding="UTF-8"?> 
<result> 
    <available date="2012-04-19" price="533"/> 
    <available date="2012-05-25" price="600"/> 
    <available date="2012-06-20" price="705"/> 
</result> 

邏輯:首先我根據@date屬性的子字符串對可用節點進行分組,然後對於每個獨特的月份,我收集所有可用的節點,按升序對它們進行排序,並以最低價格打印節點,第一個節點由於排序。希望它幫助:)

+0

@_FailedDev:該解決方案是非常好的,如果只希望多最低價格的旅遊團。在我看來,使用這種解決方案是不可能的,並且不需要修改線性搜索以最低價格輸出*全部*遊覽。你怎麼看? –

+0

@DimitreNovatchev我基於OP的嘗試,因爲他使用的是特殊ID的解決方案。當然,可以有更多的一般選擇 - 正如你指出的那樣:) – FailedDev