HomeASP.NET Learning XPath with XSLT using ASP.NET 2.0
Learning XPath with XSLT using ASP.NET 2.0
This is the first article in a series focusing on XPath with XSLT using ASP.NET 2.0. In this article, I will be focusing on setting up your own XSD, XML and XSL to test XPath expressions along with a few of the basic XPath expressions, together with XSLT constructs.
Even though this series is based on ASP.NET 2.0, I use it only as a transformation engine. The entire focus will be on working with XPath and XSLT. You can use any transformation engine according to your requirements (such as Java or others).
You can consider this series as a complement to my existing series, which focused on developing XSLT-based applications using ASP.NET 2.0. If you are new to a few of the concepts of XSLT, I strongly suggest you go through my first series, which deals completely with XSLT. I will be using few of the XSLT constructs in this series wherever appropriate.
The entire solution (source code) for this article is available as a free download (in the form of a zip). All the applications in this series have been developed using Microsoft Visual Studio 2005 Professional Edition on Microsoft Windows Server 2003 Standard Edition together with Microsoft SQL Server 2005 Developer Edition as the database. You can even directly copy and paste the code given in this article and save with XML or XSL extension and work with your own XSL parsers/engines.
I didn’t really test any of the code in any of the other tools/IDEs/servers/editions/versions. If you have any problems, please feel free to post in the discussion area.
In this article, we need to work with nested hierarchies in XML. None of my XML samples in previous articles will really help us. So I started defining my own XML schema and sample XML document for this article.
In this new design, I included the concept of departments and employees. Every department can contain any number of employees and an employee always belongs to a table. The following is the XML schema to achieve the same:
I designed the above schema using Visual Studio 2005. From the above you can understand that the root of the XML document must start with “EmployeeDetails” and can contain any number of “Departments.” Details (deptno, dname and location) of each and every “Department” will be available as attributes and every “Department” can have any number of “Employees” with details (empno, ename and sal) underneath them.
The following is the sample XML document which complements the above schema.
In the previous section, we completed setting up the XML schema and XML document. Now it is time to modify our ASP.NET 2.0 code to work with a simple XSL focusing on the XML document provided in the previous section.
Add a new button to your ASP.NET 2.0 project and add the following code to the button click event:
ProtectedSub Button2_Click(ByVal sender AsObject, ByVal e As System.EventArgs) Handles Button2.Click
Dim XSLTFileName AsString = Server.MapPath("EmpDetails01.xsl")
Dim XMLFileName AsString = Server.MapPath("EmployeeDetails.xml")
Dim docXML AsNew XmlDocument
docXML.Load(XMLFileName)
Me.txtXML.Text = docXML.InnerXml
Dim xp AsNew XPath.XPathDocument(New XmlTextReader(New IO.StringReader(docXML.InnerXml)))
Xml1.XPathNavigator = xp.CreateNavigator
Xml1.TransformSource = XSLTFileName
'----------------------------------------> generating XSLT to show to user
Dim xslt AsNew Xsl.XslCompiledTransform()
xslt.Load(XSLTFileName)
' Create the writer.
Dim settings AsNew XmlWriterSettings()
settings.Indent = True
settings.IndentChars = ControlChars.Tab
settings.ConformanceLevel = ConformanceLevel.Auto
Dim sw AsNew IO.StringWriter
Dim writer As XmlWriter = XmlWriter.Create(sw, settings)
The above code not only transforms your XML to XSL, but also displays the transformation to the user. The following is a sample XSL to test with the above ASP.NET 2.0 code:
According to the above, I defined a template to display some information when the control starts at “root” (or “/”). Within the template, I am displaying the value of “EmployeeDetails/Department/Employee/Ename.” In this case, it starts right from the root, proceeds along the path and finds the first employee name. The same gets displayed to the user.
Now, let us consider that I would like to display all the employee names. We have two good solutions for achieving the same. The first solution will use a separate template for that “Ename” element. You can observe the following code:
The other method involves using “xsl:for-each.” If you are new to this construct, I suggest you go through the third and fourth articles of my previous series. The following is the code to achieve the same:
We already retrieved all employee names using the XSLT code given in the previous section. The code given in that section always deals with the “Ename” existing only at “EmployeeDetails/Department/Employee.”
If I have the “Ename” at different levels of the hierarchy (but not in my XML document yet), the XSLT given in the previous section will not work. The following is the modified code (using separate template) to retrieve the value of “Ename” at any level of the hierarchy:
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<b>
<xsl:apply-templatesselect ="//Ename"/>
</b>
</xsl:template>
<xsl:templatematch="Ename">
<xsl:value-ofselect ="text()"/>
<br/>
</xsl:template>
</xsl:stylesheet>
You can observe that I replaced “EmployeeDetails/Department/Employee” with a simple “//Ename.” The “//” simply gives the instruction “at any level of hierarchy.” Similarly, the following is the modified code (using “xsl:for-each” construct) to retrieve the value of “Ename” at any level of hierarchy:
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<b>
<xsl:for-eachselect="//Ename">
<xsl:value-ofselect="text()"/>
<br/>
</xsl:for-each>
</b>
</xsl:template>
</xsl:stylesheet>
The output of any of the above transformations would be the same (in this case), as given in the previous section. You may find it different if you really have “Ename” at different levels of hierarchies (or paths).
In previous sections, we simply searched for a particular element throughout the document. Now, I would like to parse through every element (regardless of its path) within the document and display the values.
The following is the first approach for accomplishing the same (using a separate template):
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<b>
<xsl:apply-templatesselect ="//*"/>
</b>
</xsl:template>
<xsl:templatematch="*">
<xsl:value-ofselect ="text()"/>
<br/>
</xsl:template>
</xsl:stylesheet>
Within the above code, you can observe that I am using “//*”, which stands for “any element at any level”! The following is the second approach for accomplishing the same (using “xsl:for-each” construct).
<?xmlversion="1.0"encoding="utf-8"?>
<xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<b>
<xsl:for-eachselect="//*">
<xsl:value-ofselect="text()"/>
<br/>
</xsl:for-each>
</b>
</xsl:template>
</xsl:stylesheet>
In any of the above cases, when the XSLT gets executed, the transformation looks something like the following (I have added comments for understanding):
<b>
<br /> (for EmployeeDetails)
<br /> (for Department)
<br /> (for Employee)
1001<br /> (for Empno)
Jagadish<br /> (For Ename)
3400<br /> (For Sal)
<br /> (for Employee)
1002<br /> (for Empno)
Chatarji<br /> (for Ename)
2500<br /> (for Sal)
<br /> (for Employee)
.
.
.
</b>
In the upcoming articles, we shall look further into XPath expressions. I hope you enjoyed the article and any comments, suggestions, feedback, bugs, errors, enhancements etc. are highly appreciated at http://jagchat.spaces.live.com