using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Xml; using Chernobyl.Collections.Generic.Event; using Chernobyl.Reflection.Template.CodeDom; namespace Chernobyl.Reflection.Template.Xml { /// /// An that is generated from or can be written to /// an XML stream. /// public class XmlMember : Member { /// /// Initializes a new instance of the class. /// /// The instance that /// takes and sets service. /// The this /// belongs to. /// The to read the members /// from. /// Thrown if the /// is not positioned on an /// (see ) of /// . public XmlMember(IEventCollection services, IInstance instance, XmlReader xmlr) : base(services, string.Empty, instance) { if (xmlr.NodeType != XmlNodeType.Element) throw new ArgumentException("Unable to extract the XML member data because " + "The XmlReader passed into this constructor is not positioned on an " + "XML element. Please ensure the XmlReader is positioned correctly.", "xmlr"); // read this member and process any instances in it. Name = xmlr.LocalName; // grab all of the attributes off of the member. XmlAttribute.Create(services, xmlr); // Make sure we go past the attributes, if they exist, and drop back // down on the element. After that, we'll want to move to the elements // content or the next node. If the element is not empty we'll process // the elements content xmlr.MoveToElement(); bool emptyElement = xmlr.IsEmptyElement; if(emptyElement == true) { // this member may link to an instance, so we'll check it and // load the linked instance in if so. string xlinkHrefValue = xmlr.GetAttribute(XmlInstance.XlinkHref.AttributeName, XmlInstance.XlinkHref.AttributeUri); if (xlinkHrefValue != null) ComponentChildren.Add(new LinkedInstance(services, new XmlInstance.XlinkHref(xlinkHrefValue), new Instance(services))); // we need to call Read after to skip this element, don't do it // before the call to GetAttribute tor we won't be pulling the // attribute from the proper element xmlr.Read(); } else { // we need to call Read before the call to Create so that we can // move to the next element to read in the instance(s). xmlr.Read(); // read in the member's arguments foreach (IInstance component in XmlInstance.Create(services, xmlr)) ComponentChildren.Add(component); } } /// /// Creates a collection of instances by /// reading them from an . /// /// The instance that /// takes and sets service. /// The the /// s belong to. /// The to read the members /// from. /// The s that have been created. /// Thrown if this method cannot process one /// of the members because it is not one of the supported members (a /// property, method, or field). public static IMember[] Create(IEventCollection services, IInstance instance, XmlReader xmlr) { if (xmlr.NodeType != XmlNodeType.Element && xmlr.NodeType != XmlNodeType.Text) throw new ArgumentException("Unable to extract the XML member data because " + "The XmlReader passed into this method is not positioned on an " + "XML element or text node. Please ensure the XmlReader is positioned correctly.", "xmlr"); List xmlMembers = new List(); int startDepth = xmlr.Depth; bool finished = false; do { // get to the element if we aren't already on one if (xmlr.NodeType == XmlNodeType.Element || xmlr.NodeType == XmlNodeType.Text) { // check if the node that we are on is a member. If it isn't, then we // are on a instance or an "Arguments" element and we need to create // a constructor to read in this instance and any other potential instances. bool childrenWereMembers = false; if (xmlr.LocalName.Length != 0) { MemberInfo[] memberInfos = instance.Type.GetMember(xmlr.LocalName); if (memberInfos.Length != 0) { MemberInfo memberInfo = memberInfos.First(); switch (memberInfo.MemberType) { case MemberTypes.Property: xmlMembers.Add(new CodeDomProperty(new XmlMember(services, instance, xmlr))); break; case MemberTypes.Method: { // if the method has one of the qualifiers // specified by CodeDomEvent, then this // method is an add or remove method for // an event and needs to be created as // an event. if (memberInfo.Name.StartsWith(CodeDomEvent.AddNameQualifier) == true || memberInfo.Name.StartsWith(CodeDomEvent.RemoveNameQualifier) == true) xmlMembers.Add(new CodeDomEvent(new XmlMember(services, instance, xmlr))); else xmlMembers.Add(new CodeDomMethod(new XmlMember(services, instance, xmlr))); } break; case MemberTypes.Field: xmlMembers.Add(new CodeDomField(new XmlMember(services, instance, xmlr))); break; case MemberTypes.Event: xmlMembers.Add(new CodeDomEvent(new XmlMember(services, instance, xmlr))); break; default: throw new Exception("Unable to process \"" + xmlr.Name + "\" on the instance \"" + instance.Name + "\", it is not a property, method, or field."); } childrenWereMembers = true; } } // in the event the child element is not a recognized if (childrenWereMembers == false) xmlMembers.Add(new CodeDomConstructor(new XmlConstructor(services, instance, xmlr))); } else finished = !xmlr.Read(); } while (xmlr.Depth >= startDepth && finished == false); return xmlMembers.ToArray(); } } }