Question

I have a template which fetches images and then outputs them into one of two templates.

I would like it to track each individual image and output based on the values of each one. Currently, if one image is wide, it outputs them all according to the wide template. I would rather utilize both templates.

<xsl:template name="get-images">
    <xsl:param name="image-entry"/>
    <xsl:choose>

        <xsl:when test="($image-entry/image/meta/@width) &gt; ($image-entry/image/meta/@height)">
        <xsl:apply-templates select="$image-entry/image" mode="wide">
            <xsl:with-param name="image-class" select="'full-width'"/>
            <xsl:with-param name="caption-class" select="'full-width-caption'"/>
        </xsl:apply-templates>
        </xsl:when>

        <xsl:otherwise>
            <xsl:apply-templates select="$image-entry/image" mode="tall">
            <xsl:with-param name="image-class" select="'center'"/>
            <xsl:with-param name="caption-class" select="'full-width-caption'"/>
            </xsl:apply-templates>
        </xsl:otherwise>

    </xsl:choose>
</xsl:template>

<xsl:template match="image" mode="wide">
    <xsl:param name="image-class" />
    <xsl:param name="caption-class" />

    <a href="{$root}/image/full{@path}/{filename}">
        <img src="{$root}/image/wide{@path}/{filename}" alt="{../description}" class="{$image-class}"/>
    </a>

    <p class="{$caption-class}">
        Image courtesy of: <a href="{../source}"><xsl:value-of select="../title"/></a>
    </p>
</xsl:template>

<xsl:template match="image" mode="tall">
    <xsl:param name="image-class" />
    <xsl:param name="caption-class" />

    <span class="centered">
        <a href="{$root}/image/full{@path}/{filename}">
            <img src="{$root}/image/tall{@path}/{filename}" alt="{../description}" class="{$image-class}"/>
        </a>
    </span>

    <p class="{$caption-class}">
        Image courtesy of: <a href="{../source}"><xsl:value-of select="../title"/></a>
    </p>
</xsl:template>

Bonus question: How can I ignore the caption if value source doesn't exist?

            <article-images field-id="24" subsection-id="5" items="1">
                <item id="109" creation-date="2014-04-24T05:16:52+01:00">
                    <image size="317 KB" path="/uploads" type="image/jpeg">
                        <filename>funny-lolcat.jpg</filename>
                        <meta creation="2014-04-24T05:16:52+01:00" width="1600" height="1200" />
                    </image>
                    <description mode="formatted"><p>Aww!</p>
</description>
                    <title handle="" />
                    <source handle="" />
                </item>
            </article-images>
Was it helpful?

Solution

Instead of two modes, use one mode and move the wide vs not-wide logic into the template match expressions:

<xsl:template match="image[meta/@width &gt; meta/@height]">
  <!-- logic for wide image -->
</xsl:template>

<xsl:template match="image">
  <!-- logic for not-wide image -->
</xsl:template>

And now you can just apply templates to all the images in one go without the choose:

<xsl:apply-templates select="$image-entry/image"/>

To ignore the caption if there's no source, I'd move the caption logic into another template matching the source element

<xsl:template match="source" mode="caption">
  <p class="full-width-caption">
      Image courtesy of: <a href="{.}"><xsl:value-of select="../title"/></a>
  </p>
</xsl:template>

Then in the main template do:

<xsl:apply-templates select="../source" mode="caption"/>

If there is a source this will produce a caption, if there isn't then it'll produce nothing.

Given the example you've just added to the question it looks like you want to exclude the caption no when the source element "doesn't exist" but rather if it has no value. You can do this by changing the above apply-templates to

<xsl:apply-templates select="../source[string()]" mode="caption" />

This would add a caption for <source handle="">something</source> but not for <source handle="" />.

What this is doing is filtering so we only select the ../source element if the [string()] predicate is true. The string() function returns the "string value" of the context element (the source in this case) and a string in boolean context is treated as false if it is empty and true otherwise. So in this case the effect is to apply templates to the source element only if it has a non-empty value.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top