Saturday, February 21, 2009

Practical primer of using XSL Transformation Extension Objects - XSLT Localization

XSL Transformation is widly known tecnique for converting XML files to XHTML output. XSLT is designed for use as part of XSL, which is a stylesheet language for XML. XSL specifies the styling of an XML document by using XSLT to describe how the document is transformed into another XML document that uses the formatting vocabulary.

Here is sample XML document that will be used further.


<?xml version="1.0" encoding="UTF-8"?>
<sales>
<division id="North">
<revenue>10</revenue>
<growth>9</growth>
<bonus>7</bonus>
</division>
<division id="South">
<revenue>4</revenue>
<growth>3</growth>
<bonus>4</bonus>
</division>
<division id="West">
<revenue>6</revenue>
<growth>-1.5</growth>
<bonus>2</bonus>
</division>
</sales>

Here is sample XSL Transformation


<html xsl:version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
lang="en">
<head>
<title>Sales Results By Division</title>
</head>
<body>
<table border="1">
<tr>
<th>Division</th>
<th>Revenue</th>
<th>Growth</th>
<th>Bonus</th>
</tr>
<xsl:for-each select="sales/division">
<!-- order the result by revenue -->
<xsl:sort select="revenue"
data-type="number"
order="descending"/>
<tr>
<td><em><xsl:value-of select="@id"/></em></td>
<td><xsl:value-of select="revenue"/></td>
<td>
<!-- highlight negative growth in red -->
<xsl:if test="growth &lt; 0">
<xsl:attribute name="style"> <xsl:text>color:red</xsl:text>
</xsl:attribute>
</xsl:if>
<xsl:value-of select="growth"/>
</td>
<td><xsl:value-of select="bonus"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>

By using following sample c# code we can effectivly load xml document, and transform it's content into xhtml by using given xslt transformation:


XmlDocument xmldocument = new XmlDocument();
xmldocument.Load(@"..\..\data.xml");

XslCompiledTransform xsltransform = new XslCompiledTransform();
xsltransform.Load(@"..\..\style.xsl");

XmlTextWriter htmlwriter = new XmlTextWriter("output.html", null);
xsltransform.Transform(xmldocument, htmlwriter);

Now since we know how to transform xml data with xsl stylesheet and produce valid html code, we can continue with introducing XSL Extension Objects.

Extension objects are used to extend the functionality of style sheets. Extension objects are maintained by the XsltArgumentList class.
The following are advantages to using an extension object rather than embedded script:

  • Provides better encapsulation and reuse of classes.
  • Allows style sheets to be smaller and more maintainable.

XSLT extension objects are added to the XsltArgumentList object using the AddExtensionObject method. A qualified name and namespace URI are associated with the extension object at that time. In this example we are using ResourceReader object
public class ResourceReader
{
public string GetResourceString(string key)
{
//TODO: Read localized string representation for provided 'key' from resource file
switch (key)
{
case "0001":return "Division";
case "0002":return "Revenue";
case "0003":return "Growth";
case "0004":return "Bonus";
}
return string.Format("No resource value found for key='{0}'", key);
}
}

Let's add this object to XsltArgumentList so we can use latter in xsl transformation for reading string values from resources


XmlDocument xmldocument = new XmlDocument();
xmldocument.Load(@"..\..\data.xml");

XslCompiledTransform xsltransform = new XslCompiledTransform();
xsltransform.Load(@"..\..\style.xsl");

XsltArgumentList arguments = new XsltArgumentList();
arguments.AddExtensionObject("urn:ResourceReader", new ResourceReader());

XmlTextWriter htmlwriter = new XmlTextWriter("output.html", null);
xsltransform.Transform(xmldocument, arguments, htmlwriter);

And modified xslt stylesheet will look like this


<html
xsl:version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ResourceReader="urn:ResourceReader"
lang="en">
<head>
<title>Sales Results By Division</title>
</head>
<body>
<table border="1">
<tr>
<th><xsl:value-of select="ResourceReader:GetResourceString('0001')" /></th>
<th><xsl:value-of select="ResourceReader:GetResourceString('0002')" /></th>
<th><xsl:value-of select="ResourceReader:GetResourceString('0003')" /></th>
<th><xsl:value-of select="ResourceReader:GetResourceString('0004')" /></th>
</tr>
<xsl:for-each select="sales/division">
<xsl:sort select="revenue"
data-type="number"
order="descending"/>
<tr>
<td><em><xsl:value-of select="@id"/></em></td>
<td><xsl:value-of select="revenue"/></td>
<td>
<xsl:if test="growth &lt; 0">
<xsl:attribute name="style">
<xsl:text>color:red</xsl:text>
</xsl:attribute>
</xsl:if>
<xsl:value-of select="growth"/>
</td>
<td><xsl:value-of select="bonus"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html> tml>

And the rest is history. Cheers!

Thursday, May 1, 2008

PowerShell - Automate the non-automatable

PowerShell is new command and scripting environment on windows platforms. Anyone who has used unix shells know the power of those scripting tools. On the other hand windows users had ms-dos command environment invented mostly for average users, advanced users can use cygwin linux-like emulation on windows as an alternative for scripting. PowerShell fills this gap, and it is for advanced users.

With PowerShell you can use extended scripting capabilities and full .net object-oriented support.

Mixing those two technologies scripting and .net results in highly powerful shell – PowerShell.
Ever interested in performing scripting operations over windows registry system?

dir hklm:\software

powershellps_

How about scripting on SharePoint platform ?!

$site = new-object Microsoft.SharePoint.SPSite(“http://sps/sites/testsite”)

Or … instantiate a SqlCommand object ?!  yep it is possible. PowerShell can store instantiated objects into variables and combining them you can perform various complex automation processes, for example extending your build server with auto deployment capabilities on your staging server/s. Deployment processes can include removing/installing windows services, creating databases, setting permissions etc, this can be handled by PowerShell. This tool is a truly scripting heaven for .net developers.

I use it mainly for automate deployment processes on MOSS servers, I found this language as very flexible and powerful, I encourage everyone to start using/experiment and make your life easier.

Monday, November 26, 2007

My favorite 5 reasons why programmers work on weekends









Programmers don’t really have a fixed schedule. We can work all weekend and take off Monday if we like.

We hate working on Mondays.

We don’t really like sun tanning or physical sports which are usually weekend activities.

52 weekends equals around 832 hours @ $100/hr, or more, that’s a lot of money to throw away.

We have so much outboard gear like iPods, phones, TV Games, etc that it takes the whole weekend to sync it all with our laptops.


More reasons to work on weekends here

Sunday, November 18, 2007

The Ninja

The Ninja is your team’s MVP, and no one knows it. Like the legendary assassins, you do not know that The Ninja is even in the building or working, but you discover the evidence in the morning. You fire up the source control system and see that at 4 AM, The Ninja checked in code that addresses the problem you planned to spend all week working on, and you did not even know that The Ninja was aware of the project! See, while you were in Yet Another Meeting, The Ninja was working.

Ninjas are so stealthy, you might not even know their name, but you know that every project they’re on seems to go much more smoothly. Tread carefully, though. The Ninja is a lone warrior; don’t try to force him or her to work with rank and file.

10 types of programmers you’ll encounter in the field

Wednesday, October 10, 2007

Wrong result on float.TryParse() method

One of the introduced features in .NET 2.0 platform was TryParse() method, very practical and performance wise extension. TryParse method returns a boolean to denote whether the conversion has been successful or not, and returns the converted value through an out parameter.
In this test case I will try to present possible bug in converting string value to float by using this method.


float f;
string
stringValue = "123,456789101112";
float.TryParse(stringValue, out f);

String value that needs to be converted to float is 123,456789101112, expected float value after parsing would be the same number, but number 123.456787 was returned. Sixth decimal was wrongly rounded / generated, and instead of 9 - number 7 is placed.
Is this conversion culture specific, is some hidden mechanism for rounding applied?

Decimal method for parsing string into decimal value is working correctly.