2011-02-19 41 views
4

XSLT組由鑑於這種XML半小時

<root> 
    <row> 
    <time>08:00</time> 
    <sales>800</sales> 
    </row> 
    <row> 
    <time>08:15</time> 
    <sales>815</sales> 
    </row> 
    <row> 
    <time>08:30</time> 
    <sales>830</sales> 
    </row> 
    <row> 
    <time>08:45</time> 
    <sales>845</sales> 
    </row> 
    <row> 
    <time>11:00</time> 
    <sales>1100</sales> 
    </row> 
    <row> 
    <time>11:45</time> 
    <sales>1145</sales> 
    </row> 
    <row> 
    <time>14:15</time> 
    <sales>1415</sales> 
    </row> 
    <row> 
    <time>14:30</time> 
    <sales>1430</sales> 
    </row> 
</root> 

我試圖找到一種方法,XSLT通過總結30個分鐘的間隔變換銷售。我可以使用MUENCHIAN方法按小時間隔60分鐘進行總結,但由於我需要一個自定義函數(但我不能使用XSLT 2.0和.Net的自定義函數),因此我無法使用它30分鐘。請幫忙!

預期輸出是這樣的:

30 minute 
08:00 $1600 
08:30 $1675 
11:00 $1100 
11:30 $1145 
14:00 $1415 
14:30 $1430 
+0

優秀的問題,+1。查看我的答案以獲取完整的XSLT 1.0解決方案。 – 2011-02-19 03:44:17

+0

我已經爲我的答案添加了第二個解決方案。 :) – 2011-02-19 06:17:13

+0

現在我真的明白爲什麼社區希望XSLT 2.0如此糟糕。它的工作原理,但談論一個解決方法。唷!非常感謝! – Echiban 2011-02-19 07:24:09

回答

6

溶液1

該轉化

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

<xsl:key name="krowsInHalfHour" match= 
    "row[not((substring-after(time,':')+30) mod 30 = 0)]" 
    use="generate-id(
     preceding-sibling::row 
      [60*substring-before(time,':') 
      + 
      substring-after(time,':') 
      >= 
      60*substring-before(current()/time,':') 
      + 
      substring-after(current()/time,':') 

      - 
      substring-after(current()/time,':') mod 30 

      ] 
      [1] 
        ) 
    "/> 

<xsl:template match= 
    "row[(substring-after(time,':')+30) mod 30 = 0 
    or 
     not(
     60*substring-before(preceding-sibling::row[1]/time,':') 
      + 
      substring-after(preceding-sibling::row[1]/time,':') 
     >= 
      60*substring-before(time,':') 
      + 
      substring-after(time,':') 

      - 
      substring-after(time,':') mod 30 
     ) 
     ] 
    "> 
    <xsl:variable name="vPrevStartMins" select= 
    "60*substring-before(time,':') 
    + 
    substring-after(time,':') 

    - 
    substring-after(time,':') mod 30 
    "/> 
    <xsl:value-of select= 
    "concat('&#xA;',floor($vPrevStartMins div 60), 
      ':', concat(substring('0',($vPrevStartMins mod 60 >0)+1), 
         $vPrevStartMins mod 60 
         ) 
      ) 
    "/> 
    <xsl:text> $</xsl:text> 
    <xsl:value-of select= 
    "sum(sales 
     | 
     key('krowsInHalfHour',generate-id())/sales)"/> 
</xsl:template> 

<xsl:template match="text()"/> 
</xsl:stylesheet> 

當所提供的XML文檔應用:

<root> 
    <row> 
     <time>08:00</time> 
     <sales>800</sales> 
    </row> 
    <row> 
     <time>08:15</time> 
     <sales>815</sales> 
    </row> 
    <row> 
     <time>08:30</time> 
     <sales>830</sales> 
    </row> 
    <row> 
     <time>08:45</time> 
     <sales>845</sales> 
    </row> 
    <row> 
     <time>11:00</time> 
     <sales>1100</sales> 
    </row> 
    <row> 
     <time>11:45</time> 
     <sales>1145</sales> 
    </row> 
    <row> 
     <time>14:15</time> 
     <sales>1415</sales> 
    </row> 
    <row> 
     <time>14:30</time> 
     <sales>1430</sales> 
    </row> 
</root> 

產生想要的,正確的結果:

8:00 $1615 
8:30 $1675 
11:00 $1100 
11:30 $1145 
14:00 $1415 
14:30 $1430 

解決方案2

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="my:my" > 
<xsl:output method="text"/> 
<xsl:strip-space elements="*"/> 

<my:halfHours> 
    <t>00:00</t><t>00:30</t><t>01:00</t><t>01:30</t> 
    <t>02:00</t><t>02:30</t><t>03:00</t><t>03:30</t> 
    <t>04:00</t><t>04:30</t><t>05:00</t><t>05:30</t> 
    <t>06:00</t><t>06:30</t><t>07:00</t><t>07:30</t> 
    <t>08:00</t><t>08:30</t><t>09:00</t><t>09:30</t> 
    <t>10:00</t><t>10:30</t><t>11:00</t><t>11:30</t> 
    <t>12:00</t><t>12:30</t><t>13:00</t><t>13:30</t> 
    <t>14:00</t><t>14:30</t><t>15:00</t><t>15:30</t> 
    <t>16:00</t><t>16:30</t><t>17:00</t><t>17:30</t> 
    <t>18:00</t><t>18:30</t><t>19:00</t><t>19:30</t> 
    <t>20:00</t><t>20:30</t><t>21:00</t><t>21:30</t> 
    <t>22:00</t><t>22:30</t><t>23:00</t><t>23:30</t> 
    <t>24:00</t> 
</my:halfHours> 

<xsl:variable name="vhalfHrs" select= 
    "document('')/*/my:halfHours/*"/> 

<xsl:template match="row"> 
    <xsl:variable name="vStart" select= 
    "$vhalfHrs[translate(.,':','') 
      > 
      translate(current()/time,':','') 
      ][1] 
       /preceding-sibling::*[1] 
    "/> 

    <xsl:variable name="vprecRow" select= 
    "preceding-sibling::*[1]"/> 

    <xsl:if test= 
    "not(translate($vprecRow/time,':','') 
     >= 
     translate($vStart,':','') 
     )"> 
    <xsl:value-of select="concat('&#xA;',$vStart, ' $')"/> 
    <xsl:value-of select= 
    "sum(sales|following-sibling::* 
      [not(translate(time,':','') 
       >= 
       translate($vStart/following-sibling::*,':','') 
       ) 
      ] 
      /sales 
     ) 
    "/> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

當這種轉變是在同一個XML文檔,再次通緝,正確的結果應用生產

08:00 $1615 
08:30 $1675 
11:00 $1100 
11:30 $1145 
14:00 $1415 
14:30 $1430 

說明

  1. 在變$vhalfHrs我們將其值白天每半小時週期的起始時間元素。

  2. 在每個row匹配的模板中,$vStart變量設置TI這個半小時的開始時間,在其中當前節點(row)的time落入。

  3. 將變量$vprecRow設置爲當前row的前面的同級(row)。

  4. 如果上述row的時間不晚於開始半小時的時間(以$的vStart ), then the current row`在這半小時內的第一個。

  5. 我們輸出開始半小時的時間。

  6. 我們計算並輸出所有row元素,其time在這同一個半小時的時間的總和。他們遵循當前row及其time的兄弟姐妹不大於或等於下半個小時的開始。

溶液3(XSLT 2.0):

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
<xsl:output method="text"/> 

<xsl:template match="/*"> 
    <xsl:for-each-group select="row" group-adjacent= 
    "(xs:integer(substring-before(time,':'))*60 
    + 
    xs:integer(substring-after(time,':')) 
    ) 
    idiv 30 
    "> 
    <xsl:variable name="vStartMinutes" 
     select="current-grouping-key()*30"/> 
    <xsl:value-of separator="" select= 
    "'&#xA;', 
    format-number($vStartMinutes idiv 60, '00'), ':', 
    format-number($vStartMinutes mod 60,'00'), 
    ' $', 
    sum(current-group()/sales/xs:integer(.)) 
    "/> 
    </xsl:for-each-group> 
</xsl:template> 
</xsl:stylesheet> 

當該轉化如上述施加在相同的XML文檔中,相同的想要的,正確的結果產生

08:00 $1615 
08:30 $1675 
11:00 $1100 
11:30 $1145 
14:00 $1415 
14:30 $1430 

說明

  1. 我們正在使用<xsl:for-each-group>group-adjacent屬性組作爲表達式計算1/2小時期間在其中row/time是的位置。

  2. 大量使用標準功能current-group()current-grouping-key()

3

沒有前述軸,這個樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:key name="kRowByHalfHour" 
      match="row" 
      use="floor((substring(time,1,2)*60+substring(time,4))div 30)"/> 
    <xsl:template match="row[count(.|key('kRowByHalfHour', 
             floor((substring(time,1,2) * 60 
               + substring(time,4)) div 30) 
            )[1] 
          )=1 
         ]"> 
     <xsl:variable name="vKey" 
      select="floor((substring(time,1,2)*60+substring(time,4))div 30)"/> 
     <xsl:value-of 
      select="concat(format-number(floor($vKey * 30 div 60),'00'),':', 
          format-number(($vKey * 30) mod 60,'00'),' $', 
          sum(key('kRowByHalfHour',$vKey)/sales),'&#xA;' 
        )"/> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 

輸出:

08:00 $1615 
08:30 $1675 
11:00 $1100 
11:30 $1145 
14:00 $1415 
14:30 $1430 

編輯2:甚至更好的鍵與歸一化的時間,允許的參數值(由document()函數或兩個相位轉換):如果我們將關鍵計算作爲複雜性度量,則這將是O(N)

相關問題