Webtogether

Simple and Nice Index File

You can read about the original snif here. The basic idea was to lift the burden of generating the schnik-schnak from the server. For that purpose the server is now sending a xml representation as seen in the DataSource chapter. The whole application logic (if we can call it application) is done via XSLT. In simple terms it's snif in XSLT. On the other hand the CSS styling is the same, no changes there. But snif looks cute anyway.

Transformation

There are three versions of the transformation provided. The simple one which really is only a table (even withoud border). The second version is the same as snif. The third version adds small things which are not in the original but do not provide significant improvement. Below I want to present some implementation details of the XSLT.

Day of the week

The algorithm is documented very well. below you can see the xslt implementation which is not terribly difficult but was fun to code. First you have an xml table which assigns the day string to the given number ( 0=Sunday, 1=Monday etc.) The day2string function will convert the given number to the day name and convert the day name to the given language set for the script. The call of the day2string contains the computation for the day of week.

...
  <day>
    <str xml:lang="en" number="0">Sunday</str>
    <str xml:lang="en" number="1">Monday</str>
    <str xml:lang="en" number="2">Tuesday</str>
    <str xml:lang="en" number="3">Wednesday</str>
    <str xml:lang="en" number="4">Thursday</str>
    <str xml:lang="en" number="5">Friday</str>
    <str xml:lang="en" number="6">Saturday</str>
  </day>
...
<xsl:template name="day2string">
  <xsl:param name="daynum"/>
  <xsl:call-template name="getLocalizedString">
    <xsl:with-param name="stringName" select="document('')/xsl:stylesheet/cfg:data/day/str[@number=$daynum][1]"/>
  </xsl:call-template>
</xsl:template>
...
<xsl:call-template name="day2string">
  <xsl:with-param name="daynum" select="round(($day+(2*$month)+((6*($month+1)) div 10)+$year+($year div 4)-($year div 100)+($year div 400)+1) mod 7)"/>
</xsl:call-template>
...

And below you can see how the input in form of a date in the xml data is converted into the string which contains also the day name. This can be achieved on the unix systems also by doing a ls with the appropriate switch (you see the day name) but I'm not sure if it is universal. But now as it is implemented in the XSLT it works anywhere. Below you can see how it looks on the screen.

snif_day2string.PNG

Internationalisation

The internationalisation happens in the xslt. Not only can you switch the language instantly it will also inflate your XSLT ! Well you could work out some scheme to include only the required language and have every translation in a separate xml file. The idea for this kind of localization comes from here and I have seen something similar also here. Basically you have a static xml embedded in the xslt and use a template to extract the translation based on the set language. The english strings are used as defaults, this means when no value for the key is found then the key itself is returned (this is apparent from the template).

...
<xsl:param name="Lang" select="list/@l"/>
 
<!-- lookup tables -->
<cfg:data>
  <lng>
    <!-- german strings -->
    <str xml:lang="de-DE" name="Permission">Zugriffsrechte</str>
    <str xml:lang="de-DE" name="Subdirs">Unterverzeichnisse</str>
    <str xml:lang="de-DE" name="Owner">Besitzer</str>
...
    <!-- slovak strings -->
    <str xml:lang="sk-SK" name="Permission">Prava</str>
    <str xml:lang="sk-SK" name="Subdirs">Podadresare</str>
    <str xml:lang="sk-SK" name="Owner">Vlastnik</str>
    <str xml:lang="sk-SK" name="Group">Skupina</str>
...
<xsl:template name="getLocalizedString">
  <xsl:param name="stringName"/>
  <xsl:variable name="str" select="document('')/xsl:stylesheet/cfg:data/lng/str[@name=$stringName]"/>
  <xsl:choose>
    <xsl:when test="$str[lang($Lang)]">
      <xsl:value-of select="$str[lang($Lang)][1]"/>
    </xsl:when>
    <xsl:when test="$str[lang($PrimaryLang)]">
      <xsl:value-of select="$str[lang($PrimaryLang)][1]"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$stringName"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
...

The internationalisation then looks like this on the screen. The english, german and slovak version.

snif_internationalisation.PNG

File Size

The file size is shown in TB, GB, MB, KB, B depending on the size. This is done by a template. The original size in bytes is shown when your cursor hovers above the "truncated" size. The formatnumber template will place commas after every three digits except the last three ones. The size template simply divides the byte size and depending on the result assigns the proper size postfix.

...
<xsl:template name="formatnumber">
  <xsl:param name="bytesize"/>
  <xsl:choose>
    <xsl:when test="string-length($bytesize) &gt; 3">
      <xsl:call-template name="formatnumber">
        <xsl:with-param name="bytesize" select="substring($bytesize,1,string-length($bytesize)-3)"/>
      </xsl:call-template>
      <xsl:text>,</xsl:text>
      <xsl:value-of select="substring($bytesize,string-length($bytesize)-2)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$bytesize"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
 
<xsl:template name="size">
  <xsl:param name="bytesize"/>
  <span>
    <xsl:attribute name="title">
      <xsl:call-template name="formatnumber">
        <xsl:with-param name="bytesize" select="$bytesize"/>
      </xsl:call-template>
      <xsl:text> bytes</xsl:text>
    </xsl:attribute>
    <xsl:choose>
      <xsl:when test="$bytesize &gt; 1099511627776">
        <xsl:value-of select="floor($bytesize div (109951162777.6)) div 10"/>
        <xsl:text> TB</xsl:text>
      </xsl:when>
      <xsl:when test="$bytesize &gt; 1073741824">
        <xsl:value-of select="floor($bytesize div 107374182.4) div 10"/>
        <xsl:text> GB</xsl:text>
      </xsl:when>
      <xsl:when test="$bytesize &gt; 1048576">
        <xsl:value-of select="floor($bytesize div (104857.6)) div 10"/>
        <xsl:text> MB</xsl:text>
      </xsl:when>
      <xsl:when test="($bytesize div 1024) &gt; 1">
        <xsl:value-of select="floor($bytesize div 102.4) div 10"/>
        <xsl:text> KB</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$bytesize"/>
        <xsl:text>  B</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </span>
</xsl:template>
...

The resulting effect is then seen on the picture below.

snif_filesize.PNG

The rest

Additionally the small icons for the different file types are directly embedded in the xslt script. Download of the file is working too. Sorting is done in the xslt script even when the sorting parameters are supplied to the php script.

ToDo

  • You can place the xml template and the xslt into hashes and thus get the "one file" approach which the original snif has, see directory for inspiration.
  • You can apply the path of the script as the prefix of the supplied path. That would prevent the user to ascend above the directory where script is placed.
  • to add for example the descript.ion functionality you can add metadata in the .metadata directory.
  • It would be possible to generate the metadata with the mediainfo tool (generate once or on the fly, your choice). That could look like this:
snif_comment.PNG
  • Of course the two points above will require the modification of the xslt to actually show the additional data

Use

In the file section you can download the lsxml.php, lsxml.xml and xsl scripts. Just place them in a directory and invoke like below

https://localhost/directory/lsxml.php?d=/my/downloaded/files/&s=n&o=a&x=snif

where localhost should be the host on which the apache/php/script is running. The directory is the relative path to the document root of the apache web server where you have placed the script.
There are three xslt's supplied. One called default (very simple), snif and candy. You can use the x switch on the command line to choose which xslt should be used.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.