2010-10-26 22 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