Posts Tagged ‘snippet’
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>
How to convert NameValueCollection to a (Query) String [Revised]
Following on from a comment on my previous post about converting a NameValueCollection to a (query) string – I have finally got around to revising my code snippet. Now the method will handle same key multiple values, (it no longer comma-separates them).
I have also added extra parameters so that you can define your own delimiter (since the HTTP specification says that you can use both ampersands & and semicolons ;) and there is an option for omitting keys with empty values.
/// <summary>
/// Constructs a NameValueCollection into a query string.
/// </summary>
/// <remarks>Consider this method to be the opposite of "System.Web.HttpUtility.ParseQueryString"</remarks>
/// <param name="parameters">The NameValueCollection</param>
/// <param name="delimiter">The String to delimit the key/value pairs</param>
/// <returns>A key/value structured query string, delimited by the specified String</returns>
public static String ConstructQueryString(NameValueCollection parameters, String delimiter, Boolean omitEmpty)
{
if (String.IsNullOrEmpty(delimiter))
delimiter = "&";
Char equals = '=';
List<String> items = new List<String>();
for (int i = 0; i < parameters.Count; i++)
{
foreach (String value in parameters.GetValues(i))
{
Boolean addValue = (omitEmpty) ? !String.IsNullOrEmpty(value) : true;
if (addValue)
items.Add(String.Concat(parameters.GetKey(i), equals, HttpUtility.UrlEncode(value)));
}
}
return String.Join(delimiter, items.ToArray());
}
How to convert NameValueCollection to a (Query) String
Most ASP.NET developers know that you can get a key/value pair string from the Request.QueryString object (via the .ToString() method). However that functionality isn’t the same for a generic NameValueCollection object (of which Request.QueryString is derived from).
So how do you take a NameValueCollection object and get a nicely formatted key/value pair string? (i.e. “key1=value1&key2=value2“) … Here’s a method I wrote a while ago:
/// <summary>
/// Constructs a QueryString (string).
/// Consider this method to be the opposite of "System.Web.HttpUtility.ParseQueryString"
/// </summary>
/// <param name="nvc">NameValueCollection</param>
/// <returns>String</returns>
public static String ConstructQueryString(NameValueCollection parameters)
{
List<String> items = new List<String>();
foreach (String name in parameters)
items.Add(String.Concat(name, "=", System.Web.HttpUtility.UrlEncode(parameters[name])));
return String.Join("&", items.ToArray());
}
Just in case you didn’t know about the System.Web.HttpUtility.ParseQueryString method, it’s a quick way of converting a query (key/value pairs) string back into a NameValueCollection.
Making Request.QueryString writable (by clone/copy)
Every now and then I completely forget that the Request.QueryString (and Request.Form) object is read-only. Today I had a bit of functionality where I needed to remove a key/value from the collection – but the Remove() method (of the NameValueCollection object) throws an exception.
Unfortunately, the Request.QueryString’s CopyTo method assigns the values to an ARRAY, not a NameValueCollection – losing functionality and flexibility.
You need to copy the Request.QueryString object to a new NameValueCollection instance, here’s how:
NameValueCollection qs = new NameValueCollection(Request.QueryString);
Now you can add/remove the key/values to your hearts content!
Oh, yeah, remember to import the System.Collections.Specialized namespace too!
Posting source code on WordPress.com
I feel like a complete n00b … I’ve only just found out how to mark-up source-code snippets on WordPress.com
It’s in their FAQs: How do I post source code?
Essentially you use the short-code: [sourcecode language='css']...[/sourcecode]
Here’s an example:
// A "Hello World!" program in C#
class Hello
{
static void Main()
{
System.Console.WriteLine("Hello World!");
}
}
I knew about WP.org plugins that did this, but I’ve been scratching my head on how do this on WP.com for ages now!



