2017-09-25 145 views
1

這種劃分源XML:複雜的「選擇」

<root> 
    <!-- a and b have the same date entries, c is different --> 
    <variant name="a"> 
    <booking> 
     <date from="2017-01-01" to="2017-01-02" /> 
     <date from="2017-01-04" to="2017-01-06" /> 
    </booking> 
    </variant> 
    <variant name="b"> 
    <booking> 
     <date from="2017-01-01" to="2017-01-02" /> 
     <date from="2017-01-04" to="2017-01-06" /> 
    </booking> 
    </variant> 
    <variant name="c"> 
    <booking> 
     <date from="2017-04-06" to="2017-04-07" /> 
     <date from="2017-04-07" to="2017-04-09" /> 
    </booking> 
    </variant> 
</root> 

我想組的三個變種,以便每個日期相同@from@to每個變種要相對集中。

我的嘗試是:

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

    <xsl:template match="root"> 
    <variants> 
    <xsl:for-each-group select="for $i in variant return $i" group-by="booking/date/@from"> 
     <group> 
     <xsl:attribute name="cgk" select="current-grouping-key()"/> 
     <xsl:copy-of select="current-group()"></xsl:copy-of> 
     </group> 
    </xsl:for-each-group> 
    </variants> 
    </xsl:template> 
</xsl:stylesheet> 

但是這給了太多組。 (如何)這可能實現?

+0

你得到的輸出是什麼? – GavinBrelstaff

+0

那麼您使用哪種XSLT 2.0處理器?使用Saxon 9.8或任何其他XSLT 3.0處理器和「複合」分組鍵可能會更容易。另外,具有相同'date'元素的'variant'會發生什麼,但是按不同的順序?訂單是否重要? –

+0

@MartinHonnen目前我正在使用Saxon-HE 9.4.0.2J,但我可以輕鬆更新。 – topskip

回答

2

使用composite key和XSLT 3.0,你可以使用

<xsl:template match="root"> 
    <variants> 
     <xsl:for-each-group select="variant" group-by="booking/date/(@from, @to)" composite="yes"> 
      <group key="{current-grouping-key()}"> 
       <xsl:copy-of select="current-group()"/> 
      </group> 
     </xsl:for-each-group> 
    </variants> 
</xsl:template> 

即應集團任何variant元素結合在一起,他們同爲後代date元素序列。

XSLT 3.0由Saxon 9.8(任意版本)或9.7(PE和EE)或2017版Altova XMLSpy/Raptor支持。

使用XSLT 2.0,你可以用string-join()串聯所有這些日期值:與date後裔相同的序列

<xsl:template match="root"> 
    <variants> 
     <xsl:for-each-group select="variant" group-by="string-join(booking/date/(@from, @to), '|')"> 
      <group key="{current-grouping-key()}"> 
       <xsl:copy-of select="current-group()"/> 
      </group> 
     </xsl:for-each-group> 
    </variants> 
</xsl:template> 

像XSLT 3.0解決方案,它只是羣體variant,我不知道這是否足夠或在計算分組鍵之前,是否可能要先排序date後代。在XSLT 3如果你能做到這一點很容易與

 <xsl:for-each-group select="variant" group-by="sort(booking/date,(), function($d) { xs:date($d/@from), xs:date($d/@to) })!(@from, @to)" composite="yes"> 

在線(雖然留下9.8 HE背後,因爲它不支持函數表達式/高階函數,所以你需要移動的排序,以自己用戶定義的xsl:function並在那裏使用xsl:perform-sort)。

+0

太棒了!我在我的簡單測試用例上嘗試過'composite =「yes」',並且它工作正常。我會嘗試將其應用於更復雜的「真實世界」數據並回報。 – topskip

+0

我希望我能給你多一個upvote!再次感謝。我非常喜歡看到其他解決方案,這些解決方案激勵我閱讀並嘗試更多。我幾次遇到XSLT/XPath 3,但從來沒有一個很好的理由嘗試它們。 – topskip