How to use umbraco.library GetMedia in XSLT
From time to time I notice a reoccurring post over at the Our Umbraco forum; how to display an image (from the Media section) in XSLT?
A quick answer can be found on the Our Umbraco wiki for the umbraco.library GetMedia method.
For most uses, the last example in the wiki works great. But I want to show you a “super safe” way of dealing with GetMedia in XSLT.
Where I find a lot of the examples go wrong is that they make the assumption that a media node (XML) is returned from the GetMedia call, e.g.
<xsl:value-of select="umbraco.library:GetMedia($currentPage/data[@alias='mediaId'], 'false')/data[@alias='umbracoFile']" />
If the ‘mediaId’ property didn’t contain either a numeric value or a valid media node id, then it would return null … meaning that the following “/data” would throw an Exception! (Displaying “Error parsing XSLT file” message on the front-end.) Not what you or your users want to see!
In order to consider any user inputs, like media IDs not being selected, or even a referenced media node is deleted in the back-office, here is the “super safe” approach:
<xsl:template match="/"> <xsl:variable name="mediaId" select="number($currentPage/data[@alias='mediaId'])" /> <xsl:if test="$mediaId > 0"> <xsl:variable name="mediaNode" select="umbraco.library:GetMedia($mediaId, 0)" /> <xsl:if test="count($mediaNode/data) > 0"> <xsl:if test="string($mediaNode/data[@alias='umbracoFile']) != ''"> <img src="{$mediaNode/data[@alias='umbracoFile']}" alt="[image]"> <xsl:if test="string($mediaNode/data[@alias='umbracoHeight']) != ''"> <xsl:attribute name="height"> <xsl:value-of select="$mediaNode/data[@alias='umbracoHeight']" /> </xsl:attribute> </xsl:if> <xsl:if test="string($mediaNode/data[@alias='umbracoWidth']) != ''"> <xsl:attribute name="width"> <xsl:value-of select="$mediaNode/data[@alias='umbracoWidth']" /> </xsl:attribute> </xsl:if> </img> </xsl:if> </xsl:if> </xsl:if> </xsl:template>
Here’s what happens:
- The “mediaId” is pulled from a property of the “currentPage” and cast as a number. Optionally the “mediaId” could be passed in via a macro parameter, or somewhere else?
- The first condition checks the the “mediaId” is numeric, and greater-than zero.
- The “mediaId” is passed through to “GetMedia”, along with the false flag to only pull-back the required node (not it’s children, for Folder media items).
- We check if the media node has any child “data” elements – which contain the data about the image/media.
- Then we check if the “umbracoFile” property has any data – if not, then there is no point displaying an image.
- There are extra conditions for the “height” and “width” properties – these are optional.
Personally, I add an “altText” property to the Image media-type … and use that in the XSLT – again this is optional, but strongly recommended!
I can see how this “super safe” approach is overkill – especially compared with a single line of XSLT … but from my experience, it’s better to be safe than sorry – especially when dealing with user data-input – your assumptions and expectations of how users will use the system aren’t always correct!
Update: OK, I agree the extra “if” statements are overkill… so here’s a condensed version – assuming that the “umbracoHeight” and “umbracoWidth” properties are always there…
<xsl:template match="/"> <xsl:variable name="mediaId" select="number($currentPage/data[@alias='mediaId'])" /> <xsl:if test="$mediaId > 0"> <xsl:variable name="mediaNode" select="umbraco.library:GetMedia($mediaId, 0)" /> <xsl:if test="count($mediaNode/data) > 0 and string($mediaNode/data[@alias='umbracoFile']) != ''"> <img src="{$mediaNode/data[@alias='umbracoFile']}" alt="[image]" height="{$mediaNode/data[@alias='umbracoHeight']}" width="{$mediaNode/data[@alias='umbracoWidth']}" /> </xsl:if> </xsl:if> </xsl:template>