2

我一直在寻找如何访问当前节点,同时使用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。

4

2 回答 2

2

这种转变

<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 方法进行分组——使用复合分组键。

于 2012-06-05T03:24:14.217 回答
0

@Dimitre Novatchev 的回答更为详尽,但我发现了另一种我想分享的可能性。它不依赖于keys,因此更“对新手友好”。另一方面,它也没有解决原来的“访问迭代的当前节点”问题:

<?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>
于 2012-06-05T05:28:59.070 回答