Click here to Skip to main content
15,892,298 members
Articles / Programming Languages / XML

Delegate-Based XML Processor for Configuring Objects from XML

Rate me:
Please Sign up or sign in to vote.
4.38/5 (5 votes)
20 Aug 2006CPOL2 min read 29.5K   72   13  
Here is a flexible, memory-efficient way of parsing an XML without dealing with the intricacies of XmlReader
/*
 * Created by: Otto von Wachter
 * Created: Saturday, August 19, 2006
 */

using System.Collections;
using System.Xml;

namespace XmlProcessor
{
	public class XmlProcessor
	{
		XmlTextReader rdr;		
		ArrayList configs = new ArrayList();
		Stack elementStack = new Stack();

		public XmlProcessor(XmlTextReader rdr)
		{
			this.rdr = rdr;
		}

		public void RegisterElementHandler(string elementName, ElementHandler handler)
		{
			ElementHandlerConfig config = new ElementHandlerConfig(elementName, handler);
			configs.Add(config);
		}
		
		public void Start()
		{
			bool lastElementEmpty = false;
			while (rdr.Read())
			{
				if (!rdr.IsStartElement())
				{
					//pop off because we reached a closing tag
					elementStack.Pop();
					continue;
				}
				else if (lastElementEmpty)
				{
					//pop off because this is not a sub-element of last
					elementStack.Pop();
				}
				Element parent = elementStack.Count == 0? null : (Element) elementStack.Peek(); 
				Element el = new Element(rdr.Name, parent);
				LoadAttributes(el);
				elementStack.Push(el);
				ElementHandler handler = FindHandler(rdr.Name);
				if (handler != null)
					handler(el);
				
				lastElementEmpty = rdr.IsEmptyElement;
			}
		}
			
		private ElementHandler FindHandler(string name)
		{
			ElementHandlerConfig config = null;
			for (int i = 0; i < configs.Count; i++)
			{
				ElementHandlerConfig cfg = (ElementHandlerConfig) configs[i];
				if (cfg.ElementName == name)
				{
					config = cfg;
					break;					
				}
			}
			return config != null ? config.handler : null;
		}

		private void LoadAttributes(Element element)
		{
			rdr.MoveToFirstAttribute();
			for (int col=0;col<rdr.AttributeCount;col++)
			{
				element.Attributes[rdr.Name]=rdr.Value;
				rdr.MoveToNextAttribute();
			}
			rdr.MoveToElement();			
		}
	}
	
	public class Element
	{
		public string Name; 
		public IDictionary Attributes = new Hashtable();
		public Element Parent;
		public object Peer;  //arbitrary object to associate with this element

		public Element(string name, Element parent)
		{
			Name = name;
			Parent = parent;
		}
		
		public override string ToString()
		{
			if (Parent != null) 
				return Parent.ToString() + "/" + Name;
			else 
				return Name;
		}

		public Element FindAncestorByElementName(string name)
		{
			Element cur = this;
			while (cur.Parent != null)
			{
				cur = cur.Parent;
				if (cur.Name == name)
					return cur;
			}
			return null;
		}		
	}
	
	public class ElementHandlerConfig
	{		
		public string ElementName;
		public ElementHandler handler;

		public ElementHandlerConfig(string elementName, ElementHandler handler)
		{
			ElementName = elementName;
			this.handler = handler;
		}
	}
	
	public delegate void ElementHandler(Element element);
}

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
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions