Click here to Skip to main content
15,895,084 members
Articles / Programming Languages / XML

Xmi CodeDom Library, Part 1

Rate me:
Please Sign up or sign in to vote.
4.23/5 (15 votes)
26 May 2008CPOL5 min read 75K   770   45  
A .Net 2.0 library that converts XMI into CodeDom. Part 1 introduces the library.
// This code is copyright Dustin Metzgar.
// There are no restrictions to what you can do with this code.  If you do
// use it for something interesting, let me know (dustin.metzgar@gmail.com).

using System;
using System.CodeDom;
using System.Collections;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml;

namespace XmiParser
{
	/// <summary>
	/// A class that is designed to read XMI documents into the object model format used 
	/// by the code generation system.
	/// </summary>
	public class XmiHelper
	{
		private XmlDocument _OrigDoc;
		private Hashtable _XmiObjects;

		/// <summary>
		/// Whether or not the XML document is an XMI document.
		/// </summary>
		public bool IsXmiDocument 
		{
			get 
			{
				try 
				{
					return _OrigDoc.DocumentElement.Name == "XMI";
				}
				catch 
				{
					return false;
				}
			}
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="doc"></param>
		public XmiHelper(XmlDocument doc)
		{
			_OrigDoc = doc;
			_XmiObjects = new Hashtable();
		}

		/// <summary>
		/// Finds a xmi object by its xmi id.
		/// </summary>
		/// <param name="xmiId"></param>
		/// <returns></returns>
		public XmiBaseObject FindObjectByXmiId(string xmiId) 
		{
			return _XmiObjects[xmiId] as XmiBaseObject;
		}

		/// <summary>
		/// Parses the XMI document.
		/// </summary>
		public void ParseXmi() 
		{
			Hashtable htElems = GetElementTable();
			foreach (string elemName in htElems.Keys) 
			{
				XmlNodeList nl = _OrigDoc.SelectNodes("XMI/XMI.content//" + elemName);
				Type t = htElems[elemName] as Type;
				foreach (XmlElement el in nl) 
				{
					XmiBaseObject xbo = Activator.CreateInstance(t, new object[] { el, this }) as XmiBaseObject;
					if (!xbo.IsIdRef)
						_XmiObjects.Add(xbo.XmiId, xbo);
				}
			}
		}

		/// <summary>
		/// Gets a list of all the xmi objects collected.
		/// </summary>
		/// <returns></returns>
		public XmiBaseObject[] GetObjects() 
		{
			ArrayList al = new ArrayList(_XmiObjects.Values);
			return (XmiBaseObject[])al.ToArray(typeof(XmiBaseObject));
		}

		/// <summary>
		/// The element table reads the current assembly for all the classes that extend <see cref="XmiBaseObject"/>.
		/// The resulting Hashtable has the name of the XMI element as the key, and the Type of the class that reads
		/// it as the value.
		/// </summary>
		/// <returns></returns>
		private Hashtable GetElementTable() 
		{
			Hashtable ht = new Hashtable();
			Assembly asm = this.GetType().Assembly;
			Type[] types = asm.GetTypes();
			foreach (Type t in types) 
			{
				if (t.IsSubclassOf(typeof(XmiBaseObject))) 
				{
					object[] attr = t.GetCustomAttributes(typeof(XmiElementNameAttribute), true);
					if (attr.Length > 0) 
					{
						XmiElementNameAttribute xena = attr[0] as XmiElementNameAttribute;
						ht.Add(xena.ElementName, t);
					}
				}
			}
			return ht;
		}

		/// <summary>
		/// Returns a CodeCompileUnit that has all the classes read from the XMI in it.
		/// </summary>
		/// <returns></returns>
		public CodeCompileUnit GetCodeDomModel() 
		{
			if (!IsXmiDocument)
				throw new ArgumentException("Document is not a valid XMI document!");
			ParseXmi();
			CodeCompileUnit ccu = new CodeCompileUnit();
			foreach (XmiNamespace xn in GetNamespaces()) 
			{
				CodeNamespace cn = new CodeNamespace(EnsureNamespaceName(xn.Name));
				ccu.Namespaces.Add(cn);
				cn.Imports.Add(new CodeNamespaceImport("System"));
				foreach (XmiClass xc in GetClassesInNamespace(xn)) 
				{
					CodeTypeDeclaration ctd = xc.GetCodeDomClass();
					cn.Types.Add(ctd);
				}
			}
			return ccu;
		}

		private XmiNamespace[] GetNamespaces() 
		{
			ArrayList al = new ArrayList();
			XmiBaseObject[] xmiObjects = GetObjects();
			foreach (XmiBaseObject xbo in xmiObjects) 
			{
				if (xbo is XmiNamespace)
					al.Add(xbo);
			}
			return (XmiNamespace[])al.ToArray(typeof(XmiNamespace));
		}

		private XmiClass[] GetClassesInNamespace(XmiNamespace xn) 
		{
			ArrayList al = new ArrayList();
			XmiBaseObject[] xmiObjects = GetObjects();
			foreach (XmiBaseObject xbo in xmiObjects) 
			{
				if (xbo is XmiClass) 
				{
					XmiClass xc = xbo as XmiClass;
					if (xn.XmiId == xc.NamespaceId)
						al.Add(xc);
				}
			}
			return (XmiClass[])al.ToArray(typeof(XmiClass));
		}

		private static string EnsureNamespaceName(string ns) 
		{
			if (ns == null || ns.Length == 0)
				return "UnknownNamespace";
			Regex re = new Regex("[^a-zA-Z0-9_]");
			string s = re.Replace(ns, "");
			re = new Regex("^0-9");
			while (s.Length > 1 && re.IsMatch(s))
				s = s.Substring(1);
			if (s.Length == 1 && re.IsMatch(s))
				return "UnknownNamespace";
			return s;
		}
	}
}

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
Software Developer Microsoft
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