Saturday, October 11, 2008

Using XSLT files with the new XMLDataSource control

I’ve spent almost 2 hours trying to add XMLDataSource to my project and all my attempts were unsuccessful. After some googling I’ve found wonderful article that describes exactly the same problem as for me. So I’m reprinting it here.


VS 2005 RTM (.net framework 2.0)
Target: Intermediate Developers

Consider you have an XML file like this:

 

<Employees>

  <Employee FirstName="Tom" LastName="Jones" CustomerId="1" />

  <Employee FirstName="John" LastName="Doe" CustomerId="2" />

</Employees>

 

 

You wish to display the data in a DropDownList with the DataTextField set to the FirstName and the DataValueField set to the CustomerId..

 

..and you do not want to write any code ;-)

Here is how you do it.

Drag and drop an
XmlDataSource and DropDownList control on to your page. Set their properties like so:

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/Employees.xml"></asp:XmlDataSource>

<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="XmlDataSource1"

DataTextField="FirstName" DataValueField="CustomerId">

</asp:DropDownList>


Run the page.

The DropDownList will get rendered like so:

<select name="DropDownList1" id="DropDownList1">

<option value="1">Tom</option>

<option value="2">John</option>

</select>

What if the XML file were like this (where the values were elements instead of attributes)?

<Employees>

  <Employee>

    <FirstName>Tom</FirstName>

    <LastName>Jones</LastName>

    <CustomerId>1</CustomerId>

  </Employee>

  <Employee>

    <FirstName>John</FirstName>

    <LastName>Doe</LastName>

    <CustomerId>2</CustomerId>

  </Employee>

</Employees>

 

Our page will fail with the following error:
DataBinding: 'System.Web.UI.WebControls.XmlDataSourceNodeDescriptor' does not contain a property with the name 'FirstName'.


The reason is that attributes of XML elements are promoted to properties and exposed through the XmlDataSource during databinding. In our case, FirstName is an element instead of an attribute which leads to the error.

 

So what can we do about this? Easy, we have to figure out how to transform the FirstName, CustomerId so that they become attributes of the parent node - Employee. In other words, we need to transform the second XML file so that it looks like the first XML file. This is were XSLTs come in. Explaining XLSTs is beyond the scope of this post. Please use your search engine to learn more J
XSLT Reference

The
XmlDataSource allows you to specify an XSLT file where you can define a transformation that will be applied to the DataFile you specified. 
 

Add an XSL file to your project and enter the following  (In brief, the XSLT below will transform the XML file resulting in the  FirstName, CustomerId elements becoming attributes of the Employee node)


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="Employees">

    <Employees>

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

    </Employees>

  </xsl:template>

  <xsl:template match="Employee">

    <Employee>

      <xsl:attribute name="FirstName">

        <xsl:value-of select="FirstName"/>

      </xsl:attribute>

      <xsl:attribute name="CustomerId">

        <xsl:value-of select="CustomerId"/>

      </xsl:attribute>

    </Employee>

  </xsl:template>

</xsl:stylesheet>

Set the XmlDataSource’s TransformFile property to point to this XSL file. Our page will look like this:

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/Employees.xml" TransformFile="~/XSLTFile.xsl"></asp:XmlDataSource>

<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="XmlDataSource1"

           DataTextField="FirstName" DataValueField="CustomerId">

    </asp:DropDownList>

 

The DropDownList will now get rendered like so:

<select name="DropDownList1" id="DropDownList1">

<option value="1">Tom</option>

<option value="2">John</option>

</select>

 

What if you wanted to display the FirstName, LastName in the DataTextField separated by a comma?

Easy! Change the XSL file to this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="Employees">

    <Employees>

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

    </Employees>

  </xsl:template>

  <xsl:template match="Employee">

    <Employee>

      <xsl:attribute name="FullName">

        <xsl:value-of select="FirstName"/>

        <xsl:text xml:space="preserve">, </xsl:text>

        <xsl:value-of select="LastName"/>

      </xsl:attribute>

      <xsl:attribute name="CustomerId">

        <xsl:value-of select="CustomerId"/>

      </xsl:attribute>

    </Employee>

  </xsl:template>

</xsl:stylesheet>


Note that we changed the attribute name to FullName.  

Note also the xml:space attribute which specifies that the space after the comma should be preserved.

Now change the page to this:

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/Employees.xml" TransformFile="~/XSLTFile.xsl"></asp:XmlDataSource>

<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="XmlDataSource1"

           DataTextField="FullName" DataValueField="CustomerId">

    </asp:DropDownList>


The DropDownList will get rendered like this:


<select name="DropDownList1" id="DropDownList1">

     <option value="1">Tom, Jones</option>

     <option value="2">John, Doe</option>

</select>

 

No comments: