我想知道如何在使用xsL:for-each
迭代节点集合时访问当前节点。这是我的 XML:
<events>
<event>
<date>
<year>2012</year>
<month>July</month>
</date>
<description>...</description>
</event>
<!-- more events -->
</events>
我试图实现的是这样的HTML表示:
<h2>2012</h2>
<dl>
<dt>July</dt>
<dd>One of these for every event with year=2012 and month=July</dd>
<dt>August</dt>
<!-- ... -->
</dl>
<h2>2013</h2>
<!-- ... -->
我正在使用 XPath 表达式来获取所有不同的年份,然后迭代它们,调用名为 year
的模板,其中包含参数 $year
和 $events
。获得$year
的价值很容易,但我正在努力寻找合适的事件。以下内容不起作用,可能是因为第二个谓词中的.
是指正在测试谓词的event
。但是如何访问那里的year
呢?
<xsl:template match="events">
<xsl:for-each select="event[not(date/year=preceding-sibling::event/date/year)]/date/year">
<xsl:call-template name="year">
<xsl:with-param name="year" select="." />
<xsl:with-param name="events" select="event[date/year=.]" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
提前非常感谢!
PS:必须与 XPath 和 XSLT 1.0 一起使用。
此转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kYear" match="year" use="."/>
<xsl:key name="kEventByMonthYear" match="event"
use="string(date)"/>
<xsl:key name="kMonthByMonthYear" match="month"
use="string(..)"/>
<xsl:key name="kMonthByYear" match="month"
use="../year"/>
<xsl:template match="/*">
<xsl:for-each select=
"*/date/year
[generate-id() = generate-id(key('kYear', .)[1])]
">
<h2><xsl:value-of select="."/></h2>
<dl>
<xsl:apply-templates select=
"key('kMonthByYear', current())
[generate-id()
=
generate-id(key('kMonthByMonthYear',
string(..)
)[1]
)
]"/>
</dl>
</xsl:for-each>
</xsl:template>
<xsl:template match="month">
<dt><xsl:value-of select="."/></dt>
<xsl:for-each select=
"key('kEventByMonthYear', string(current()/..))">
<dd><xsl:value-of select="description"/></dd>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
应用于以下 XML 文档时:
<events>
<event>
<date>
<year>2012</year>
<month>January</month>
</date>
<description>Jan1</description>
</event>
<event>
<date>
<year>2012</year>
<month>January</month>
</date>
<description>Jan2</description>
</event>
<event>
<date>
<year>2012</year>
<month>March</month>
</date>
<description>Mar1</description>
</event>
<event>
<date>
<year>2012</year>
<month>March</month>
</date>
<description>Mar2</description>
</event>
<event>
<date>
<year>2012</year>
<month>March</month>
</date>
<description>Mar3</description>
</event>
<event>
<date>
<year>2012</year>
<month>July</month>
</date>
<description>Jul1</description>
</event>
<event>
<date>
<year>2012</year>
<month>July</month>
</date>
<description>Jul2</description>
</event>
<event>
<date>
<year>2012</year>
<month>September</month>
</date>
<description>Sep1</description>
</event>
<event>
<date>
<year>2012</year>
<month>October</month>
</date>
<description>Oct1</description>
</event>
<event>
<date>
<year>2012</year>
<month>October</month>
</date>
<description>Oct2</description>
</event>
<event>
<date>
<year>2012</year>
<month>November</month>
</date>
<description>Nov1</description>
</event>
<event>
<date>
<year>2012</year>
<month>November</month>
</date>
<description>Nov2</description>
</event>
<event>
<date>
<year>2012</year>
<month>December</month>
</date>
<description>Dec1</description>
</event>
<event>
<date>
<year>2012</year>
<month>December</month>
</date>
<description>Dec2</description>
</event>
<event>
<date>
<year>2012</year>
<month>December</month>
</date>
<description>Dec3</description>
</event>
<event>
<date>
<year>2013</year>
<month>January</month>
</date>
<description>Jan1</description>
</event>
<event>
<date>
<year>2013</year>
<month>January</month>
</date>
<description>Jan2</description>
</event>
</events>
产生所需的正确结果:
<h2>2012</h2>
<dl>
<dt>January</dt>
<dd>Jan1</dd>
<dd>Jan2</dd>
<dt>March</dt>
<dd>Mar1</dd>
<dd>Mar2</dd>
<dd>Mar3</dd>
<dt>July</dt>
<dd>Jul1</dd>
<dd>Jul2</dd>
<dt>September</dt>
<dd>Sep1</dd>
<dt>October</dt>
<dd>Oct1</dd>
<dd>Oct2</dd>
<dt>November</dt>
<dd>Nov1</dd>
<dd>Nov2</dd>
<dt>December</dt>
<dd>Dec1</dd>
<dd>Dec2</dd>
<dd>Dec3</dd>
</dl>
<h2>2013</h2>
<dl>
<dt>January</dt>
<dd>Jan1</dd>
<dd>Jan2</dd>
</dl>
解释:
正确使用Muenchian方法进行分组 - 使用复合分组键。
瓦切夫的答案是更详细的答案,但我发现了另一种我想分享的可能性。它不依赖于key
,因此对新手更"友好"。另一方面,它也不能解决原始的"访问迭代的当前节点"问题:
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="events">
<xsl:for-each select="event[not(date/year=preceding-sibling::event/date/year)]/date/year">
<xsl:call-template name="year">
<xsl:with-param name="year" select="." />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="year">
<xsl:param name="year" />
<h2><xsl:value-of select="$year" /></h2>
<dl class="dl-horizontal">
<xsl:for-each select="//event[date/year=$year][not(date/month=preceding-sibling::event[date/year=$year]/date/month)]/date/month">
<xsl:call-template name="month">
<xsl:with-param name="month" select="." />
<xsl:with-param name="year" select="$year" />
</xsl:call-template>
</xsl:for-each>
</dl>
</xsl:template>
<xsl:template name="month">
<xsl:param name="month" />
<xsl:param name="year" />
<dt><xsl:value-of select="$month" /></dt>
<xsl:for-each select="//event[date/year=$year][date/month=$month]">
<xsl:call-template name="event">
<xsl:with-param name="event" select="." />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="event">
<xsl:param name="event" />
<dd><xsl:copy-of select="description/node()" /></dd>
</xsl:template>
</xsl:transform>