Click here to Skip to main content
15,891,431 members
Articles / Programming Languages / C#

A Very Easy to Use Excel XML Import-Export Library

Rate me:
Please Sign up or sign in to vote.
4.18/5 (86 votes)
25 Nov 2008CPOL13 min read 647.9K   19.6K   356  
Import export library for the Excel XML format, which reduces a programmer's work to the bare minimum.
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Xml;

namespace Yogesh.Extensions
{
	/// <summary>
	/// Extended xml attribute
	/// </summary>
	public class XmlReaderAttributeItem
	{
		/// <summary>
		/// Name of attribute
		/// </summary>
		public string Name { get; set; }
		/// <summary>
		/// Local name of attribute
		/// </summary>
		public string LocalName { get; set; }
		/// <summary>
		/// Value of attribute
		/// </summary>
		public string Value { get; set; }
		/// <summary>
		/// Prefix if any
		/// </summary>
		public string Prefix { get; set; }
		/// <summary>
		/// Has a value?
		/// </summary>
		public bool HasValue { get; set; }
	}

	/// <summary>
	/// DateSpan class used to computer difference of two dates
	/// </summary>
	public class DateSpan
	{
		/// <summary>
		/// Difference in days
		/// </summary>
		public int Days { get; set; }
		/// <summary>
		/// Difference in months
		/// </summary>
		public int Months { get; set; }
		/// <summary>
		/// Difference in years
		/// </summary>
		public int Years { get; set; }
	}

	/// <summary>
	/// Object extensions methods which are available if you are using VS2008
	/// </summary>
	public static class ObjectExtensions
	{
		/// <summary>
		/// Returns specified number of characters from the left of string
		/// </summary>
		/// <param name="text">String on which extension method is used</param>
		/// <param name="chars">Number of chars to return</param>
		/// <returns>Returns specified number of characters from the left of string</returns>
		public static string Left(this string text, int chars)
		{
			return text.Substring(0, Math.Min(text.Length, chars));
		}

		/// <summary>
		/// Returns specified number of characters from the right of string
		/// </summary>
		/// <param name="text">String on which extension method is used</param>
		/// <param name="chars">Number of chars to return</param>
		/// <returns>Returns specified number of characters from the right of string</returns>
		public static string Right(this string text, int chars)
		{
			if (text.Length <= chars)
				return text;

			return text.Substring(text.Length - chars, chars);
		}

		/// <summary>
		/// Checks if the string is empty or only contains spaces
		/// </summary>
		/// <param name="text">String on which extension method is used</param>
		/// <returns>true if empty, false otherwise</returns>
		public static bool IsNullOrEmpty(this string text)
		{
			if (text == null)
				return true;

			return string.IsNullOrEmpty(text.Trim());
		}

		/// <summary>
		/// Checks if the string is a valid email address
		/// </summary>
		/// <param name="inputEmail">String on which extension method is used</param>
		/// <returns>true if valid email address, false otherwise</returns>
		public static bool IsValidEmail(this string inputEmail)
		{
			return IsValidEmail(inputEmail, false);
		}

		/// <summary>
		/// Checks if the string is empty or only contains spaces
		/// </summary>
		/// <param name="inputEmail">String on which extension method is used</param>
		/// <param name="isEmptyValid">Is a empty string is considered a valid email address?</param>
		/// <returns>true if empty, false otherwise</returns>
		public static bool IsValidEmail(this string inputEmail, bool isEmptyValid)
		{
			if (inputEmail.IsNullOrEmpty())
			{
				if (isEmptyValid)
					return true;
				else
					return false;
			}

			string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
				  @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
				  @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";

			Regex re = new Regex(strRegex);

			if (re.IsMatch(inputEmail))
				return true;

			return false;
		}

		private static XmlDocument _staticDoc;
		/// <summary>
		/// XML encodes a string
		/// </summary>
		/// <param name="text">String on which extension method is used</param>
		/// <returns>returns the encoded string</returns>
		public static string XmlEncode(this string text)
		{
			if (text == null)
				return "";

			if (_staticDoc == null)
			{
				_staticDoc = new XmlDocument();
				_staticDoc.LoadXml("<text></text>");
			}
			lock (_staticDoc)
			{
				_staticDoc.LastChild.InnerText = text;

				return _staticDoc.LastChild.InnerXml;
			}
		}

		/// <summary>
		/// Parses a string to a integar form
		/// </summary>
		/// <typeparam name="T">Integar type</typeparam>
		/// <param name="text">String to parse</param>
		/// <param name="variable">Variable to store value to</param>
		/// <returns>true if parse was successful, false otherwiseParsed string</returns>
		[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")]
		public static bool ParseToInt<T>(this string text, out T variable)
		{
			if (!typeof(T).IsPrimitive && typeof(T).FullName != "System.Decimal")
				throw new ArgumentException("'variable' must only be a primitive type");

			decimal d;

			if (!decimal.TryParse(text, NumberStyles.Number,
				CultureInfo.InvariantCulture, out d))
			{
				variable = default(T);

				return false;
			}

			variable = (T)Convert.ChangeType(d, typeof(T), CultureInfo.InvariantCulture);

			return true;
		}

		/// <summary>
		/// Checks whether a enum value is correct or not
		/// </summary>
		/// <param name="enumerator">Enumerator on which extension method is used</param>
		/// <returns>returns true if valid, false otherwise</returns>
		/// <remarks>
		/// This is a interesting function. If you set a enum to a int value, you can use
		/// this function to test the value to be correct or not. What is special about this
		/// function is that if you use the Flags attribute for the enum, it will check if the
		/// value is a right bit wise match. This can better be understood with the example
		/// provided.
		/// </remarks>
		/// <example>
		/// <code>
		/// public enum NonFlagEnum
		/// {
		/// 	One = 1,
		/// 	Two = 2,
		/// 	Three = 4,
		/// 	Four = 8,
		/// 	Five = 16
		/// }
		/// 
		/// [Flags]
		/// public enum FlagEnum
		/// {
		/// 	One = 1,
		/// 	Two = 2,
		/// 	Three = 4,
		/// 	Four = 8,
		/// 	Five = 16,
		/// }
		/// 
		/// // Non flaged
		/// NonFlagEnum nfe = NonFlagEnum.One;
		/// nfe.IsValid(); // true
		/// 
		/// nfe = (NonFlagEnum) 5;
		/// nfe.IsValid(); // false
		/// 
		/// nfe = (NonFlagEnum) 21;
		/// nfe.IsValid(); // false
		/// 
		/// nfe = (NonFlagEnum) 32;
		/// nfe.IsValid(); // false
		/// 
		/// nfe = NonFlagEnum.One | NonFlagEnum.Four;
		/// nfe.IsValid(); // false because 9 is not present in the enum
		/// 
		/// // Flaged
		/// FlagEnum fe = FlagEnum.One;
		/// fe.IsValid(); // true
		/// 
		/// fe = (FlagEnum) 5;
		/// // true because value will be FlagEnum.One | FlagEnum.Three
		/// fe.IsValid();
		/// 
		/// fe = (FlagEnum) 21;
		/// // true because value will be: 
		/// // FlagEnum.Five | FlagEnum.Three | FlagEnum.One
		/// fe.IsValid();
		/// 
		/// fe = (FlagEnum) 32;
		/// fe.IsValid(); // false
		/// 
		/// fe = FlagEnum.One | FlagEnum.Four;
		/// fe.IsValid(); // true
		/// </code>
		/// </example>
		public static bool IsValid(this Enum enumerator)
		{
			bool defined = Enum.IsDefined(enumerator.GetType(), enumerator);

			if (!defined)
			{
				FlagsAttribute[] attributes =
					(FlagsAttribute[])enumerator.GetType().GetCustomAttributes(
					typeof(FlagsAttribute), false);

				if (attributes != null && attributes.Length > 0)
					return enumerator.ToString().Contains(",");
			}

			return defined;
		}

		/// <summary>
		/// Returns enum's description
		/// </summary>
		/// <param name="enumerator">Enumerator on which extension method is used</param>
		/// <returns>If the enum value has a <code>DescriptionAttribute</code>, returns the
		/// description, otherwise returns <code>ToString()</code></returns>
		public static string GetDescription(this Enum enumerator)
		{
			FieldInfo fi = enumerator.GetType().GetField(enumerator.ToString());

			DescriptionAttribute[] attributes =
				(DescriptionAttribute[])fi.GetCustomAttributes(
				typeof(DescriptionAttribute), false);

			if (attributes != null && attributes.Length > 0)
				return attributes[0].Description;

			return enumerator.ToString();
		}

		/// <summary>
		/// Check whether a flag is set in a particular enum value
		/// </summary>
		/// <param name="enumerator">Enumerator on which extension method is used</param>
		/// <param name="enumFlag">Enumerator flag to check</param>
		/// <returns>returns true if flag set, false otherwise</returns>
		[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flag")]
		public static bool IsFlagSet(this Enum enumerator, Enum enumFlag)
		{
			if (!enumerator.IsValid())
				return false;

			if (!enumFlag.IsValid())
				return false;

			if (enumerator.GetType() != enumFlag.GetType())
				return false;

			int enumValue = (int)Enum.Parse(enumerator.GetType(), enumerator.ToString());
			int flagValue = (int)Enum.Parse(enumFlag.GetType(), enumFlag.ToString());

			return ((enumValue & flagValue) == flagValue);
		}

		/// <summary>
		/// Returns difference of two dates
		/// </summary>
		/// <param name="date">DateTime on which extension method is used</param>
		/// <param name="dateToCompare">The second date to compare difference with</param>
		/// <returns>return DateSpan instance of the calculated date difference</returns>
		/// <remarks>The computation always is date - dateToCompare, so dateToCompare should be
		/// lesser than date. If it is not, the answer is always a little bit... ahem... weird.</remarks>
		public static DateSpan DateDifference(this DateTime date, DateTime dateToCompare)
		{
			int totalMonths = ((date.Year - dateToCompare.Year) * 12) +
				date.Month - dateToCompare.Month;

			int days = 0;

			if (date.Day < dateToCompare.Day)
			{
				int day, month, year;

				day = dateToCompare.Day;
				if (date.Month == 1)
				{
					month = 12;
					year = date.Year - 1;
				}
				else
				{
					month = date.Month - 1;
					year = date.Year;
				}

				DateTime dateCalculator = new DateTime(year, month, day);

				days = (date - dateCalculator).Days;

				totalMonths--;
			}
			else
			{
				days = date.Day - dateToCompare.Day;
			}

			DateSpan ds = new DateSpan();
			ds.Years = totalMonths / 12;
			ds.Months = totalMonths % 12;
			ds.Days = days;

			return ds;
		}

		/// <summary>
		/// Extension method to get a single attribute and its value
		/// </summary>
		/// <param name="reader">XmlReader on which extension method is used</param>
		/// <param name="attribute">Attribute to read</param>
		/// <returns>XmlReaderAttributeItem instance if attribute found, null otherwise</returns>
		public static XmlReaderAttributeItem GetSingleAttribute(this XmlReader reader, string attribute)
		{
			return GetSingleAttribute(reader, attribute, false);
		}

		/// <summary>
		/// Extension method to get a single attribute and its value
		/// </summary>
		/// <param name="reader">XmlReader on which extension method is used</param>
		/// <param name="attribute">Attribute to read</param>
		/// <param name="moveToEnd">Move to the end of the element?</param>
		/// <returns>XmlReaderAttributeItem instance if attribute found, null otherwise</returns>
		public static XmlReaderAttributeItem GetSingleAttribute(this XmlReader reader, string attribute, bool moveToEnd)
		{
			string element = reader.Name;
			if (moveToEnd && reader.IsEmptyElement)
				moveToEnd = false;

			foreach (XmlReaderAttributeItem xa in reader.GetAttributes())
			{
				if (xa.LocalName == attribute)
				{
					if (moveToEnd)
						while (reader.Read() && !(reader.Name == element && reader.NodeType == XmlNodeType.EndElement)) ;

					return xa;
				}
			}

			if (moveToEnd)
				while (reader.Read() && !(reader.Name == element && reader.NodeType == XmlNodeType.EndElement)) ;

			return null;
		}

		/// <summary>
		/// Extension method to get a all attribute of a element
		/// </summary>
		/// <param name="reader">XmlReader on which extension method is used</param>
		/// <returns>List of all attributes as XmlReaderAttributeItem</returns>
		public static IEnumerable<XmlReaderAttributeItem> GetAttributes(this XmlReader reader)
		{
			List<XmlReaderAttributeItem> list = new List<XmlReaderAttributeItem>();

			if (!reader.HasAttributes)
				return list;

			reader.MoveToFirstAttribute();
			list.Add(ReadAttribute(reader));

			while (reader.MoveToNextAttribute())
				list.Add(ReadAttribute(reader));

			return list;
		}

		private static XmlReaderAttributeItem ReadAttribute(XmlReader reader)
		{
			XmlReaderAttributeItem attr = new XmlReaderAttributeItem();

			attr.Name = reader.Name;
			attr.LocalName = reader.LocalName;
			attr.Prefix = reader.Prefix;
			attr.HasValue = reader.HasValue;

			if (attr.HasValue)
				attr.Value = reader.Value;
			else
				attr.Value = "";

			return attr;
		}

		/// <summary>
		/// Parses a enum from a string 
		/// </summary>
		/// <typeparam name="T">Enum type</typeparam>
		/// <param name="value">String to parse</param>
		/// <returns>Parsed enum value</returns>
		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
		public static T ParseEnum<T>(string value)
		{
			return (T)Enum.Parse(typeof(T), value);
		}

		/// <summary>
		/// Checks where a type is a numeric type
		/// </summary>
		/// <param name="type">Type to check</param>
		/// <returns>true if type is numeric type, false otherwise</returns>
		public static bool IsNumericType(Type type)
		{
			string typeName = type.FullName;

			switch (typeName)
			{
				case "System.SByte":
				case "System.Int16":
				case "System.Int32":
				case "System.Int64":
				case "System.Byte":
				case "System.UInt16":
				case "System.UInt32":
				case "System.UInt64":
				case "System.Single":
				case "System.Double":
				case "System.Decimal":
					return true;
			}

			return false;
		}
	}
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India

Comments and Discussions