ASP.NET : Display XML Data



I recently took the plunge and finally joined stackoverflow.com and I must say its quite a brilliant site (one of the best programming sites in my opinion) with a few very cleverly thought out concepts (badges, bounties, reputation etc).

I also managed to successfully hunt down my first bounty - something that I feel might make for an useful post.

Imagine you've got the following piece of XML:

XML/books.xml
 
<?xml version="1.0" encoding="utf-8" ?>
<authors>
  <author name="Edsger Wybe Dijkstra">
    <books>
      <book title="A Discipline of Programming" />
      <book title="A Method of Programming" />
      <book title="EWD316 - A Short Introduction to the Art of Programming" />
    </books>
  </author>
  <author name="Bjarne Stroustrup">
    <books>
      <book title="Programming: Principles and Practice Using C++" />
      <book title="The C++ Programming Language" />
      <book title="The Design and Evolution of C++" />
    </books>
  </author>
  <author name="Christoff Truter">
  </author>
</authors>
 

The XML file contains a list of famous programmers (and one not so famous) along with some of the books they wrote. In the first example I am going to bind a ListView control to a XmlDataSource in order to render the contents of the XML file, observe:
 
<asp:XmlDataSource runat="server" ID="xmlSource" XPath="authors/author" DataFile="~/XML/books.xml">
</asp:XmlDataSource>
 
<asp:ListView runat="server" ID="lvAuthors" ItemPlaceholderID="divAuthors" DataSourceID="xmlSource">
	<LayoutTemplate>
		<asp:PlaceHolder runat="server" ID="divAuthors"></asp:PlaceHolder>
	</LayoutTemplate>
	<ItemTemplate>
		<div>
			<h3>
				<%#XPath("@name") %>
			</h3>
		</div>
	</ItemTemplate>
</asp:ListView>
 

Notice the XPath attribute & expression, they basically provide the control with the means to navigate/display the appropriate nodes. You will also notice that we're only displaying a list of the authors (for abbreviation sake), but what about their books?

In the following snippet I nest a ListView within a ListView in order to achieve exactly that (list of authors including their books), observe:
 
<asp:ListView runat="server" ID="lvAuthors" ItemPlaceholderID="divAuthors" DataSourceID="xmlSource">
	<LayoutTemplate>
		<asp:PlaceHolder runat="server" ID="divAuthors"></asp:PlaceHolder>
	</LayoutTemplate>
	<ItemTemplate>
		<div>
			<h3>
				<%#XPath("@name") %>
			</h3>
			<asp:ListView runat="server" ID="lvBooks" DataSource='<%#XPathSelect("books/book") %>' ItemPlaceholderID="divBooks">
				<LayoutTemplate>
					<ul>
						<asp:PlaceHolder runat="server" ID="divBooks"></asp:PlaceHolder>
					</ul>
				</LayoutTemplate>
				<ItemTemplate>
					<li>
						<%#XPath("@title") %>
					</li>
				</ItemTemplate>
				<EmptyDataTemplate>
					No Books
				</EmptyDataTemplate>
			</asp:ListView>
		</div>
	</ItemTemplate>
</asp:ListView>
 

Notice the XPathSelect statement in the preceding snippet, this is where we assign the author books (child nodes) as DataSource to the nested ListView control.

The second method I am going to have a quick look at involves the Xml Control and a xslt file - which I am going to use to render/transform the XML file into HTML.

 
<asp:Xml ID="Xml1" runat="server" TransformSource="~/XML/books.xslt" DocumentSource="~/XML/books.xml"></asp:Xml>
 

Like in the first example (for abbreviation sake), we only display a list of authors at first.

XML/books.xslt
 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="utf-8" method="html" />
  <xsl:template match="authors/author">
    <div>
      <h3>
        <xsl:apply-templates select="@name"/>
      </h3>
    </div>
  </xsl:template>
</xsl:stylesheet>
 

In the following xslt snippet we achieve the same results - as via the nested ListView.

XML/books.xslt
 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="utf-8" method="html" />
  <xsl:template match="authors/author">
    <div>
      <h3>
        <xsl:apply-templates select="@name"/>
      </h3>
      <xsl:if test="books/book">
        <ul>
          <xsl:apply-templates select="books/book"/>
        </ul>
      </xsl:if>
      <xsl:if test="not(books/book)">
        No Books
      </xsl:if>
    </div>
  </xsl:template>
  <xsl:template match="books/book">
    <li>
      <xsl:apply-templates select="@title"/>
    </li>
  </xsl:template>
</xsl:stylesheet>
 

Additional Reading

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.xmldatasource.aspx
http://www.w3schools.com/xsl/default.asp
http://stackoverflow.com/questions/4803128/avoid-reloading-all-xml-data-for-each-repeater-vb-net/4849797#4849797





Post/View comments
 

Interesting Exceptions: C# - PathTooLongException



When I told one of my developer friends that I am going to write a post about the PathTooLongException, he found it rather amusing - how much could there really be to this Exception?

In Windows the full path of a file/folder can't be longer than 260 characters, this limit is enforced by the .net framework and normally by the operating system as well (one can't create a full path longer than 260 characters via windows explorer for example).

But recently however, I noticed a more interesting issue surrounding this exception while importing folders/files using a tool I wrote - quite a number of the paths exceeded the 260 character limit and obviously raised the PathTooLongException when the code attempted to import the folders/files.

Which obviously means that this limit can't exactly be set in stone.

After doing some digging (and playing around), I found its possible to circumvent the 260 limit programatically (Win32 API - Unicode via the "\\?\" prefix) and using 8.3 path names via the Windows console as well (upto aprox 32000 characters).

In the following snippet we succeed in creating paths longer than 260 characters via 8.3 file/folder names:

 
c:
cd\
md aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd aaaaaa~1
md aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd aaaaaa~1
dir c:\ > test.txt
 

The interesting thing (after running this snippet) on Windows XP/2003, is that one can't even browse to the file within the second folder - but on Windows 7/2008 (and I would imagine Vista as well) it was possible to browse to that file at least.

Now if we try to delete the folder (created via the previous snippet) using windows explorer, windows will swear at us (whoops you've just created a folder you can't remove, bwahaha).

Just joking, you will be able to remove those folders using the following snippet:

 
c:
cd\aaaaaa~1\aaaaaa~1
del test.txt
cd..
rd aaaaaa~1
cd..
rd aaaaaa~1
 

As for the second way (that I know of) to sidestep the 260 character limit, can be seen in the following extremely crude snippet (don't use as is) - via the Win32 API.

 
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
 
public static class LongPath
{
    static class Win32Native
    {
        [StructLayout(LayoutKind.Sequential)]
        public class SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr pSecurityDescriptor;
            public int bInheritHandle;
        }
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CreateDirectory(string lpPathName, SECURITY_ATTRIBUTES lpSecurityAttributes);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, SECURITY_ATTRIBUTES securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
    }
 
    public static bool CreateDirectory(string path)
    {
        return Win32Native.CreateDirectory(String.Concat(@"\\?\", path), null);
    }
 
    public static FileStream Open(string path, FileMode mode, FileAccess access)
    {
        SafeFileHandle handle = Win32Native.CreateFile(String.Concat(@"\\?\", path), (int)0x10000000, FileShare.None, null, mode, (int)0x00000080, IntPtr.Zero);
        if (handle.IsInvalid)
        {
            throw new System.ComponentModel.Win32Exception();
        }
        return new FileStream(handle, access);
    }
}
 

The interesting thing to note here, is that each segment created like this can't be longer than 255 characters (which is a bit longer than the folder names we can create via the 8.3 method) e.g. "c:\<255>\<255>\<255.ext>".

In the next snippet we apply the LongPath class as seen in the preceding snippet, which demonstrates how to access these files programmatically.

 
string path = @"c:\".PadRight(255, 'a');
LongPath.CreateDirectory(path);
 
path = String.Concat(path, @"\", "".PadRight(255, 'a'));
LongPath.CreateDirectory(path);
 
string filename = Path.Combine(path, "test.txt");
 
FileStream fs = LongPath.Open(filename, FileMode.CreateNew, FileAccess.Write);
 
using (StreamWriter sw = new StreamWriter(fs))
{
    sw.WriteLine("abc");
}
 

Another interesting thing to note, is that one can't browse to the folders created in the preceding snippet, in any of the Windows Operating systems - it is however still possible to access them via the windows console using 8.3 file/folder names.

All of this is a bit of an ugly situation, infact most of the apps I tested didn't support reading/importing files affected by this issue. Is this an issue we must simply ignore?

Additional Reading
http://www.hanno.co.za/post/2011/04/04/Copying-files-with-very-long-filenames-paths.aspx http://msdn.microsoft.com/en-us/library/aa365247.aspx
http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx
http://vlaurie.com/computers2/Articles/filenames.htm





Post/View comments
 
First 6 7 8 9 10 11 12 13 14 15 Last / 62 Pages (124 Entries)

Latest Posts

Be the best stalker you can be


2011-12-13 22:33:54

Syntactic sugar (C#): Enum


2011-08-04 16:50:18

Top 5 posts

Simple WYSIWYG Editor


Creating a WYSIWYG textbox for your website is actually quite simple.
2007-02-01 12:00:00

Moving items between listboxes in ASP.net/PHP example


Move items between two listboxes in ASP.net(C#, VB.NET) and PHP
2008-06-12 17:07:43

Cross Browser Issues: Firefox Word Wrapping


Firefox word wrapping issues
2008-06-09 09:51:21

Populate a TreeView Control C#


Populate a TreeView control in a windows application.
2009-08-27 16:01:03

C# YouTube : Google API


Post on how to integrate with YouTube using the Google Data API
2011-03-12 08:37:51