2009-10-10 152 views
1

類似於這個問題(有多個相關條目,但作爲一個新的用戶,我只能發佈一個URL): Xpath Get elements that are between 2 elements的XPath XSLT:選擇兩個其他元素之間的元素,第二部分

我對於選擇「其他/定界」元素之間出現的元素集有一個疑問。嘗試使用XSLT將平面HTML表格轉換爲層次結構的 時會出現這種情況。我嘗試在模板中使用遞歸,但撒克遜拒絕接受,因爲它導致死鎖,很可能是我的錯,但讓我們從頭開始。

第一源數據的HTML表:

<table > 
    <thead> 
     <tr> 
      <th>Column 1</th> 
      <th>Column 2</th> 
      <th>Column 3</th> 
     </tr> 
    </thead> 
    <tbody> 
     <tr> 
      <th colspan="3" >Group 1</th> 
     </tr> 
     <tr> 
      <td>attribute 1.1.1</td> 
      <td>attribute 1.1.3</td> 
      <td>attribute 1.1.2</td> 
     </tr> 
     <tr> 
      <td>attribute 1.2.1</td> 
      <td>attribute 1.2.2</td> 
      <td>attribute 1.2.3</td> 
     </tr> 
     <tr> 
      <td>attribute 1.3.1</td> 
      <td>attribute 1.3.2</td> 
      <td>attribute 1.3.3</td> 
     </tr> 
     <tr> 
      <th colspan="3" >Group 2</th> 
     </tr> 
     <tr> 
      <td>attribute 2.1.1</td> 
      <td>attribute 2.1.3</td> 
      <td>attribute 2.1.2</td> 
     </tr> 
     <tr> 
      <td>attribute 2.2.1</td> 
      <td>attribute 2.2.2</td> 
      <td>attribute 2.2.3</td> 
     </tr> 
     <tr> 
      <td>attribute 2.3.1</td> 
      <td>attribute 2.3.2</td> 
      <td>attribute 2.3.3</td> 
     </tr> 
    </tbody> 
</table> 

XML中的目標輸出是:

<groups> 
    <group name="Group 1"> 
     <item attribute1="attribute 1.1.1" attribute2="attribute 1.1.3" attribute3="attribute 1.1.2"/> 
     <item attribute1="attribute 1.2.1" attribute2="attribute 1.2.2" attribute3="attribute 1.2.3"/> 
     <item attribute1="attribute 1.3.1" attribute2="attribute 1.3.2" attribute3="attribute 1.3.3"/> 
    </group> 
    <group name="Group 2"> 
     <item attribute1="attribute 2.1.1" attribute2="attribute 2.1.3" attribute3="attribute 2.1.2"/> 
     <item attribute1="attribute 2.2.1" attribute2="attribute 2.2.2" attribute3="attribute 2.2.3"/> 
     <item attribute1="attribute 2.3.1" attribute2="attribute 2.3.2" attribute3="attribute 2.3.3"/> 
    </group> 
</groups> 

所以我想將所有的項目條目,(TR元素)和將它們添加到一個組中。這基本上歸結爲選擇所有後續兄弟TR元素,直到我們遇到一個具有TH元素作爲孩子的元素。如果我只能確定有TH孩子,表示爲一組一個新的標題這個第一TR的位置,這可能是與完成:

<xsl:for-each select="tbody/tr"> 
    <xsl:if test="th"> 
     <xsl:element name="group"> 
      <xsl:attribute name="name"><xsl:value-of select="th"/></xsl:attribute> 
      <xsl:for-each select="following-sibling::tr[position() < $positionOfNextThElement]">    
       <xsl:call-template name="item"/> 
      </xsl:for-each> 
     </xsl:element> 
    </xsl:if> 
</xsl:for-each> 

不過,我不能確定的位置首先遇到TR/TH標籤。

如上所述,我嘗試使用模板中的遞歸:總是調用「item」模板,並在此模板中確定是否要在下一個項目上調用它。我認爲問題出在模板中調用模板。上下文中的項目不會增加?我應該交出一個參數來確定我們正在處理的項目嗎?

總之,這是我想出了:

<xsl:for-each select="tbody/tr"> 
    <xsl:if test="th"> 
     <xsl:element name="group"> 
      <xsl:attribute name="name"><xsl:value-of select="th"/></xsl:attribute> 
      <xsl:call-template name="item"/> 
     </xsl:element> 
    </xsl:if> 
</xsl:for-each> 

<xsl:template name="item"> 
    <xsl:element name="item"> 
     <xsl:attribute name="attribute1"><xsl:value-of select="following-sibling::tr[1]/td[1]"/></xsl:attribute> 
     <xsl:attribute name="attribute2"><xsl:value-of select="following-sibling::tr[1]/td[2]"/></xsl:attribute> 
     <xsl:attribute name="attribute2"><xsl:value-of select="following-sibling::tr[1]/td[3]"/></xsl:attribute> 
    </xsl:element> 
    <!-- When the next element has not got a TH tag, continue with invoking this template --> 
    <xsl:if test="count(following-sibling::tr[1]/th) != 1"> 
     <xsl:call-template name="item"/> 
    </xsl:if> 
</xsl:template> 

就如何實現這一歡迎任何建議!

回答

0

的備選解決方案,安裝用於進行可變屬性計數且無需遞歸。

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

    <xsl:template match="table"> 
    <groups> 
     <xsl:apply-templates select="tbody/tr[th]"/> 
    </groups> 
    </xsl:template> 

    <xsl:template match="tr[th]"> 
    <group name="{th}"> 
     <xsl:apply-templates select=" 
     following-sibling::tr[not(th)][ 
      generate-id(preceding-sibling::tr[th][1]) = generate-id(current()) 
     ] 
     "/> 
    </group> 
    </xsl:template> 

    <xsl:template match="tr"> 
    <item> 
    <xsl:apply-templates select="td" /> 
    </item> 
    </xsl:template> 

    <xsl:template match="td"> 
    <xsl:attribute name="attribute{position()}"> 
     <xsl:value-of select="." /> 
    </xsl:attribute> 
    </xsl:template> 

</xsl:stylesheet> 
1

當您遞歸調用模板「item」時,上下文不會增加的原因是xs:call-template始終將當前上下文項作爲上下文進行傳遞。正如你可能看到的那樣,變換隻是進入無限遞歸。

假設您始終需要生成三個屬性,那麼您甚至不需要遞歸。

試試這個:

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

    <xsl:template match="table"> 
     <groups> 
      <xsl:apply-templates select="tbody/tr[th]"/> 
     </groups> 
    </xsl:template> 

    <xsl:template match="tr[th]"> 
     <xsl:variable name="id" select="generate-id(.)"/> 
     <group name="{string(th)}"> 
      <xsl:apply-templates 
       select="following-sibling::tr[not(th)][generate-id(preceding-sibling::tr[th][1]) = $id]"/> 
     </group> 
    </xsl:template> 

    <xsl:template match="tr"> 
     <item attribute1="{td[1]}" attribute2="{td[2]}" attribute3="{td[3]}" />      
    </xsl:template> 

</xsl:stylesheet> 

這是通過應用模板到每個表頭行。這些模板中的每一個都使用複雜的xpath調用「其」後面的行,這些行是具有該特定行的任何後續兄弟行,因爲它是第一個帶有標題的行。

當然,如果屬性數量不同,那麼您需要遞歸併增加傳遞一個指示位置的參數。

XSLT分組有一些已建立的方法,其中之一是遞歸的,就像您正在做的那樣。另一種方法稱爲Muenchian分組。一個好的寫法是here

+0

豎起大拇指爲您的答案!這樣做的好處是,所幸屬性的數量是靜態的。我將查看參考文檔,以瞭解將來的分組問題。 – Holtkamp 2009-10-10 15:11:18

相關問題