2010-10-26 55 views
1

使用XSLT我試圖找出一個辦法只能發出HTML錶行,當值來自於該換每次最後一次迭代不同,上一次迭代不同循環。基本上,我想讓表格看起來具有分組標題,只需在標題更改後寫出它。我有一點麻煩只能發出一些HTML當一個變量在XSLT

概念上工作了我怎麼能做到這一點考慮一旦它被定義,你不能改變一個變量的值。

<xsl:for-each select="//databaseConstraint/constraint"> 

    <xsl:variable name="caption" select="@caption" /> 

    <tr> 
     <th colspan="2"><xsl:value-of select="$caption" /></th> 
    </tr> 

    ... 

</xsl:for-each > 

更新我下面試過,但我得到一個錯誤:NodeTest這裏

<xsl:for-each select="//databaseConstraint/constraint"> 

    <xsl:variable name="caption" select="@caption" /> 

    <xsl:if test="not(@caption = preceding-sibling::@caption)"> 
    <tr> 
     <th colspan="2"> 
      <xsl:value-of select="$caption" /> 
     </th> 
    </tr> 
    </xsl:if> 

    ... 

</xsl:for-each > 
+1

看到我的答案比簡單一個簡單的解決方案,這應該很好用於大多數用途。 – LarsH 2010-10-26 11:06:13

+0

你寫道:*你介意告訴我該怎麼做*。如果您發佈減少輸入樣本,也許有人可以告訴你如何在「XSLT樣式」(模式匹配和分組)中執行此操作。 – 2010-10-26 12:35:53

+0

好問題,+1。查看我的答案,瞭解適用於任何文檔結構的完整解決方案,並提供詳細解釋。 – 2010-10-26 13:05:38

回答

1
<xsl:if test="not(@caption = preceding-sibling::@caption)"> 

這將測試字幕是否等於一個字幕屬性即上下文節點的兄弟,即你正在處理所述約束元件的兄弟節點。但我懷疑它「失敗」,因爲語法錯誤,因爲標題步驟有兩個軸:preceding-sibling::attribute::(這是@的縮寫)。

你可能想要的是

<xsl:if test="not(@caption = preceding-sibling::constraint[1]/@caption)"> 

這將做你想做的,它比Muenchian簡單,它可能快速就夠了,如果瀏覽器的XPath實現是體面的,因爲它只需要測試一個其他節點,而不是所有先前的約束節點。

如果這種策略對於您的目的不夠快,如果你有很多數據,你可以使用Muenchian分組,就像@Frédéric說的那樣。

此外:[1][position() = 1]的縮寫。這裏的意思是,在=的右側,我們只有在當前元素之前的約束。如果我們省略了[1],我們將比較當前元素的@caption值和前面的兄弟約束元素中的全部的@captions。

它認識到XPath的=運營商(有機會時)在節點集工作,而不只是單值或節點是非常重要的。所以A = B,其中A和B是節點集,如果有節點集A的任何成員等於節點集B的任何成員,則返回true。這更像是SQL中的連接。這是一個強大的操作,但你必須知道它在做什麼。

另一個細節...爲什麼[1]產生緊接在之前的約束元素而不是文檔中的第一個?因爲position()反映當前軸的方向,在本例中爲preceding-sibling。如XPath spec所述,

An axis that only ever contains the context node or nodes that are before the context node in document order is a reverse axis. Thus, the ancestor, ancestor-or-self, preceding, and preceding-sibling axes are reverse axes; all other axes are forward axes. ...

The proximity position of a member of a node-set with respect to an axis is defined to be the position of the node in the node-set ordered in document order if the axis is a forward axis and ordered in reverse document order if the axis is a reverse axis. The first position is 1.

HTH。

+1

+1中提到的語法錯誤說明。 – 2010-10-26 12:36:51

+0

誰投下了這個答案,請有禮貌留下建設性的意見。 – LarsH 2010-10-26 13:46:57

+0

我也因爲*素描*一個可能的解決方案而被壓倒了。 「嘗試了一些不起作用的東西」=> vote--;謝謝闡述相同的想法。 – devio 2010-10-26 17:40:22

0

預計這並不容易使用XSLT 1.0做。如果您的實現支持XSLT 2.0功能,請使用xsl:for-each-group。如果您遇到1.0,請查看this Muenchian implementation using keys

+0

謝謝。它應該可以在大多數瀏覽器中工作,那麼XSLT 2.0會如何呢? – 2010-10-26 09:28:12

+3

是的,它的確如此。直到今天,Internet Explorer和Firefox都不支持XSLT 2.0。 – 2010-10-26 09:35:17

0

您可以嘗試比較使用前或兄弟姐妹先行當前節點(或它的屬性之一)與之前的節點,並只顯示,如果目前的!=前面的桌子上。請參閱XPath Axes

+0

你介意告訴我該怎麼做?我試過上面的編輯,但失敗了。 – 2010-10-26 09:39:13

+0

@Matthew:良好的經驗法則:當你說某件事情失敗或不起作用時,請告訴它做了什麼。 – LarsH 2010-10-26 10:58:54

+0

@LarsH我做過了,看看我在編輯 – 2010-10-27 01:23:42

1

I'm trying to work out a way to only emit a HTML table row when a value is different from the last iteration of the for-each loop

這個答案字面上。如果你想執行分組瞭解Muenchian grouping

這種轉變

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:variable name="vConstraints" 
     select="//databaseConstraint/constraint"/> 
    <table> 
     <xsl:for-each select="$vConstraints"> 
     <xsl:variable name="vCaption" select="@caption" /> 
     <xsl:variable name="vPos" select="position()"/> 

     <xsl:if test="not($vCaption = $vConstraints[$vPos -1]/@caption)"> 
      <tr> 
       <th colspan="2"><xsl:value-of select="$vCaption" /></th> 
      </tr> 
     </xsl:if> 
     </xsl:for-each> 
    </table> 
</xsl:template> 
</xsl:stylesheet> 

當下面的XML文檔應用:

<t> 
<a> 
<databaseConstraint> 
    <constraint caption="Simple Constraint"/> 
</databaseConstraint> 
<databaseConstraint> 
    <constraint caption="Simple Constraint"/> 
</databaseConstraint> 
</a> 
<b> 
<databaseConstraint> 
    <constraint caption="Complex Constraint"/> 
</databaseConstraint> 
</b> 
</t> 

產生想要的,正確的結果

<table> 
    <tr> 
     <th colspan="2">Simple Constraint</th> 
    </tr> 
    <tr> 
     <th colspan="2">Complex Constraint</th> 
    </tr> 
</table> 

請注意

  1. 改造工程,即使在情況下,當<constraint>元素不是同級,或者即使他們中的一些祖先/彼此的後代。

  2. 在這種情況下,有必要收集所有<constraint>元件在一個變量中,並rememper當前<constraint>元件position(),使得有可能將其與<constraint>元件在先前位置比較節點集。

+0

+1我認爲,作爲一個公平的字面答案,這是一個很好的答案。 – 2010-10-26 19:08:25

+0

這非常有用。請記住它。 – 2010-10-27 01:22:51

+0

@Matthew:不客氣:) – 2010-10-27 01:30:36