我喜歡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}
我能做到這一點?
我喜歡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}
我能做到這一點?
該轉化短期(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()],'}}','
')"/>
<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()],'}}','
')"/>
</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}
有很好的方式做到這一點,並有可惡的做法。我沒有足夠的時間去思考的一個很好的方法,它如何搶你?:
<?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 > 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) < 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() > 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}的情況,那麼它會調用一個遞歸模板來查找並打印結束。
這裏是一些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>} </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}
我能想出的最簡單的樣式表解決您的問題:
<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>} </xsl:text>
</xsl:template>
<xsl:template match="td"/>
</xsl:stylesheet>
說明:首先,我們匹配每一個td
其直接前置兄弟本身不是一個class
一個td
屬性等於x
。這些是開始節點,所以我們使用它們的值作爲每個序列的開始。
對於我們使用的下一個td
序列的末端,不具有作爲其緊跟着兄弟另一個td
其class
是x
。
所有其他節點都被忽略。
你想用XSLT 2.0或1.0解決這個問題嗎? 2.0有''這樣應該很容易。 –
2012-07-12 13:33:41
@MartinHonnen我使用xslt 1.0 – 2012-07-12 13:39:59