Click here to Skip to main content
15,893,594 members
Articles / Programming Languages / XML

Enumerate over XML data in a foreach loop

Rate me:
Please Sign up or sign in to vote.
4.91/5 (22 votes)
11 Jan 20053 min read 99.1K   892   50  
An article which shows how to enumerate over XML data in a foreach loop as if the data were in a collection.
using System;
using System.IO;
using System.Xml;
using System.Collections;

namespace CustomerEnumeration
{
	/// <summary>
	/// Exposes information about customers.  This class can be enumerated over in a foreach loop.
	/// </summary>
	public class Customers : IEnumerable, IDisposable
	{
		private CustomerEnumerator custEnumerator = null;

		#region IEnumerable Members

		// When the foreach loop begins, this method is invoked so that the loop gets an enumerator to query.
		public IEnumerator GetEnumerator()
		{
			if( this.custEnumerator == null )
				this.custEnumerator = new CustomerEnumerator();
			return this.custEnumerator;
		}

		#endregion IEnumerable Members

		#region IDisposable Members

		public void Dispose()
		{
			if( this.custEnumerator != null )
				this.custEnumerator.Dispose();
		}

		#endregion
	}

	/// <summary>
	/// Exposes the customer data found in Customers.xml.
	/// </summary>
	public class CustomerEnumerator : IEnumerator, IDisposable
	{
		#region Data

		private readonly string        fileName = @"..\..\Customers.xml";
		private          XmlTextReader reader;

		#endregion Data

		#region IEnumerator Members

		public void Reset()
		{
			if( this.reader != null )
				this.reader.Close();
			System.Diagnostics.Debug.Assert( File.Exists( this.fileName ), "Customer file does not exist!" );
			StreamReader stream = new StreamReader( this.fileName );
			this.reader         = new XmlTextReader( stream );
		}

		public bool MoveNext()
		{
			// Call Reset the first time MoveNext is called instead of in the constructor 
			// so that we keep the stream open only as long as needed.
			if( this.reader == null )
				this.Reset();
			if( this.FindNextTextElement() )
				return true;
			this.reader.Close();
			return false;
		}

		public object Current
		{
			get
			{
				// No need to call FindNextTextElement here because it was called for us by MoveNext().
				string firstName = this.reader.Value;

				// Set 'val' to a default value in case the element was empty.
				string val = "";
				if( this.FindNextTextElement() )
					val = this.reader.Value;

				string lastName = val;

				// Set 'val' to a default value in case the element was empty.
				val = "0";
				if( this.FindNextTextElement() )
					val = this.reader.Value;

				int     orders;
				try   { orders = Int32.Parse( val ); }
				catch {	orders = Int32.MinValue;     }

				// Set 'val' to a default value in case the element was empty.
				val = "0";
				if( this.FindNextTextElement() )
					val = this.reader.Value;

				decimal balance;
				try   { balance = Decimal.Parse( val ); }
				catch { balance = Decimal.MinValue;     }

				return new Customer( firstName, lastName, orders, balance );
			}
		}

		#endregion

		#region Private Helper

		/// <summary>
		/// Advances the XmlTextReader to the next Text element in the XML stream.
		/// Returns true if there is more data to be read from the stream, else false.
		/// </summary>
		private bool FindNextTextElement()
		{
	bool readOn = this.reader.Read();
	bool prevTagWasElement = false;
	while( readOn && this.reader.NodeType != XmlNodeType.Text )
	{
		// If the current element is empty, stop reading and return false.
		if( prevTagWasElement &&  this.reader.NodeType == XmlNodeType.EndElement )
			readOn = false;
		prevTagWasElement = this.reader.NodeType == XmlNodeType.Element;
		readOn = readOn && this.reader.Read();
	}
	return readOn;
		}

		#endregion Private Helper

		#region IDisposable Members

		public void Dispose()
		{
			if( this.reader != null )
				this.reader.Close();
		}

		#endregion

		#region Finalizer

		~CustomerEnumerator()
		{
			this.Dispose();
		}

		#endregion // Finalizer
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
Josh creates software, for iOS and Windows.

He works at Black Pixel as a Senior Developer.

Read his iOS Programming for .NET Developers[^] book to learn how to write iPhone and iPad apps by leveraging your existing .NET skills.

Use his Master WPF[^] app on your iPhone to sharpen your WPF skills on the go.

Check out his Advanced MVVM[^] book.

Visit his WPF blog[^] or stop by his iOS blog[^].

See his website Josh Smith Digital[^].

Comments and Discussions