XML结构:
<units>
<unit>
<lesson>
<name>Sample 1</name>
<sections>
<section type="IN">
<title> Sample Title 1 </title>
</section>
</sections>
</lesson>
<lesson>
<name>Sample 2</name>
<sections>
<section type="OF">
<title> Sample Title 2 </title>
</section>
</sections>
</lesson>
<lesson>
<name>Sample 3</name>
<sections>
<section type="IN">
<title> Sample Title 3</title>
</section>
</sections>
</lesson>
<lesson>
<name>Sample 4</name>
<sections>
<section type="AS">
<title> Sample Title 4</title>
</section>
</sections>
</lesson>
<lesson>
<name>Sample 5</name>
<sections>
<section type="IN">
<title> Sample Title 5</title>
</section>
</sections>
</lesson>
</unit>
</units>
我的要求是获取title元素的值并显示如下(分组相似数据和显示)
IN:
Sample Title 1
Sample Title 3
Sample Title 5
OF:
Sample Title 2
AS:
Sample Title 5
我使用了follow-sibling选项来获得预期的输出。由于XML结构很庞大(我只粘贴了代码片段),因此无法在XSLT中使用../../和所有内容对路径进行硬编码。请帮助我获得预期的输出。
答案 0 :(得分:3)
使用分组比使用任何一个兄弟轴更好地解决这个问题:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:key name="bySectionType" match="section" use="@type" />
<xsl:template match="/">
<xsl:apply-templates select="units/unit/lesson/sections/section" />
</xsl:template>
<xsl:template match="section" />
<xsl:template
match="section[generate-id()=
generate-id(key('bySectionType', @type)[1])]">
<xsl:value-of select="concat(@type, ':
')" />
<xsl:apply-templates select="key('bySectionType', @type)" mode="out" />
</xsl:template>
<xsl:template match="section" mode="out">
<xsl:value-of select="concat(normalize-space(title), '
')" />
</xsl:template>
</xsl:stylesheet>
输出:
IN:
Sample Title 1
Sample Title 3
Sample Title 5
OF:
Sample Title 2
AS:
Sample Title 4
为了完整性,以下样式表使用preceding
和following
轴获得相同的结果:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:apply-templates select="units/unit/lesson/sections/section" />
</xsl:template>
<xsl:template match="section" />
<xsl:template
match="section[not(preceding::section[@type=current()/@type])]">
<xsl:value-of select="concat(@type, ':
')" />
<xsl:apply-templates select=".|following::section[@type=current()/@type]"
mode="out" />
</xsl:template>
<xsl:template match="section" mode="out">
<xsl:value-of select="concat(normalize-space(title), '
')" />
</xsl:template>
</xsl:stylesheet>
这是一种效率低得多的解决方案。解决这个问题的常用方法是使用Muenchian方法进行分组,如上所示。
答案 1 :(得分:1)
以下是XSLT 2.0中的解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each-group select="//section" group-by="@type">
<xsl:value-of select="@type, ':
'" separator=""/>
<xsl:value-of select="current-group()/title" separator="
" />
<xsl:value-of select="'
'"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>