使用XSLT从XML节点列表创建HTML

时间:2011-03-16 00:16:09

标签: xslt

我是XSLT上的菜鸟。 我有一个XML,其中t节点后跟其他节点,然后另一个t节点可能再次出现,然后再次出现节点,依此类推

<t />
<n1 />
<n2 />
..

<t/>
<n3 />
<n4 />
...

我需要将此XML转换为HTML,其中t个节点将其后的所有节点包装到下一个t节点

<div class='t'>
   <div class='n1'/>
   <div class='n2'/>
    ...
</div>

<div class='t'>
   <div class='n3'/>
   <div class='n4'/>
    ...
</div>

我很难实现这一点。 任何想法\提示?

谢谢!

2 个答案:

答案 0 :(得分:6)

这是对邻居的分组。有很多解决方案:

确认这个良好的输入:

<root>
    <t />
    <n1 />
    <n2 />
    <t/>
    <n3 />
    <n4 />
</root>

XSLT 1.0:遍历跟随轴

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="root">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]" mode="group"/>
            <xsl:apply-templates select="t"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="t">
        <div class="t">
            <xsl:apply-templates select="following-sibling::node()[1]"
                                 mode="group"/>
        </div>
    </xsl:template>
    <xsl:template match="t" mode="group"/>
    <xsl:template match="node()" mode="group">
        <xsl:apply-templates select="."/>
        <xsl:apply-templates select="following-sibling::node()[1]"
                             mode="group"/>
    </xsl:template>
    <xsl:template match="*[starts-with(name(),'n')]">
        <div class="{name()}"/>
    </xsl:template>
</xsl:stylesheet>

XSLT 1.0:密钥

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:key name="kNodeByMark"
             match="node()[../t][not(self::t)]"
             use="generate-id((..|preceding-sibling::t[1])[last()])"/>
    <xsl:template match="root">
        <xsl:copy>
            <xsl:apply-templates select="key('kNodeByMark',generate-id())"/>
            <xsl:for-each select="t">
                <div class="t">
                    <xsl:apply-templates
                         select="key('kNodeByMark',generate-id())"/>
                </div>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[starts-with(name(),'n')]">
        <div class="{name()}"/>
    </xsl:template>
</xsl:stylesheet>

XSLT 2.0:for-each-group指令

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="root">
        <xsl:copy>
            <xsl:apply-templates select="node()[../t[1] >> .]"/>
            <xsl:for-each-group select="node()" group-starting-with="t">
                <div class="t">
                    <xsl:apply-templates 
                         select="current-group()[position()>1]"/>
                </div>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[starts-with(name(),'n')]">
        <div class="{name()}"/>
    </xsl:template>
</xsl:stylesheet>

输出:

<root>
    <div class="t">
        <div class="n1" />
        <div class="n2" />
    </div>
    <div class="t">
        <div class="n3" />
        <div class="n4" />
    </div>
</root>

编辑:遍历跟踪轴重构,看起来像其他解决方案。剥离身份规则。

答案 1 :(得分:0)

请参阅我关于您的问题的说明,关于“哪个XSLT版本?”。如果您的目标版本支持分组,请在此处查看其他答案,因为这更容易理解,并且几乎肯定会在任何XSLT处理器上执行得更好。如果您不确定,我建议使用像这样的1.0解决方案。

你可以使用与大多数XSLT处理器一样的“XML片段”来完成它,但我在你的XML中添加了一个“root”元素,以减少回答你问题时的某些未知数。

在下面的解决方案中,我试图在XSLT的形状和您想要的输出形状之间保持直接关联。在我看来,这使得维护/理解更容易,至少对于较小的样式表而言。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/root">
    <xsl:for-each select="t">
      <div class='t'>
        <xsl:for-each select="following-sibling::*[count(preceding-sibling::t)=(count(current()/preceding-sibling::t) + 1) and not(self::t)]">
          <div class='{name()}' />
        </xsl:for-each>
      </div>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

“follow-sibling :: * [count(previous-sibling :: t)=(count(current()/ preceding-sibling :: t)+ 1)的右侧而不是(self :: t)]“可以简化,我敢肯定,使用类似”current():: position()“(这是无效的,fyi),但我生锈了,不记得一些别名语法。

这基本上说:1)评估每一个T. 2)选择前面有相同数量T的元素,作为我们当前评估的T的索引。

请注意,您可能已尝试在程序上进行迭代,并发现无法存储在XSLT中找到的最后一个值。或者您已经发现可以,但只能使用嵌套模板。您正在执行的这种类型的支点有许多XSLT新手遇到障碍,所以不要感觉不好。