C# XML Directory Lister






4.29/5 (8 votes)
Oct 22, 2000

255606

6654
Generates a directory list as XML
This is an update to a project I wrote using the .NET alpha release. This version works with the .NET Beta 2 release.
I was looking for a useful little project to start learning C# and the .NET framework. In my job we do a lot of things with XML so I was interested in exercising some of the XML classes. In particular I wanted to see how XML and ADO+ fit together. The result is the code in this project.
This code generates a list of entries in a directory as XML. The XML can be
returned to the caller as an XML string, a W3C DOM document, or an ADO+ DataSet
.
A word of WARNING. To compile the attached code, you need to have the .NET Framework SDK Beta 2 installed which. You can get the .NET Framework SDK here. Please don't send me questions regarding installation of the SDK.
Below is the source code for the XML directory lister:
using System; using System.IO; using System.Xml; using System.Data; namespace GregHack.XMLStuff.Cs { /// <summary> /// This class generates a list of files in a directory as XML. It can /// return the XML as a string, a W3C DOM document, or a DataSet. I /// wrote this code to learn about the XML capabilities of the framework /// work specifically with the DataSets. /// </summary> public class XMLDirectoryLister { private Boolean m_bUseDOMCalls; /// <summary> /// Constructor /// </summary> /// <param name="bUseDOMCalls">Use W3C DOM calls to build XML?</param> /// <returns>None</returns> public XMLDirectoryLister( Boolean bUseDOMCalls ) { m_bUseDOMCalls = bUseDOMCalls; } /// <summary> /// This method generates a list of files in a directory as XML and /// returns the XML as a string. /// </summary> /// <param name="strDirectory">List files in this directory</param> /// <returns>A XML string with the directory file list</returns> public string getXMLString( string strDirectory ) { string strXML = ""; XmlDocument doc = getXML( strDirectory ); if ( doc != null ) { StringWriter writer = new StringWriter(); doc.Save( writer ); strXML = writer.ToString(); } doc = null; return strXML; } /// <summary> /// This method generates a list of files in a directory as XML and /// returns the XML as a DataSet. /// </summary> /// <param name="strDirectory">List files in this directory</param> /// <returns>A DataSet with the directory file list</returns> public DataSet getXMLDataset( string strDirectory ) { DataSet ds = null; string strXML = getXMLString( strDirectory ); XmlDataDocument datadoc = new XmlDataDocument(); datadoc.DataSet.ReadXml( new StringReader(strXML) ); ds = datadoc.DataSet; return ds; } /// <summary> /// This public method generates a list of files in a directory as XML and /// returns the XML as a W3C DOM document. /// </summary> /// <param name="strDirectory">List files in this directory</param> /// <returns>A W3C DOM docuemnt with the directory file list</returns> public XmlDocument getXMLDocument( string strDirectory ) { return getXML( strDirectory ); } private XmlDocument getXML( string strDirectory ) { XmlDocument xmlDoc; if ( m_bUseDOMCalls ) xmlDoc = getXMLUsingDOMCalls( strDirectory ); else xmlDoc = getXMLUsingTextWriterClass( strDirectory ); return xmlDoc; } /// <summary> /// This private method generates a list of files in a directory as XML and /// returns the XML as a W3C DOM document using the DOM calls. /// </summary> /// <param name="strDirectory">List files in this directory</param> /// <returns>A W3C DOM docuemnt with the directory file list</returns> private XmlDocument getXMLUsingDOMCalls( string strDirectory ) { // Create the document. XmlDocument doc = new XmlDocument(); // Insert the xml processing instruction and the root node XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "", "yes"); doc.PrependChild ( dec ); // Add the root element XmlElement nodeElem = doc.CreateElement( "dirlist" ); doc.AppendChild( nodeElem ); Boolean bFirst = true; // Process the directory list DirectoryInfo dir = new DirectoryInfo( strDirectory ); foreach ( FileSystemInfo entry in dir.GetFileSystemInfos() ) { if ( bFirst == true ) { // If we haven't added any elements yet, go ahead and add a text element which // contains the full directory path. XmlElement root = doc.DocumentElement; String strFullName = entry.FullName; String strFileName = entry.Name; String strDir = strFullName.Substring( 0, strFullName.Length - strFileName.Length ); root.SetAttribute ("dir", strDir ); bFirst = false; } // Add a new text node with a tag entry. There will be one added per // item encountered in the directory. XmlElement elem = doc.CreateElement("entry"); doc.DocumentElement.AppendChild(elem); // Write out the things we are interested in about this entry in the // directory. addTextElement( doc, elem, "name", entry.Name ); addTextElement( doc, elem, "created", entry.CreationTime.ToString() ); addTextElement( doc, elem, "lastaccess", entry.LastAccessTime.ToString() ); addTextElement( doc, elem, "lastwrite", entry.LastWriteTime.ToString() ); addTextElement( doc, elem, "isfile", ( (entry.Attributes & FileAttributes.Directory) > 0 ) ? "False" : "True" ); addTextElement( doc, elem, "isdir", ( (entry.Attributes & FileAttributes.Directory) > 0 ) ? "True" : "False" ); addTextElement( doc, elem, "readonly", ( (entry.Attributes & FileAttributes.ReadOnly) > 0 ) ? "True" : "False" ); } return doc; } /// <summary> /// This private method adds a text element to the XML document as the last /// child of the current element. /// </summary> /// <param name="doc">The XML document</param> /// <param name="nodeParent">Parent of the node we are adding</param> /// <param name="strTag">The tag of the element to add</param> /// <param name="strValue">The text value of the new element</param> private void addTextElement( XmlDocument doc, XmlElement nodeParent, string strTag, string strValue ) { XmlElement nodeElem = doc.CreateElement( strTag ); XmlText nodeText = doc.CreateTextNode( strValue ); nodeParent.AppendChild( nodeElem ); nodeElem.AppendChild( nodeText ); } /// <summary> /// This private method generates a list of files in a directory as XML and /// returns the XML as a W3C DOM document using the XmlTextWriter class. /// </summary> /// <param name="strDirectory">List files in this directory</param> /// <returns>A W3C DOM docuemnt with the directory file list</returns> private XmlDocument getXMLUsingTextWriterClass( string strDirectory ) { StringWriter writerString = new StringWriter(); XmlTextWriter writer = new XmlTextWriter( writerString ); writer.WriteStartDocument(true); Boolean bFirst = true; // Process the directory list DirectoryInfo dir = new DirectoryInfo( strDirectory ); foreach ( FileSystemInfo entry in dir.GetFileSystemInfos() ) { if ( bFirst == true ) { // If we haven't added any elements yet, go ahead and add a text element which // contains the full directory path. writer.WriteStartElement( "dirlist", "" ); String strFullName = entry.FullName; String strFileName = entry.Name; String strDir = strFullName.Substring( 0, strFullName.Length - strFileName.Length ); writer.WriteAttributeString( "dir", strDir ); bFirst = false; } // Add a new text node with a tag entry. There will be one added per // item encountered in the directory. writer.WriteStartElement( "entry", "" ); // Write out the things we are interested in about this entry in the // directory. writer.WriteElementString( "name", entry.Name ); writer.WriteElementString( "created", entry.CreationTime.ToString() ); writer.WriteElementString( "lastaccess", entry.LastAccessTime.ToString() ); writer.WriteElementString( "lastwrite", entry.LastWriteTime.ToString() ); writer.WriteElementString( "isfile", ( (entry.Attributes & FileAttributes.Directory) > 0 ) ? "False" : "True" ); writer.WriteElementString( "isdir", ( (entry.Attributes & FileAttributes.Directory) > 0 ) ? "True" : "False" ); writer.WriteElementString( "readonly", ( (entry.Attributes & FileAttributes.ReadOnly) > 0 ) ? "True" : "False" ); writer.WriteEndElement(); // entry } writer.WriteEndElement(); // dirlist writer.WriteEndDocument(); string strXML = writerString.ToString(); StringReader reader = new StringReader( strXML ); XmlDocument doc = new XmlDocument(); doc.Load( reader ); return doc; } } }
The first thing of interest is the following code:
namespace GregHack.XMLStuff.Cs
This says that I am creating a namespace for my code. Code that references the
XMLDirectoryLister
will have to include the following line:
using GregHack.XMLStuff.Cs;
The meat of the work is done in the getXMLUsingDOMCalls()
and
the getXMLUsingTextWriterClass()
methods. They both create
a W3C document via the XmlDocument
class of the .NET framework but using
alternate methods to do so. The first method uses the XmlDocument
class
of the framework to add to and traverse the XML document. The second method uses the
XMLTextWriter
class to accomplish the same thing.
Both implementations loop through all of the entries in the directory using the
foreach
syntax of C#:
foreach ( FileSystemEntry entry in dir.GetFileSystemEntries() )
The XmlDocument
version uses the AppendChild()
method
to insert elements into the document that represent the entries in the directory. The
XMLTextWriter
version uses WriteElementString()
to accomplish
the same thing.
Something that I thought was pretty cool is how easy it is to translate XML into
an ADO+ DataSet
. The following lines of code that are in the getXMLDataset
are all that are needed:
DataSet ds = null; string strXML = getXMLString( strDirectory ); XmlDataDocument datadoc = new XmlDataDocument(); datadoc.DataSet.ReadXml( new StringReader(strXML) ); ds = datadoc.DataSet; return ds;
The ReadXml
method will parse the XML passed in and come up
with a database schema based on the XML.
The sample project contains a command line test .exe and a the XMLDirectoryLister
compiled
as a DLL. It generates XML of the form:
<?xml version='1.0' ?> <dirlist dir="C:\anet\XML Directory\"> <entry> <name>XMLDirectoryLister.bak</name> <created>9/21/2000 21:13:34</created> <lastaccess>9/21/2000 00:00:00</lastaccess> <lastwrite>9/21/2000 21:53:54</lastwrite> <isfile>True</isfile> <isdir>False</isdir> <readonly>False</readonly> </entry> <entry> <name>XMLDirectoryLister.dll</name> <created>9/21/2000 19:19:13</created> <lastaccess>9/21/2000 00:00:00</lastaccess> <lastwrite>9/21/2000 21:12:20</lastwrite> <isfile>True</isfile> <isdir>False</isdir> <readonly>False</readonly> </entry> </dirlist>
When the getXMLDataset()
method is called, it returns a DataSet
with two tables dirlist
and entry
. Entry has 7 columns,
name, created, lastaccess, lastwrite, isfile, isdir, readonly
. You can see the
relationship between the XML and the tables.
One last thing of interest is the class and method documentation. You'll notice it
uses three forward slashes and some XML tags. If
you use this style you can tell the compiler to emit XML documentation as output. It
will then create and XML file containing the documentation you put in your source file.
The XML could then be rendered as HTML or some other format to document you source. Use
a specifier in your makefile such as /doc:XMLDirectoryLister.xml
to emit
the XML documentation file. The sample project contains the XML documentation emitted
by the compiler.