Click here to Skip to main content
15,889,034 members
Articles / Programming Languages / XML

Towards a Declarative SAX Framework : Part 1 - A Simple SAX-to-C#-Mapping

Rate me:
Please Sign up or sign in to vote.
4.51/5 (15 votes)
20 May 200422 min read 62.8K   894   33  
This article demonstrates a simple but flexible way to read XML content without DOM
#region Copyright
/*********************************************************************************
 * Copyright (c) 2004 by Martin Friedrich										 *
 * Permission to freely distribute, modify and compile these sources and		 *
 * binaries as long as this copyright notice is included.						 *
 * Use of code on your risk!													 *
 * *******************************************************************************/
#endregion

using System;
using System.Collections;
using System.Reflection;

namespace SaxParserSupport
{
	namespace Impl 
	{
		/// <summary>
		/// <p>Implements the <tt>XMLElement</tt> interface.</p>
		/// <p>By default, the <tt>onText</tt>, <tt>onSignificantWhitespace</tt> and
		/// <tt>onWhitespace</tt> callback do nothing.</p>
		/// <p><tt>XMLElementImpl</tt> collects child elements in an instance of
		/// class <tt>System.Collections.ArrayList</tt> in the order of appearence.
		/// However, child elements may be removed from this collection in response
		/// to end of element events handled by inheriting implementations. For
		/// example, this might be the case if the XML data is to be transformed into
		/// other, non-tree organized structures.</p>
		/// <p>Lookup of classes for child elements is done via the fully qualified
		/// tag name of child elements. This is done by providing pairs of tag names and
		/// class names. The later ones must be fully qualified, i.e. namespaces,
		/// class and inner class (if applicable) names must be present, along with 
		/// the assembly name.</p>
		/// <p>The mapping for classes is done on a per class basis. Therefore,
		/// static constructor should be use to build the maps.</p>
		/// <p>Classes to be used for child elements must have default constructor,
		/// i.e. with empty parameter lists.</p>
		/// <seealso cref="SaxParserSupport.Impl.XMLSimpleElementImpl"/>
		/// <seealso cref="SaxParserSupport.Impl.XMLDocumentImpl"/>
		/// </summary>
		public abstract class XMLElementImpl : XMLSimpleElementImpl, XMLElement
		{
			/// <summary>
			/// Constructs a new <tt>XMLElement</tt> instance.
			/// </summary>
			protected XMLElementImpl()
			{
			}

			/// <summary>
			/// <p>Creates an instance of a <tt>XMLSimpleElement</tt> class, that is to
			/// be used to represent a child XML element.</p>
			/// <p><tt>ElementClasses</tt> is queried to get the hashtable
			/// containing the mapping of XML element tag names to classes.</p>
			/// </summary>
			/// <param name="name">The qualified tag name of the child XML element</param>
			/// <returns>An instance of a <tt>XMLSimpleElement</tt> class that matches
			/// the given tag name</returns>
			/// <exception cref="System.Xml.XmlException">A matching class could not
			/// be found</exception>
			public XMLSimpleElement lookupElement( string name )
			{
				string classname;
				if ( ( classname = (string )ElementClasses[ name ] ) == null )
					throw new System.Xml.XmlException( "element \'" + name + "\' not found"
														+ Environment.NewLine
														+ "In: "
														+ GetType().FullName );

				Type resulttype = Type.GetType( classname, true );
				ConstructorInfo ci = resulttype.GetConstructor( Type.EmptyTypes );

				XMLSimpleElement el = (XMLSimpleElement )ci.Invoke( null );
				return el;
			}

			/// <summary>
			/// Writes the XML contents represented by this instance to a stream. This
			/// includes all attributes and child elements. 
			/// </summary>
			/// <remarks>This method may throw any execption relate with stream output
			/// </remarks>
			/// <param name="ostr">The stream to be used for output</param>
			public override void write( System.IO.StreamWriter ostr )
			{
				ostr.Write( "<{0}", getName() );
				writeAttributes( ostr );
				ostr.WriteLine( " >" );
				writeSubElements( ostr );
				ostr.WriteLine( "</{0}>", getName() );
			}

			/// <summary>
			/// Writes all subelements to <tt>ostr</tt> in the order determined
			/// by the <tt>_elements</tt> collection.
			/// </summary>
			/// <remarks><list type="bullet">
			/// <item>Text and whitespace sequences are NOT contained in the <i>_elements</i>
			/// collections.</item>
			/// <item>This method may throw any execption related to stream output.</item>
			/// </list>
			/// </remarks>
			/// <param name="ostr">The stream to be used for output</param>
			protected virtual void writeSubElements( System.IO.StreamWriter ostr )
			{
				if ( _elements != null ) 
				{
					foreach ( XMLSimpleElement i in _elements ) 
					{
						if ( i is XMLElement ) ((XMLElementImpl )i).write( ostr );
						else i.write( ostr );
					}
				}
			}

			/// <summary>
			/// Adds an instance of <tt>XMLSimpleElement</tt> to the <tt>_elements</tt>
			/// collections.
			/// </summary>
			/// <param name="el">The <tt>XMLSimpleElement</tt> instance to be added</param>
			public virtual void addElement( XMLSimpleElement el )
			{
				if ( _elements == null ) _elements = new ArrayList();
				_elements.Add( el );
			}

			/// <summary>
			/// Removes an instance of <tt>XMLSimpleElement</tt> from the <tt>_elements</tt>
			/// collection
			/// </summary>
			/// <param name="el">The <tt>XMLSimpleElement</tt> instance to be removed</param>
			public virtual void removeElement( XMLSimpleElement el )
			{
				if ( _elements != null ) 
				{
					_elements.Remove( el );
				}
			}

			/// <summary>
			/// Executed on encounter of text.
			/// </summary>
			/// <remarks>
			/// This implementation does nothing
			/// </remarks>
			/// <param name="txt">Contains the text</param>
			public virtual void onText( string txt )
			{
			}

			/// <summary>
			/// Executed on on encounter of significant whitespace
			/// </summary>
			/// <remarks>
			/// This implementation does nothing
			/// </remarks>
			/// <param name="txt">Contains the whitespace sequence</param>
			public virtual  void onSignificantWhitespace( string txt )
			{
			}

			/// <summary>
			/// Executed on on encounter of whitespace
			/// </summary>
			/// <remarks>
			/// This implementation does nothing
			/// </remarks>
			/// <param name="txt">Contains the whitespace sequence</param>
			public virtual void onWhitespace( string txt )
			{
			}

			/// <summary>
			/// A <tt>System.Collections.IDictionary</tt> that contains the mapping
			/// for possible child element classes.
			/// </summary>
			protected abstract IDictionary ElementClasses 
			{
				get;
			}

			/// <summary>
			/// Contains child elements in the order of their appearence in the XML
			/// content.
			/// </summary>
			protected ArrayList _elements = null;
		}
	}
}

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
Web Developer
Germany Germany

Still lacking an university degree in computer science, I have 20 years of experience in software development and implementation. Having expert knowledge in object-oriented programming languages like C++, Java and C# on Windows, LINUX and UNIX platforms, I participated in multiple research projects at the University of Oldenburg. During these assignments, I was trusted with implementation of a graphical editor for specification languages like CSP or Z and a prototypical tool for workflow data distribution and analysis. I gained experiences in a widespread spectrum of CS and software development topics, ranging from compiler construction across data base programming to MDA. My research interests include questions of graphical user interface design and component-based systems.


I consider myself an old-school CS geek. While I admit that simple tasks do not pose much of a problem and can be done in quick and efficient manner, it's the challenging ones that appeal to me. If you are looking for a skillful employee - be it on a permanent, contract or freelance basis - and if you can live with a lacking university degree, why not contacting me?


Comments and Discussions