tags:

views:

2440

answers:

5

Hi there

I have an issue about XSLT. In my CMS it is posible to create a new article, and choose an image to be shown on that article. When an image is choosen, there will automatically be created a thumbnail of the image as well.

If we say that the uploaded image is called: image.jpg then the thumbnail will automatically be named image_thumbnail.jpg

I would now like to use the thumbnail image, everywhere on the website, where the article is mentioned, except on the article it self (where the original big image will be shown).

But how can I do that?

I imaging it as if I could get the original name of the image, and then split it up before the .jpg (or .png, .jpeg etc.) and hardcode

_thumbnail

after the name. Hope you get my point. I want to take the complete filename, and cut it into two parts, så that i can insert '_thumbnail' between the two parts.

Maybe that would work, but what if there will be uploaded an image called image.2horses.jpg(a file with more than one dot in the filename), then it wouldn't work to cut it before the '.'

Is there a way to get around this? Maybe by cutting the filename up before the last 4(.jpg .png etc.) og 5 (.jpeg) characters?

+1  A: 

Have a look at the XPath functions overview at W3Schools, specifically the substring-before method.

Rahul
What if there is a filename with more that one dot. E.g. Image.09.07.11.jpg, and i made a substring-before('Image.09.07.11.jpg','.')?Wouldn't I get "Image" and nothing more?
Kim Andersen
You may get the last dot in the string by recursion or a loop. See http://www.biglist.com/lists/xsl-list/archives/200102/msg00838.html
Scoregraphic
A: 

I believe XPath functions operating on string might help you. I would try with some simple replace or translate.

Grzegorz Oledzki
+1  A: 

A general solution involving only standard XSLT is somewhat hard since you have to search the string from the end. You can split your filename usings two functions, substring-before-last and substring-after-last. Unfortunately, these functions are not part of XSLT. You can Google and try to find implementations. Assuming you have these two functions implemented as XSLT templates you can then use the following template to generate thumbnail names:

<xsl:template name="thumbnail-name">
  <xsl:param name="file-name"/>
  <xsl:call-template name="substring-before-last">
    <xsl:with-param name="text" select="$file-name"/>
    <xsl:with-param name="chars" select="'.'"/>
  </xsl:call-template>
  <xsl:text>_thumbnail.</xsl:text>
  <xsl:call-template name="substring-after-last">
    <xsl:with-param name="text" select="$file-name"/>
    <xsl:with-param name="chars" select="'.'"/>
  </xsl:call-template>
</xsl:template>

You can use the template like this (assuming the variable $file-name contains the name of the image):

<img>
  <xsl:attribute name="src">
    <xsl:call-template name="thumbnail-name">
      <xsl:with-param name="file-name" select="$file-name"/>
    </xsl:call-template>
  </xsl:attribute>
</img>
Martin Liversage
+3  A: 

Off the top of my head:

<xsl:template name="substring-before-last">
  <xsl:param name="string1" select="''" />
  <xsl:param name="string2" select="''" />

  <xsl:if test="$string1 != '' and $string2 != ''">
    <xsl:variable name="head" select="substring-before($string1, $string2)" />
    <xsl:variable name="tail" select="substring-after($string1, $string2)" />
    <xsl:value-of select="$head" />
    <xsl:if test="contains($tail, $string2)">
      <xsl:value-of select="$string2" />
      <xsl:call-template name="substring-before-last">
        <xsl:with-param name="string1" select="$tail" />
        <xsl:with-param name="string2" select="$string2" />
      </xsl:call-template>
    </xsl:if>
  </xsl:if>
</xsl:template>

Called as:

<xsl:template match="/">

  <xsl:variable name="filename" select="'image.2horses.jpg'" />

  <xsl:variable name="basename">
    <xsl:call-template name="substring-before-last">
      <xsl:with-param name="string1" select="$filename" />
      <xsl:with-param name="string2" select="'.'" />
    </xsl:call-template>
  </xsl:variable>

  <xsl:value-of select="$basename" />

</xsl:template>

Yields:

image.2horses
Tomalak
Your code worked as well Tomalak, but I had to mark Chris Nielsen's answer as the correct one, 'cause it solved my problem to the fullest. If I could, I would mark yours as correct too :)
Kim Andersen
+1; I like your generalized solution better than mine anyhow.
Chris Nielsen
+4  A: 

Given the image's filename in $filename,

If you can assume that all images will end in ".jpg" and won't have ".jpg" elsewhere in the filename, then this should work:

<img src="{substring-before($filename, '.jpg')}_thumbnail.jpg" ... />

If you don't know the image type (like, you want to handle gif and png as well), or if you think the extension may occur multiple times in the filename ("image.jpg.jpg"), then you will want a template to help you:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
     <p>
      <xsl:call-template name="image_thumbnail">
      <xsl:with-param name="filename" select="'image.jpg'"/>
      </xsl:call-template>
     </p>

     <p>
      <xsl:call-template name="image_thumbnail">
      <xsl:with-param name="filename" select="'image.09.07.11.jpg'"/>
      </xsl:call-template>
     </p>

     <p>
      <xsl:call-template name="image_thumbnail">
      <xsl:with-param name="filename" select="'image.gif'"/>
      </xsl:call-template>
     </p>

     <p>
      <xsl:call-template name="image_thumbnail">
      <xsl:with-param name="filename" select="'image with spaces.jpg'"/>
      </xsl:call-template>
     </p>

     <p>
      <xsl:call-template name="image_thumbnail">
      <xsl:with-param name="filename" select="'image  with  irregular    spaces.jpg'"/>
      </xsl:call-template>
     </p>

     <p>
      <xsl:call-template name="image_thumbnail">
      <xsl:with-param name="filename" select="'image.jpg.again.jpg'"/>
      </xsl:call-template>
     </p>

    </xsl:template>

    <xsl:template name="image_thumbnail">
    <xsl:param name="filename"/>
     <xsl:choose>
     <xsl:when test="contains($filename, '.')">
      <xsl:variable name="before" select="substring-before($filename, '.')"/>
      <xsl:variable name="after" select="substring-after($filename, '.')"/>
      <xsl:choose>
      <xsl:when test="contains($after, '.')">
       <xsl:variable name="recursive">
        <xsl:call-template name="image_thumbnail">
        <xsl:with-param name="filename" select="$after"/>
        </xsl:call-template>
       </xsl:variable>
       <xsl:value-of select="concat($before, '.', $recursive)"/>
      </xsl:when>
      <xsl:otherwise>
       <xsl:value-of select="concat($before, '_thumbnail.', $after)"/>
      </xsl:otherwise>
      </xsl:choose>
     </xsl:when>
     <xsl:otherwise>
      <xsl:value-of select="$filename"/>
     </xsl:otherwise>
     </xsl:choose>
    </xsl:template>

</xsl:stylesheet>
Chris Nielsen
Your solution is roughly equal to mine, I can return the +1 easily. ;-)
Tomalak