using System.Xml; using System.Collections.Generic; using System; using System.Collections; using System.IO; namespace Persistence { public class XmlParser : IEnumerable { private readonly XmlReader reader; private delegate IEnumerator Handler(); private readonly Dictionary handlers; public XmlParser(TextReader input) { XmlReaderSettings settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Document, IgnoreWhitespace = true, IgnoreComments = true }; reader = XmlReader.Create(input, settings); handlers = new Dictionary { {"PRIMITIVE", ParsePrimitive}, {"COMPOSITE", ParseComposite}, {"REFERENCE", ParseReference}, {"NULL", ParseNull} }; } public IEnumerator GetEnumerator() { while (reader.Read()) { if (!reader.IsStartElement()) { break; } IEnumerator iterator; try { iterator = handlers[reader.Name].Invoke(); } catch (KeyNotFoundException) { throw new InvalidOperationException(String.Format( "No handler for XML tag \"{0}\" installed", reader.Name)); } while (iterator.MoveNext()) { yield return iterator.Current; } } } private IEnumerator ParsePrimitive() { int? id = null; string idString = reader.GetAttribute("id"); if (idString != null) id = int.Parse(idString); yield return new Primitive( reader.GetAttribute("name"), Type.GetType(reader.GetAttribute("type")), reader.ReadString(), id); } private IEnumerator ParseComposite() { string name = reader.GetAttribute("name"); Type type = Type.GetType(reader.GetAttribute("type")); string idString = reader.GetAttribute("id"); int? id = null; if (idString != null) id = int.Parse(idString); yield return new CompositeStart(name, type, id); IEnumerator iterator = GetEnumerator(); while (iterator.MoveNext()) yield return iterator.Current; yield return new CompositeEnd(name, type, id); } private IEnumerator ParseReference() { yield return new Reference( reader.GetAttribute("name"), int.Parse(reader.GetAttribute("ref"))); } private IEnumerator ParseNull() { yield return new Null(reader.GetAttribute("name")); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }