Displaying a timetable with XSLT

2019-07-07 04:59发布

问题:

I'm trying to display a university courses timetable using XSLT. My DTS looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT timetable (day,day,day,day,day,day,day)>
<!ELEMENT day (session)*>
<!ELEMENT session (begin,end,(course?))>
<!ELEMENT course (#PCDATA)>
<!ELEMENT begin (#PCDATA)>
<!ELEMENT end (#PCDATA)>

I want to display all the courses in a Day/Hour table that looks something like this (excuse the horrible design):

Trouble is, I want to do a for each clause, but just on regular numbers, not on parts of the xml. Is that possible with XSLT? For example, it would probably look something like this:

/* for each time = 8..17, do: */
    <xsl:for-each select="timetable/day">
        <xsl:value-of select="session[[begin&lt;/*time*/ or begin=/*time*/]/course" />
    </xsl:for-each>

回答1:

You can use recursion

<xsl:template name="for_i_from_8_to_17">
    <xsl:param name="i">8</xsl:param> <!-- initial value -->
    <!-- do what you have to do -->
    <xsl:if test="not($i = 17)">
        <xsl:call-template name="for_i_from_8_to_17">
            <xsl:with-param name="i">
        <xsl:value-of select="$i + 1">
        </xsl:with-param>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

(slightly adapted from xsl-list@mulberrytech.com)



回答2:

in XSLT 2.0:

<xsl:variable name="timetable" select="timetable">
<table>
  <thead>
     .. output the table heading ..
  </thead>
  <tbody>
    <xsl:for-each select="8 to 17">
    <tr>
      <xsl:variable name="hour" select="."/>
      <td><xsl:value-of select="$hour, '-', $hour+1"/></td>          
      <xsl:for-each select="$timetable/day">
        <td><xsl:value-of 
            select="session[begin lt $hour+1 and end gt $hour]/course"/>
        </td>
      </xsl:for-each>
    </xsl:for-each>
  </tbody>
</table> 

plus a bit of work on the formatting.



回答3:

You can use recursion:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <html>

      <head>
        <style type="text/css">td{border:solid 1px black} table{border-collapse:collapse}</style>
      </head>

      <table>
        <xsl:call-template name="for">
          <xsl:with-param name="count" select="10"/>
        </xsl:call-template>
      </table>
    </html>
  </xsl:template>

  <xsl:template name="for">
    <xsl:param name="i" select="0"/>
    <xsl:param name="count"/>

    <xsl:if test="$i &lt; $count">
      <tr>
        <td>
          <xsl:value-of select="concat($i + 8, ':00 - ', $i + 9, ':00')"/>
        </td>
      </tr>

      <xsl:call-template name="for">
        <xsl:with-param name="i" select="$i + 1"/>
        <xsl:with-param name="count" select="$count"/>
      </xsl:call-template>
    </xsl:if>

  </xsl:template>

</xsl:stylesheet>

Output:



回答4:

You would require to have 2 for each loops. one to iterate over the days of week and one for the hours of the day. The hours of the day could be solved with XSLT 2.0 easily like this:

<xsl:for-each select="8 to 17">
   <!-- do your stuff -->
   <xsl:value-of select="." /> <!-- dot represents a number from the range -->
</xsl:fo-each>

See this for a complete coverage of sequences and ranges.



标签: xml xslt xpath