Introduction
XSL transformation is quick, easy and the time taken to transform documents of one type to another becomes effortless with XSL as compared to any other server side or client side means. Thus, this article helps you to explore how much we can achieve with XSL. Simply said, creativity is the only limitation with XSL transformation.
Background
We often need to transform the content of one document to a completely new document type with different layout. Like taking the article from a blog and sending it as newsletter. Or create a document with certain format from each node of an XML file. Or create an XML file of certain format and change it to a completely new format. There is so much we can do with XSL and it's not complicated. This article helps you understand XSL transformation by:
- Understanding the content - tags, keywords
- Implementing a simple transformation
- Selectively reading content
- Implementing Conditional Logic
- Imposing style
- Embedding code from other XSL resources
Understanding the Content - Tags, Keywords, etc.
To start with a XSL transformation, we firstly need to create an XSL file. Firstly, what does XSL stand for? Well, it stands for EXtensible Stylesheet Language. Thus we understand that technically, XSL files are style sheets and more. Now, to understand better, let's go ahead and add an XSL file to your solution with VS2012 (this is what I am using). When you open it, the content of the files look like this (the line numbers are for reference only and do not appear in the actual code.)
1. ="1.0"="utf-8"
2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3. xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
4. <xsl:output method="xml" indent="yes"/>
5.
6. <xsl:template match="@* | node()">
7. <xsl:copy>
8. <xsl:apply-templates select="@* | node()"/>
9. </xsl:copy>
10. </xsl:template>
11. </xsl:stylesheet>
Before we start making any changes, let's try to understand what each line means:
- Line 1 - This specifies that the XSL document is of type XML of version 1.0 and will be using encoding of type utf-8. The encoding may be altered as per your requirement.
- Line 2 - This line marks the beginning of the XSL document and we see that it's of type stylesheet and has couple of attributes which are:
- version 1.0, this is the current default value.
xsmlns: xsl
- Specifies the namespace for XSL as the default. The value of xmlns:xsl
can be modified, if required in your project. xmlns:msxsl
- This specifies the default scripting language that will be used. The other possible values could be C#, VB, JScript, JavaScript, VisualBasic, or CSharp exclude-result-prefixes
- This helps avoid any namespace declarations in your result elements for namespaces that are already declared and used in the stylesheet. This helps to solely select nodes in path expressions or match patterns or used to insert extension elements.
- Line 4 - Specifies post transformation the generated document will be of type XML and will be indented for better readability. These two are not the only attributes for
xsl:output
. A detailed description could be found over here. - Line 6 - Specifies on what elements will the match take place. The current value means it should match all nodes. In case we want to match the entire XML document, we may use "/" instead. A brief overview of common matching patterns can be found here.
- Line 7- This tag means the selection made in the next rows will be copied and replaced in this section.
- Line 8 - The
xsl:apply-template
tag ensures that only those elements will be processed that matches the value provided via select
attribute. - Line 9 - Line 11 - Are all closing tags for all tags opened.
So to start with, we are now aware of what an XSL file looks like and what does the common tags mean and do.
Implement a Simple Transformation
Download the zip file Sample1 and you will find 2 files. One is an XML file that contains a list of CD in a collection and another the XSL, which will help me present the CD collection the way I want. So let's peek into the contents of the XSL:
<xsl:template match="/">
<html>
<body>
<h1>CD Collection</h1>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
</tr>
<tr>
<td>
<xsl:value-of select="catalog/cd/title[text()='Red']"/>
</td>
<td>
<xsl:value-of select="catalog/cd/artist[text()='The Communards']"/>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
- The template match says that XSL should be matched with the entire document.
- The
html
section marks the beginning of the document that will be created post transformation. - The
body
needs to have a header and it should list the CD collection in a table. - There is a new
xsl
tag called xsl:value-of
. This returns all the text that matches the condition given in the select attribute. - The
select
attribute has an xpath
expression. It says match the title node that has value "Red
" and that is a child of cd
node which is the child of catalog node.
So what is the meaning of the next expression? Find it out yourself. Change the XSL file and experiment. But to see the output, you need to associate the XML file to the XSL. So how do you do it. I know of 2 ways:
- Open the XML file and add the line given below just after the
xml
version tags:
="text/xsl"="CDCollection.xslt"
Here href
should map to actual path of the XSL file, if they are in 2 different locations. And now open the XML in Internet Explorer and see the output.
- The other way is to add both the files to a solution in VS2010 or other version. Add a project and refer to the files. Where you need to call the transformation code, first refer to the 2 namespaces given below:
Declare a transformation object like this:
XslTransform cdXslTransform = new XslTransform();
Next use the load
method:
cdXslTransform.Load("CdCollection.xslt");
Then call the transformation method:
cdXslTransform.Transform("CdCollection.xml", "FormattedCdCollection.xml");
The new file will be generated in the same location as the CdCollection.xml.
So, you have sample files to start with and tranformation techniques to choose from. Now, start experimenting.
Selectively Read Content
Now once you have tweaked the files as per your requirement, some of the changes may have worked and some didn't work out. So let us understand the various select expressions. Before we actually take up different expressions, let's understand that the expressions in XSL are pure xpath
. So here, we start with the expressions:
- You want to display a hardcoded text - No need to use select. Write it directly in the place you want it to appear. Like we did it for the heading. For example:
<h1>CD Collection</h1>
- You want the text of a particular node to appear, then do the following:
<xsl:value-of>
- This will only write the text for the node. - The
select
attribute should match the node with the particular value. title[text()='Red']
- You want to copy the entire elements that match the condition - Use
<xsl:copy-of select="cd"/>
- You want to select the parent node, whose child node matches a value - The expression for select will be -
<xsl:copy select="//cd[cd/title[text()='Red']"
- You want select the value of a element and use it later -
<xsl:variable name="color" select="'red'" />
. But you need to remember unlike variables in other programming languages, values assigned to variables cannot be re-assigned. - You need a variable with a default value that will have different values based on scope - Use
<xsl:param>
. Similar to <xsl:variable>
in syntax, but has a default value and could be reassigned. - You need to select an element whose attribute value matches a string -
<xsl:value-of select="//cd[cd/title[@name='Red']"
where name
is the attribute for the title
node. - There are many things that you may need to do. There are many functions that are already inbuilt. The list of available functions can be found here.
So, now a little more understanding, of what to do and how to keep experimenting.
Implement Conditional Logic
Now, if you have been experimenting with what we have discussed above, you must have been able to transform your XML partly or wholly. But XSL being another language, we would always love to use some conditional logic. We love our if
s and else
s and for-each
and while
. So can we do the same with XSL. Let's see what we can do with XSL:
- You want to match against a single condition or replicate an "
if
" - Use <xsl:if>
. But instead of select
attribute, we need to have the test attribute that will match the condition. So the syntax is - <xsl:if test="price > 10">
. Note since XSL is just another XML document, so instead of the usual ">
" sign we use ">
" and for "<
" we use "<
". - You want to join multiple conditions with AND or OR - AND and OR both could be used to join conditions but only in lower case i.e. as "and" and "or". E.g. -
<xsl:if test="price > 10 and price < 20">
- You want to implement a
switch
case or an if-else
or an if-else if -else
- Use <xsl:choose>
. The syntax will be:
<xsl:choose>
<xsl:when test="price > 5">
<td bgcolor="#ff00ff">
<xsl:value-of select="artist"/></td>
</xsl:when>
<xsl:otherwise>
<td><xsl:value-of select="artist"/></td>
</xsl:otherwise>
</xsl:choose>
- You want to implement a
for-each
- Use <xsl:for-each>
like this:
<xsl:for-each select="catalog/cd">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="artist"/></td>
</tr>
</xsl:for-each>
Well, now you have the understanding of the conditional logic and the operators. So why wait? Start practicising. Just one thing, before you start to zoom off, just know that like any other programming language, in XSL too, you can use these logic either as stand alone or along with others.
Impose Style
So at the beginning, we did discuss that XSL was meant for presentation. And then it is understood that we would like to stylize the output document with styles we want. So can we use styles in the output. Let's try some samples:
- You want to assign the style of an element with certain value:
<xsl:attribute name="style">
<xsl:value-of select="'color: Red;'" />
</xsl:attribute>
- You want to declare a CSS class in the xsl file. Use
<span class="re1"><xsl:attribute-set<span class="re2">/>. </span></span>
You can add a class and then add its definition in the following way -
<xsl:attribute-set name="quote">
<xsl:attribute name="padding-start">2.5cm</xsl:attribute>
<xsl:attribute name="line-height">11pt</xsl:attribute>
</xsl:attribute-set>
It's better to declare all your attribute sets at the top, so that the entire document has its scope.
- You want use existing style classes declared in .css files - You can use CdCollection.css in the XSL file by referring it like this:
<link rel="stylesheet" type="text/css" href="CdCollection.css" />
Just use this line above the header, and you will see the difference. Try other styles too. To add styles to the body of the html
document. Include the section given below in the .css file:
body{
}
So start manipulating the styles too.
Embed Code from Other XSL Resources
So by now, you will be able to create a fairly complex XSL file to handle transformation. But there remains a question, do we need to create an XSL file for each XML transformation? Aren't the complex transformations going to be tedious if we need to replicate to for all similar set of files. Well, don't worry. Coding world is not so bad. XSL are resuable and that too very easily. So how do we do it. Fairly simple way is:
The import
tags refers to external resources and will create an import tree. You can then use any functionality imposed by the imported XSL into your current XSL.
- You can use
<xsl:include>
too. Its difference from <xsl:import>
being that <xsl:include>
could only be used as a top level element.
So, we have covered a fair portion of what to do with XSL and how to do it. Hopefully, this has been useful. There are a whole lot of resources out there. My attempt has been just to collaborate them. The article that I started with is available here. The sample XML and XSL are modified versions of sample available in the tutorial. Another great resource is this. Please feel free to post your comments.