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();
}
}
}