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.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 9
January 02, 2007
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

A downloadable zip file is available for this article.

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.

Setting up your environment: XML Schema and XML

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:

<?xml version="1.0" encoding="utf-8"?>

<xs:schema id="EmployeeDetails" targetNamespace=
"http://tempuri.org/EmployeeDetails.xsd" 
elementFormDefault="qualified" xmlns=
"http://tempuri.org/EmployeeDetails.xsd" xmlns:mstns=
"http://tempuri.org/EmployeeDetails.xsd" xmlns:xs=
"http://www.w3.org/2001/XMLSchema">

      <xs:element name="EmployeeDetails">

            <xs:complexType>

                  <xs:sequence>

                        <xs:element name="Department" maxOccurs="unbounded">

                              <xs:complexType>

                                    <xs:sequence>

                                          <xs:element name="Employee" maxOccurs="unbounded">

                                                <xs:complexType>

                                                      <xs:sequence>

                                                            <xs:element name="Empno" type="xs:int" />

                                                            <xs:element name="Ename" type="xs:string" />

                                                            <xs:element name="Sal" type="xs:float" />

                                                      </xs:sequence>

                                                </xs:complexType>

                                          </xs:element>

                                    </xs:sequence>

                                    <xs:attribute name="Deptno" type="xs:int" />

                                    <xs:attribute name="Dname" type="xs:string" />

                                    <xs:attribute name="Location" type="xs:string" />

                              </xs:complexType>

                        </xs:element>

                  </xs:sequence>

            </xs:complexType>

      </xs:element>

</xs:schema>

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.

<?xml version="1.0" encoding="utf-8"?>

<EmployeeDetails>

      <Department Deptno="10" Dname="Accounting" Location="New York">

            <Employee>

                  <Empno>1001</Empno>

                  <Ename>Jagadish</Ename>

                  <Sal>3400</Sal>

            </Employee>

            <Employee>

                  <Empno>1002</Empno>

                  <Ename>Chatarji</Ename>

                  <Sal>2500</Sal>

            </Employee>

            <Employee>

                  <Empno>1003</Empno>

                  <Ename>Winner</Ename>

                  <Sal>4300</Sal>

            </Employee>

      </Department>

      <Department Deptno="20" Dname="Sales" Location="Dallas">

            <Employee>

                  <Empno>2001</Empno>

                  <Ename>Dhanam</Ename>

                  <Sal>4500</Sal>

            </Employee>

            <Employee>

                  <Empno>2002</Empno>

                  <Ename>Chinna</Ename>

                  <Sal>3400</Sal>

            </Employee>

            <Employee>

                  <Empno>2003</Empno>

                  <Ename>Pedda</Ename>

                  <Sal>3200</Sal>

            </Employee>

      </Department>

      <Department Deptno="30" Dname="Research" Location="Washington">

            <Employee>

                  <Empno>3001</Empno>

                  <Ename>Ram</Ename>

                  <Sal>5600</Sal>

            </Employee>

            <Employee>

                  <Empno>3002</Empno>

                  <Ename>Robert</Ename>

                  <Sal>5600</Sal>

            </Employee>

            <Employee>

                  <Empno>3003</Empno>

                  <Ename>Rahim</Ename>

                  <Sal>4300</Sal>

            </Employee>

      </Department>

</EmployeeDetails>

Setting up your environment: ASP.NET 2.0 code and XSL

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:

Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click

    Dim XSLTFileName As String = Server.MapPath("EmpDetails01.xsl")

    Dim XMLFileName As String = Server.MapPath("EmployeeDetails.xml")

    Dim docXML As New XmlDocument

    docXML.Load(XMLFileName)

    Me.txtXML.Text = docXML.InnerXml

    Dim xp As New XPath.XPathDocument(New XmlTextReader(New IO.StringReader(docXML.InnerXml)))

    Xml1.XPathNavigator = xp.CreateNavigator

    Xml1.TransformSource = XSLTFileName

    '----------------------------------------> generating XSLT to show to user

    Dim xslt As New Xsl.XslCompiledTransform()

    xslt.Load(XSLTFileName)

    ' Create the writer.

    Dim settings As New XmlWriterSettings()

    settings.Indent = True

    settings.IndentChars = ControlChars.Tab

    settings.ConformanceLevel = ConformanceLevel.Auto

    Dim sw As New IO.StringWriter

    Dim writer As XmlWriter = XmlWriter.Create(sw, settings)

    ' Execute the transformation.

    xslt.Transform(docXML, writer)

    writer.Close()

    Me.Literal1.Text = "<pre>" & Server.HtmlEncode(sw.ToString) & "</pre>"

    sw.Close()

  End Sub

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:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">

            <b>

                  <xsl:value-of select="EmployeeDetails/Department/Employee/Ename"/>

            </b>

      </xsl:template>

</xsl:stylesheet>

Once the above code is executed, your transformation should look something like the following:

<b>Jagadish</b>

If you are able to view the transformation as above, your setup is correct.

Retrieving all values of a particular element at a particular level of hierarchy (or path)

Let us go through our XSL sample listed in the previous section:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">

            <b>

                  <xsl:value-of select="EmployeeDetails/Department/Employee/Ename"/>

            </b>

      </xsl:template>

</xsl:stylesheet>

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:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">

            <b>

                  <xsl:apply-templates select ="EmployeeDetails/Department/Employee/Ename"/>

            </b>

      </xsl:template>

      <xsl:template match="EmployeeDetails/Department/Employee/Ename">

            <xsl:value-of select ="text()"/><br/>

      </xsl:template>

</xsl:stylesheet>

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:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">

            <b>

                  <xsl:for-each select="EmployeeDetails/Department/Employee/Ename">

                        <xsl:value-of select="text()"/>

                        <br/>

                  </xsl:for-each>

            </b>

      </xsl:template>

</xsl:stylesheet>

In either of the above cases, when the XSLT gets executed, the transformation looks something like the following:

<b>

      Jagadish<br />

      Chatarji<br />

      Winner<br />

      Dhanam<br />

      Chinna<br />

      Pedda<br />

      Ram<br />

      Robert<br />

      Rahim<br />

</b>

Retrieving all values of a particular element at any level of hierarchy (or path)

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:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">

            <b>

                  <xsl:apply-templates select ="//Ename"/>

            </b>

      </xsl:template>

      <xsl:template match="Ename">

            <xsl:value-of select ="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:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">

            <b>

                  <xsl:for-each select="//Ename">

                        <xsl:value-of select="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).

Retrieving all values of all elements at all 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):

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">

            <b>

                  <xsl:apply-templates select ="//*"/>

            </b>

      </xsl:template>

      <xsl:template match="*">

            <xsl:value-of select ="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).

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">

            <b>

                  <xsl:for-each select="//*">

                        <xsl:value-of select="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

blog comments powered by Disqus
ASP.NET ARTICLES

- Implementing ASP.NET 4.0 Page.MetaDescriptio...
- ASP.Net Development Tips
- Intro to Sessions in ASP.Net
- Google Maps API Introduction in ASP.NET usin...
- Creating an ASP.NET 3.5 Gridview Image Galle...
- Encrypt QueryString in ASP.NET 3.5 using VB....
- ASP.NET 3.5 Drop Down List Controls
- Connect to Access Database with ASP.Net
- Secure Audio Streaming with ASP.Net and Flash
- Dynamic Sitemap and Navigation in ASP.Net
- Implement Gzip and Deflate Compression in AS...
- Run ASP.Net in Ubuntu with Apache
- ASP.Net Mono Website Contact Forms
- ASP.Net URL Rewriting Methods
- Murach`s ASP.NET 4 Web Programming with C# 2...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 1 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials