2012-07-12 58 views
2

我喜歡XMLXSL數連續節點

<tr> 
<td class="x">1</td> 
<td class="x">2</td> 
<td>3</td> 
<td class="x">4</td> 
<td class="x">5</td> 
<td class="x">6</td> 
<td class="x">7</td> 
</tr> 

,我想使用XSL的結果是:

\cont{1-2} 
\cont{4-7} 

我能做到這一點?

+0

你想用XSLT 2.0或1.0解決這個問題嗎? 2.0有''這樣應該很容易。 – 2012-07-12 13:33:41

+0

@MartinHonnen我使用xslt 1.0 – 2012-07-12 13:39:59

回答

2

該轉化短期(25行)和高效(使用密鑰):

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

<xsl:key name="kFollowing" match="td[@class='x']" 
    use="concat(generate-id(..), 
       '+',generate-id(preceding-sibling::* 
           [not(self::td and @class='x')][1]) 
      )"/> 

<xsl:template match="/*"> 
    <xsl:variable name="vGroup" 
     select="key('kFollowing', concat(generate-id(),'+'))"/> 
    <xsl:value-of select= 
    "concat('\cont{{',$vGroup[1],'-',$vGroup[last()],'}}','&#xA;')"/> 
    <xsl:apply-templates/> 
</xsl:template> 

<xsl:template match="*/*"> 
    <xsl:variable name="vGroup" select= 
    "key('kFollowing', concat(generate-id(..),'+', generate-id()))"/> 
    <xsl:value-of select= 
    "concat('\cont{{',$vGroup[1],'-',$vGroup[last()],'}}','&#xA;')"/> 
</xsl:template> 

<xsl:template match="td[@class='x']|text()"/> 
</xsl:stylesheet> 

當所提供的XML文檔應用:

<tr> 
    <td class="x">1</td> 
    <td class="x">2</td> 
    <td>3</td> 
    <td class="x">4</td> 
    <td class="x">5</td> 
    <td class="x">6</td> 
    <td class="x">7</td> 
</tr> 

有用,正確結果產生:

\cont{1-2} 
    \cont{4-7} 
1

有很好的方式做到這一點,並有可惡的做法。我沒有足夠的時間去思考的一個很好的方法,它如何搶你?:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common"> 
<xsl:output method="text" indent="no"/> 

<xsl:template match="/tr"> 
    <xsl:for-each select="td[@class='x']"> 
     <xsl:variable name="currentNum" select="number(text())"/> 
     <xsl:variable name="prevNum" select="number(preceding-sibling::td[@class='x'][1]/text())"/> 
     <xsl:if test="($currentNum - 1) != $prevNum and $currentNum &gt; 0 and following-sibling::td[@class='x']"> 
      <xsl:variable name="following" select="following-sibling::td[@class='x']"/> 
      <xsl:if test="number($following[1]/text()) = ($currentNum + 1)"> 
      \cont{<xsl:value-of select="$currentNum"/>-<xsl:call-template name="findend"> 
        <xsl:with-param name="start" select="$currentNum"/> 
       <xsl:with-param name="nodes" select="$following"/> 
       </xsl:call-template>} 
      </xsl:if> 
     </xsl:if> 
    </xsl:for-each>  
</xsl:template> 

<xsl:template name="findend"> 
    <xsl:param name="nodes"/> 
    <xsl:param name="start"/> 
    <xsl:variable name="current" select="number($nodes[1]/text())"/> 
    <xsl:choose> 
     <xsl:when test="count($nodes) &lt; 2"> 
      <xsl:value-of select="$current"/> 
     </xsl:when> 
     <xsl:when test="number($nodes[2]/text()) != ($current + 1)"> 
      <xsl:value-of select="$current"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:call-template name="findend"> 
       <xsl:with-param name="nodes" select="$nodes[position() &gt; 1]"/> 
       <xsl:with-param name="start" select="$current"/> 
      </xsl:call-template> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

</xsl:stylesheet> 

輸出

\cont{1-2} 
\cont{4-7} 

我的假設是,如果你只有一個號碼,你沒我們不想繼續下去,所以你不要繼續,並且他們必須按順序排列,並且必須在class ='x'中。

有了更多時間,你可以想出更漂亮的東西!

作爲一個解釋,它通過尋找一個td [@ class ='x']誰的數字不等於前一個+1(即沒有數字或它不是連續的)。如果它找到一個,它檢查下一個數字是這個數字+1,爲了避免連續{1-1}的情況,那麼它會調用一個遞歸模板來查找並打印結束。

1

這裏是一些XSLT 1.0方法使用鍵和模式(但這些主要是爲了避免複雜的模板匹配模式):

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

<xsl:output method="text"/> 

<xsl:key name="k1" 
    match="td[@class = 'x'][preceding-sibling::*[1][self::td[@class = 'x']]]" 
    use="generate-id(
     preceding-sibling::td[ 
      @class = 'x' and 
      not(preceding-sibling::*[1][self::td[@class = 'x']]) 
     ][1] 
     )"/> 

<xsl:template match="tr"> 
    <xsl:apply-templates select="td[@class = 'x' and not(preceding-sibling::*[1][self::td[@class = 'x']])]" mode="start"/> 
</xsl:template> 

<xsl:template match="td[@class = 'x']" mode="start"> 
    <xsl:text>\cont{</xsl:text> 
    <xsl:value-of select="."/> 
    <xsl:text>-</xsl:text> 
    <xsl:apply-templates select="key('k1', generate-id())[last()]" mode="end"/> 
</xsl:template> 

<xsl:template match="td[@class = 'x']" mode="end"> 
    <xsl:value-of select="."/> 
    <xsl:text>}&#10;</xsl:text> 
</xsl:template> 

</xsl:stylesheet> 

即樣式表中,當上

<tr> 
<td class="x">1</td> 
<td class="x">2</td> 
<td>3</td> 
<td class="x">4</td> 
<td class="x">5</td> 
<td class="x">6</td> 
<td class="x">7</td> 
</tr> 

輸出施加

\cont{1-2} 
\cont{4-7} 
1

我能想出的最簡單的樣式表解決您的問題:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="td[not(preceding-sibling::*[1][self::td][@class='x'])]"> 
     <xsl:text>\cont{</xsl:text> 
     <xsl:value-of select="."/> 
     <xsl:text>-</xsl:text> 
     <xsl:value-of select="following-sibling::td[ 
       not(following-sibling::*[1][self::td][@class='x'])][1]"/> 
     <xsl:text>}&#10;</xsl:text> 
    </xsl:template> 
    <xsl:template match="td"/> 
</xsl:stylesheet> 

說明:首先,我們匹配每一個td其直接前置兄弟本身不是一個class一個td屬性等於x。這些是開始節點,所以我們使用它們的值作爲每個序列的開始。

對於我們使用的下一個td序列的末端,不具有作爲其緊跟着兄弟另一個tdclassx

所有其他節點都被忽略。