使用 XSLT 根据属性对 XML 元素进行分组 [英] Grouping XML elements based on attributes with XSLT

查看:25
本文介绍了使用 XSLT 根据属性对 XML 元素进行分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一个网页,该网页根据我无权更改的 XML 提要发布演示时间表.

Feed 如下所示:

 <session name="Session 1" starttime="2012-06-06 10:45" endtime="2012-06-06 12:45"><演示文稿名称="演示文稿 1">...演示信息</演示文稿><演示文稿名称="演示文稿 2">...演示信息</演示文稿></会话><session name="Session 2" starttime="2012-06-06 10:45" endtime="2012-06-06 12:45"><演示文稿名称="演示文稿 3">...演示信息</演示文稿><presentation name="Presentation 4">...演示信息</演示文稿></会话><session name="Session 3" starttime="2012-06-07 08:45" endtime="2012-06-07 10:45"><presentation name="Presentation 5">...演示信息</演示文稿><presentation name="Presentation 6">...演示信息</演示文稿></会话></track>

目前,我正在执行一个 <xsl:for-each select="session"> 循环来提取信息,但最终我输出了重复的日期和时间.>

我做实际的日期和时间解析没有问题,所以我目前输出的是2012年6月6日;10:45 没有问题,但由于for-each,每次都被复制,如下:

2012 年 6 月 6 日

10:45-12:45

会话 1:演示 1、演示 2

2012 年 6 月 6 日

10:45-12:45

第 2 部分:演示 3、演示 4

2012 年 6 月 7 日:

8:45-10:45

第 3 部分:演示 5、演示 6

我想要的是以某种方式提取所有常见的日期时间,例如,得到如下输出:

2012 年 6 月 6 日:

10:45-12:45

会话 1:演示 1、演示 2

会话 2:演示 3、演示 4

2012 年 6 月 7 日:

8:45-10:45

第 3 部分:演示 5、演示 6

作为参考,这是我目前的实现:

<h4><!-- 输出到 Month, DD, YYYY --><xsl:call-template name="formatDate"><xsl:with-param name="dateTime" select="@starttime"/></xsl:call-template><h5><!-- 输出时间--><xsl:call-template name="formatTime"><xsl:with-param name="dateTime" select="@starttime"/></xsl:call-template>——<xsl:call-template name="formatTime"><xsl:with-param name="dateTime" select="@endtime"/></xsl:call-template><!-- 会话标题--><h5><xsl:value-of select="@name"/></h5><!-- 演示文稿标题--><xsl:for-each select="presentation"><xsl:value-of select="@name"/><xsl:element name="br"/></xsl:for-each></xsl:for-each>

和日期时间格式化程序:

<xsl:template name="formatDate"><xsl:param name="dateTime"/><xsl:variable name="date" select="substring-before($dateTime, ' ')"/><xsl:variable name="year" select="substring-before($date, '-')"/><xsl:variable name="month" select="number(substring-before(substring-after($date, '-'), '-'))"/><xsl:variable name="day" select="number(substring-after(substring-after($date, '-'), '-'))"/><!-- 输出--><xsl:when test="$month = '1'">一月</xsl:when><xsl:when test="$month = '2'">二月</xsl:when><xsl:when test="$month = '3'">三月</xsl:when><xsl:when test="$month = '4'">四月</xsl:when><xsl:when test="$month = '5'">May</xsl:when><xsl:when test="$month = '6'">六月</xsl:when><xsl:when test="$month = '7'">七月</xsl:when><xsl:when test="$month = '8'">August</xsl:when><xsl:when test="$month = '9'">九月</xsl:when><xsl:when test="$month = '10'">October</xsl:when><xsl:when test="$month = '11'">十一月</xsl:when><xsl:when test="$month = '12'">十二月</xsl:when></xsl:选择><xsl:value-of select="' '"/><xsl:value-of select="$day"/><xsl:value-of select="', '"/><xsl:value-of select="$year"/></xsl:模板><!-- 格式化日期时间--><xsl:template name="formatTime"><xsl:param name="dateTime"/><xsl:value-of select="substring-after($dateTime, ' ')"/></xsl:模板>

解决方案

您想使用 慕尼黑方法.立即将其添加到样式表的根元素中:

<xsl:key name="sessions-by-track-name-starttime-and-endtime" match="/track/session" use="concat(parent::track/@name, '', @starttime, ' ', @endtime)"/>

然后更新您的 XSLT,如下所示:

<xsl:for-each select="session[generate-id() = generate-id(key('sessions-by-track-name-starttime-and-endtime', concat(parent::track/@name, ' ', @starttime, ' ', @endtime))[1])]"><h4><!-- 输出到 Month, DD, YYYY --><xsl:call-template name="formatDate"><xsl:with-param name="dateTime" select="@starttime"/></xsl:call-template><h5><!-- 输出时间--><xsl:call-template name="formatTime"><xsl:with-param name="dateTime" select="@starttime"/></xsl:call-template>——<xsl:call-template name="formatTime"><xsl:with-param name="dateTime" select="@endtime"/></xsl:call-template><xsl:for-each select="key('sessions-by-track-name-starttime-and-endtime', concat(parent::track/@name, ' ', @starttime, ' ', @endtime))"><!-- 会话标题--><h5><xsl:value-of select="@name"/></h5><!-- 演示文稿标题--><xsl:for-each select="presentation"><xsl:value-of select="@name"/><xsl:element name="br"/></xsl:for-each></xsl:for-each></xsl:for-each>

I am working on a webpage that publishes a schedule of presentations based on an XML feed that I don't have access to change.

The feed looks like this:

  <track name="Track 1">
    <session name="Session 1" starttime="2012-06-06 10:45" endtime="2012-06-06 12:45">
      <presentation name="Presentation 1">
        ...presentation info
      </presentation>
      <presentation name="Presentation 2">
        ...presentation info
      </presentation>
    </session>
    <session name="Session 2" starttime="2012-06-06 10:45" endtime="2012-06-06 12:45">
      <presentation name="Presentation 3">
        ...presentation info
      </presentation>
      <presentation name="Presentation 4">
        ...presentation info
      </presentation>
    </session>
    <session name="Session 3" starttime="2012-06-07 08:45" endtime="2012-06-07 10:45">
      <presentation name="Presentation 5">
        ...presentation info
      </presentation>
      <presentation name="Presentation 6">
        ...presentation info
      </presentation>
    </session>
  </track>

At present, I am doing an <xsl:for-each select="session"> loop to pull out information, however that ends with me outputting duplicate dates and times.

I have no problem doing the actual date and time parsing, so I am currently outputting June 6, 2012; 10:45 with no issue, but it is being duplicated each time due to the for-each, as follows:

June 6, 2012

10:45-12:45

Session 1: Presentation 1, Presentation 2

June 6, 2012

10:45-12:45

Session 2: Presentation 3, Presentation 4

June 7, 2012:

8:45-10:45

Session 3: Presentation 5, Presentation 6

What I would like is to somehow pull out all common datetimes, for instance, get output like:

June 6, 2012:

10:45-12:45

Session 1: Presentation 1, Presentation 2

Session 2: Presentation 3, Presentation 4

June 7, 2012:

8:45-10:45

Session 3: Presentation 5, Presentation 6

For reference, here is my current implementation:

<xsl:for-each select="session">
  <h4>
    <!-- output to Month, DD, YYYY -->
    <xsl:call-template name="formatDate">
      <xsl:with-param name="dateTime" select="@starttime" />
    </xsl:call-template>
  </h4>

  <h5>
    <!-- output time -->
    <xsl:call-template name="formatTime">
      <xsl:with-param name="dateTime" select="@starttime" />
    </xsl:call-template> - 
    <xsl:call-template name="formatTime">
      <xsl:with-param name="dateTime" select="@endtime" />
    </xsl:call-template>
  </h5>

  <!-- session title -->
  <h5><xsl:value-of select="@name"/></h5>

  <!-- presentation title -->          
  <xsl:for-each select="presentation">
    <xsl:value-of select="@name"/><xsl:element name="br"/>
  </xsl:for-each>

</xsl:for-each>

And the date-time formatter:

<!-- formatting dateTime -->
<xsl:template name="formatDate">
  <xsl:param name="dateTime" />
  <xsl:variable name="date" select="substring-before($dateTime, ' ')" />
  <xsl:variable name="year" select="substring-before($date, '-')" />
  <xsl:variable name="month" select="number(substring-before(substring-after($date, '-'), '-'))" />
  <xsl:variable name="day" select="number(substring-after(substring-after($date, '-'), '-'))" />

  <!-- output -->
  <xsl:choose>
    <xsl:when test="$month = '1'">January</xsl:when>
    <xsl:when test="$month = '2'">February</xsl:when>
    <xsl:when test="$month = '3'">March</xsl:when>
    <xsl:when test="$month = '4'">April</xsl:when>
    <xsl:when test="$month = '5'">May</xsl:when>
    <xsl:when test="$month = '6'">June</xsl:when>
    <xsl:when test="$month = '7'">July</xsl:when>
    <xsl:when test="$month = '8'">August</xsl:when>
    <xsl:when test="$month = '9'">September</xsl:when>
    <xsl:when test="$month = '10'">October</xsl:when>
    <xsl:when test="$month = '11'">November</xsl:when>
    <xsl:when test="$month = '12'">December</xsl:when>
  </xsl:choose>
  <xsl:value-of select="' '" />
  <xsl:value-of select="$day" />
  <xsl:value-of select="', '" />
  <xsl:value-of select="$year" />
</xsl:template>

<!-- formatting dateTime -->
<xsl:template name="formatTime">
  <xsl:param name="dateTime" />
  <xsl:value-of select="substring-after($dateTime, ' ')" />
</xsl:template>

解决方案

You want to group using the Muenchian method. Add this immediately inside the root element of your stylesheet:

<xsl:key name="sessions-by-track-name-starttime-and-endtime" match="/track/session" use="concat(parent::track/@name, ' ', @starttime, ' ', @endtime)"/>

Then update your XSLT as shown:

<xsl:for-each select="session[generate-id() = generate-id(key('sessions-by-track-name-starttime-and-endtime', concat(parent::track/@name, ' ', @starttime, ' ', @endtime))[1])]">
  <h4>
    <!-- output to Month, DD, YYYY -->
    <xsl:call-template name="formatDate">
      <xsl:with-param name="dateTime" select="@starttime" />
    </xsl:call-template>
  </h4>

  <h5>
    <!-- output time -->
    <xsl:call-template name="formatTime">
      <xsl:with-param name="dateTime" select="@starttime" />
    </xsl:call-template> - 
    <xsl:call-template name="formatTime">
      <xsl:with-param name="dateTime" select="@endtime" />
    </xsl:call-template>
  </h5>

  <xsl:for-each select="key('sessions-by-track-name-starttime-and-endtime', concat(parent::track/@name, ' ', @starttime, ' ', @endtime))">

    <!-- session title -->
    <h5><xsl:value-of select="@name"/></h5>

    <!-- presentation title -->          
    <xsl:for-each select="presentation">
      <xsl:value-of select="@name"/><xsl:element name="br"/>
    </xsl:for-each>

  </xsl:for-each>

</xsl:for-each>

这篇关于使用 XSLT 根据属性对 XML 元素进行分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆