Archive
Gotcha: don’t use ‘{$…}’ syntax or ‘$…’ syntax in XSL-XPath’s concat
<xsl:template match="cxml:Item" mode="col">
<xsl:variable name="FILENAME" select="…someXPathQuery…"/>
<xsl:variable name="IMAGE" select="concat(‘http://gallery.clipflair.net/activity/image/’, $FILENAME, ‘.png’)"/>
…
I got confused a bit today after a long day of fiddling with XSL and ClipFlair Activity Gallery’s CXML (Collection XML) data (as used in PivotViewer control), and didn’t understand why I couldn’t use an XSL variable’s (FILENAME in the sample above) calculated value inside the definition of another variable.
That other variable (IMAGE) was using “concat” function of XPath and I was getting a literal string concatenated, instead of the value of the FILENAME one.
After a while I noticed that I was using string quotes arround the respective argument passed to the “concat” function. One needs to use $FILENAME there, not ‘$FILENAME’ and of course not ‘{$FILENAME}’ (the last one is used inside say HTML argument values used for output, like <img href=”{$IMAGE}” />)
HowTo: Group output items using XSL transformation
While trying to generate a single HTML page that will list all ClipFlair activities using XSL Transformations (XSLT), I had the need to group items in 2-column rows.
This is my contribution to other solutions suggested at (if you like it you can vote it up there):
http://stackoverflow.com/questions/9908488/xslt-for-each-wrapping-every-nth-item-in-a-div/
Faced by the same problem, that is wanting to output
<div class="container">
<div class="row">
<div class="col">...</div>
<div class="col"/>...</div>
</div>
<div class="row">
...
</div>
</div>
from a CXML (Collection XML) file (http://gallery.clipflair.net/collection/activities.cxml – the data behind the PivotViewer display at http://gallery.clipflair.net/activity)
I coined up the following, based on other suggestions here, but using "mode" attribute of "template" and "apply-templates" XSL tags instead which make it cleaner I believe:
<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml http://gallery.clipflair.net/collection/activities.cxml?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cxml="http://schemas.microsoft.com/collection/metadata/2009"
exclude-result-prefixes="cxml"
>
<xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="COLUMNS" select="2"/>
<!-- ########################### -->
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>ClipFlair Activities</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Collection">
<div class="container">
<xsl:apply-templates/>
</div>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Items">
<xsl:apply-templates
select="cxml:Item[position() mod $COLUMNS = 1]" mode="row"/>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Item" mode="row">
<div class="row">
<div>----------</div>
<xsl:apply-templates
select=".|following-sibling::cxml:Item[position() < $COLUMNS]" mode="col"/>
</div>
</xsl:template>
<xsl:template match="cxml:Item" mode="col">
<xsl:variable name="URL" select="@Href"/>
<xsl:variable name="FILENAME"
select="cxml:Facets/cxml:Facet[@Name='Filename']/cxml:String/@Value"/>
<div class="col">
<xsl:value-of select="$FILENAME"/> --- <xsl:value-of select="$URL"/>
</div>
</xsl:template>
<!-- ########################### -->
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()|@*">
</xsl:template>
</xsl:stylesheet>
the output from the above when run in Altova XMLSpy tool (note that it uses altova_samplexml processor instruction to find the XML data) is:
2DaysInParis-OpenActivity-CapRev-FR-EN.clipflair --- http://studio.clipflair.net/?activity=2DaysInParis-OpenActivity-CapRev-FR-EN.clipflair
Abu_Dukhan-CapRev-A1-AR.clipflair --- http://studio.clipflair.net/?activity=Abu_Dukhan-CapRev-A1-AR.clipflair
----------
AFarewellToArms-RevCap-C2-EN.clipflair --- http://studio.clipflair.net/?activity=AFarewellToArms-RevCap-C2-EN.clipflair
agComhaireamhCountingRND.clipflair --- http://studio.clipflair.net/?activity=agComhaireamhCountingRND.clipflair
----------
Al-imtihan-CapRev-B1-AR.clipflair --- http://studio.clipflair.net/?activity=Al-imtihan-CapRev-B1-AR.clipflair
AlBar-Cap-B1-B2-IT.clipflair --- http://studio.clipflair.net/?activity=AlBar-Cap-B1-B2-IT.clipflair
...
Fix: Transform Manager ignoring media files added to watch folders
I’ve been puzzled for some days now with the IIS Transform Manager installation we have at ClipFlair for automating the conversion of media files (for example using Microsoft Expression Encoder) into IIS Smooth Streams.
The watch folder I’ve set up for this task was ignoring some of the media files I was dropping in for no apparent reason (e.g. it was picking up some .MP4 files but not other .MP4 ones).
Eventually I realized that the files it wasn’t picking up didn’t have at their Properties/Security tab access rights for the user account that has been assigned to the Transform Manager service, while the processed files (it keeps them at the “WorkQueue/Finished” subfolder” under the watch folder for the respective job [e.g. “Smooth (VC1)”]) had full access rights for that account.
Obviously by dropping them in the watch folder that had those rights assigned they also got the same rights, but not all the filed did. Maybe it is some Windows Server 2008 R2 bug when dropping multiple files together into a folder, not sure though. Adding the needed rights to each of those files, Transform Manager watch folder task immediately pulled them for processing (and soon put them into the “WorkQueue/Running”)
Another thing I noted was that at the Watch Folder task’s (say the “Video files to VC-1 Smooth Streams” ) “Scheduler” tab, at “Concurrent Jobs”, the default setting was set to 1. If you control how many files are placed in the watch folder (e.g. users aren’t uploading files there themselves) you can even check the value “Unlimited” there to process all the dropped files in parallel.
HowTo: Scale control arround its center using a render transform
In the context of ClipFlair development, I was recently adding independent scaling (zooming) functionality to its ZUI container’s floating windows (apart from the container zooming functionality) and came across some strange behavior, where the windows seemed to also move apart from getting scaled.
After banging my head a bit I decided to take a closer look at Microsoft’s documentation and noticed the following text at http://msdn.microsoft.com/en-us/library/system.windows.uielement.rendertransformorigin.aspx
"RenderTransformOrigin has a somewhat nonstandard use of the Point structure value, in that the Point does not represent an absolute location in a coordinate system. Instead, values between 0 and 1 are interpreted as a factor for the range of the current element in each x,y axis. For example, (0.5,0.5) will cause the render transform to be centered on the element, or (1,1) would place the render transform at the bottom right corner of the element. NaN is not an accepted value. Values beyond 0 and 1 are also accepted, and will result in more unconventional transform effects. For instance, if you set RenderTransformOrigin to be (5,5), and then apply a RotateTransform, the rotation point will be well outside the bounds of the element itself. The transform will spin your element around in a big circle that originates beyond bottom right. The origin might be somewhere inside its parent element and could possibly be possibly out of frame or view. Negative point values are similar, these will go beyond the top left bounds. Render transforms do not affect layout, and are typically used to animate or apply a temporary effect to an element."
Since ClipFlair’s FloatingWindowHostZUI template uses a Canvas to host its FloatingWindows, I obviously didn’t care about the phrase “Render transforms do not affect layout”, but the phrase “values between 0 and 1 are interpreted as a factor for the range of the current element in each x,y axis” rang a bell immediately.
Misguided by the poor Intellisense info for the RenderTransformOrigin property, I had thought that point was in the control’s coordinate system, and since I wanted to scale the control arround its center, I had used the following erroneous statement:
window.RenderTransformOrigin = new Point(window.ActualWidth/2, window.ActualHeight/2);
window.RenderTransform = new ScaleTransform().SetScale((double)e.NewValue);
…
instead of the correct one:
window.RenderTransformOrigin = new Point(0.5, 0.5);
//scale arround the window center
window.RenderTransform = new ScaleTransform().SetScale((double)e.NewValue);
That is the range 0 to 1 for x & y coordinates of RenderTransformOrigin refers to the UIElement region, whereas less or greater values are (proportionally) outside of it, useful for example if you want to rotate an object arround an external point with a RotateTransform.
Don’t get puzzled by the expression new ScaleTransform().SetScale(…), it’s a syntax I use for authoring portable source code between WPF and Silverlight (since Silverlight only has a parameter-less constructor for ScaleTransform and anyway WPF doesn’t have a constructor that takes a single parameter for both X and Y scale values).
To sum up, here’s the “Scale” property I added to the FloatingWindow class:
#region public double Scale
/// <summary> /// Gets or sets current window scale. /// </summary> /// <value>Current scale.</value>
public double Scale {
get { return (double)GetValue(ScaleProperty); }
set { SetValue(ScaleProperty, value); } } /// <summary>
/// Identifies the <see cref="FloatingWindow.Scale" /> dependency property.
/// </summary>
/// <value>
/// The identifier for the <see cref="FloatingWindow.Scale" /> dependency property.
/// </value> public static readonly DependencyProperty ScaleProperty =
DependencyProperty.Register("Scale", typeof(double), typeof(FloatingWindow),
new PropertyMetadata(1d, OnScalePropertyChanged));
//Must use 1d here, not 1 (else will get XAMLParseException at runtime)
/// <summary>
/// ScaleProperty PropertyChangedCallback call back static function.
/// </summary>
/// <param name="d">FloatingWindow object whose Scale property is changed.</param>
/// <param name="e">DependencyPropertyChangedEventArgs contains old and new values.</param> private static void OnScalePropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
FloatingWindow window = (FloatingWindow)d;
if (window != null)
{
window.RenderTransformOrigin = new Point(0.5, 0.5); //scale arround the window center
window.RenderTransform = new ScaleTransform().SetScale((double)e.NewValue);
}
} #endregion
text transforms: TemplateFilter, TextCaseConvertion, CharConv, Dos2Unix, Unix2Dos, ClearTextFilter
Added various tools related to text transformations at my tranXform website (30-Sep-2010 update):
TemplateFilter
DOS filter – parses CSV-style multi-column (“;” separator) input text rows (one row per text line) and generates text based on a supplied template that is applied per input row
TextCaseConvertion
simple GUI-based tool to convert string to upper-case, lower-case and camel-case
CharConv
Windows and Microsoft Word GUI for Text transformation given character set mapping (from/to) and calculation of mapping given matching (portions of) source and target text
Useful for deciphering copy-pasted text from PDF documents that ends-up with strange character swaps in it due to encoding reasons
Dos2Unix
DOS filter – converts CRLF (Dos/Windows style) to LF (Unix style) for text ending line markers
Unix2Dos
DOS filter – converts LF (Unix style) to CRLF (Dos/Windows style) for text ending line markers
ClearTextFilter
DOS filter – converts control characters to space chars