2012-10-22 17:18:04 +00:00
|
|
|
|
#region Using Statements
|
|
|
|
|
using System;
|
2012-09-28 20:57:30 +00:00
|
|
|
|
using System.Collections.Generic;
|
2012-10-02 20:05:12 +00:00
|
|
|
|
using System.Diagnostics;
|
2012-09-28 20:57:30 +00:00
|
|
|
|
using System.IO;
|
2012-10-02 20:05:12 +00:00
|
|
|
|
using System.Linq;
|
2012-09-29 16:17:59 +00:00
|
|
|
|
using System.Reflection;
|
2012-09-28 20:57:30 +00:00
|
|
|
|
using System.Xml;
|
2012-10-02 21:28:13 +00:00
|
|
|
|
using System.Xml.Linq;
|
2012-09-28 20:57:30 +00:00
|
|
|
|
using ANX.Framework.NonXNA.Development;
|
2012-09-29 16:17:59 +00:00
|
|
|
|
using ANX.Framework.NonXNA.Reflection;
|
2012-10-22 17:18:04 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
// This file is part of the ANX.Framework created by the
|
|
|
|
|
// "ANX.Framework developer group" and released under the Ms-PL license.
|
|
|
|
|
// For details see: http://anxframework.codeplex.com/license
|
2012-09-28 20:57:30 +00:00
|
|
|
|
|
|
|
|
|
namespace ANX.Framework.Content.Pipeline.Importer
|
|
|
|
|
{
|
2012-10-02 22:05:42 +00:00
|
|
|
|
[ContentImporter(new[] {".xml"})]
|
2012-09-28 20:57:30 +00:00
|
|
|
|
[Developer("SilentWarrior / Eagle Eye Studios")]
|
2012-10-02 22:05:42 +00:00
|
|
|
|
[PercentageComplete(90)]
|
|
|
|
|
[TestState(TestStateAttribute.TestState.InProgress)]
|
2012-09-28 20:57:30 +00:00
|
|
|
|
public class XmlImporter : ContentImporter<object>
|
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
private XDocument _doc;
|
2012-09-28 20:57:30 +00:00
|
|
|
|
public override object Import(string filename, ContentImporterContext context)
|
|
|
|
|
{
|
|
|
|
|
object result;
|
|
|
|
|
context.Logger.LogMessage("Checking if file exists.");
|
|
|
|
|
if (!File.Exists(filename))
|
|
|
|
|
throw new InvalidContentException("The XML file \"" + filename + "\" could not be found.");
|
|
|
|
|
|
|
|
|
|
context.Logger.LogMessage("Starting analysis of the XML file.");
|
|
|
|
|
using (XmlReader xml = XmlReader.Create(filename))
|
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
_doc = XDocument.Load(filename);
|
2012-09-28 20:57:30 +00:00
|
|
|
|
//Check if XML contains XnaContent or AnxContent root element
|
|
|
|
|
context.Logger.LogMessage("Checking for root element.");
|
2012-10-02 21:28:13 +00:00
|
|
|
|
var tag = _doc.Element("XnaContent");
|
|
|
|
|
if (tag == null)
|
|
|
|
|
{
|
|
|
|
|
tag = _doc.Element("AnxContent");
|
|
|
|
|
if (tag == null)
|
|
|
|
|
throw new InvalidContentException(
|
|
|
|
|
"The Xml file does not contain a valid XnaContent or AnxContent tag.");
|
|
|
|
|
}
|
|
|
|
|
//Check which type is beeing described in the XML by grabbing the Asset node
|
|
|
|
|
var assetNode = _doc.Descendants("Asset").ToArray()[0];
|
|
|
|
|
if (assetNode == null)
|
|
|
|
|
throw new InvalidContentException("Xml document does not contain an asset definition.");
|
|
|
|
|
Type type = null;
|
|
|
|
|
foreach (var attrib in assetNode.Attributes().Where(attrib => attrib.Name == "Type"))
|
|
|
|
|
{
|
2012-10-02 22:05:42 +00:00
|
|
|
|
type = GetType(attrib.Value);
|
2012-10-02 21:28:13 +00:00
|
|
|
|
}
|
|
|
|
|
if (type == null)
|
|
|
|
|
throw new InvalidContentException("There is no assembly within the search path that contains such type.");
|
2012-10-02 22:05:42 +00:00
|
|
|
|
context.Logger.LogImportantMessage("Type is " + type);
|
2012-09-28 20:57:30 +00:00
|
|
|
|
//Create an instance of that type and fill it with the appropriate stuff
|
2012-10-02 21:28:13 +00:00
|
|
|
|
result = ReadObject(type, context.Logger);
|
2012-10-02 22:05:42 +00:00
|
|
|
|
context.Logger.LogMessage("XmlImporter has finished.");
|
2012-09-28 20:57:30 +00:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-02 22:13:26 +00:00
|
|
|
|
private static Type GetType(string typeString)
|
2012-09-28 20:57:30 +00:00
|
|
|
|
{
|
2012-10-02 22:05:42 +00:00
|
|
|
|
//TODO: Implement custom assembly path checking
|
2012-10-02 21:28:13 +00:00
|
|
|
|
//Check every assembly in the current working dir for type
|
|
|
|
|
foreach (
|
|
|
|
|
var file in
|
|
|
|
|
Directory.GetFiles(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location), "*.dll"))
|
2012-09-29 16:17:59 +00:00
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
try
|
2012-09-29 16:17:59 +00:00
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
Assembly assembly = Assembly.LoadFrom(file);
|
|
|
|
|
foreach (Type type in TypeHelper.SafelyExtractTypesFrom(assembly))
|
2012-09-29 16:17:59 +00:00
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
if (type.FullName == typeString)
|
2012-09-29 16:17:59 +00:00
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
return type;
|
2012-09-29 16:17:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-10-02 21:28:13 +00:00
|
|
|
|
}
|
2012-11-04 08:46:52 +00:00
|
|
|
|
catch //(Exception ex)
|
2012-10-02 21:28:13 +00:00
|
|
|
|
{
|
2012-11-04 08:46:52 +00:00
|
|
|
|
//Debugger.Break(); //TODO: Go and check whats wrong and handle exceptions properly
|
2012-09-29 16:17:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-10-02 22:05:42 +00:00
|
|
|
|
Type t = Type.GetType(typeString);
|
|
|
|
|
return t;
|
2012-09-28 20:57:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-02 21:28:13 +00:00
|
|
|
|
private object ReadObject(Type type, ContentBuildLogger logger)
|
2012-09-28 20:57:30 +00:00
|
|
|
|
{
|
|
|
|
|
var props = new Dictionary<string, object>();
|
2012-10-02 21:28:13 +00:00
|
|
|
|
|
|
|
|
|
var assetNode = _doc.Descendants("Asset").ToArray()[0]; //Get first node again, can not be null cause we checked it before
|
|
|
|
|
var nodes = assetNode.Descendants();
|
|
|
|
|
|
|
|
|
|
foreach (var xElement in nodes.Where(xElement => xElement.Name != "Item" && xElement.Name != "Key" && xElement.Name != "Value")) //Reserved keywords
|
2012-09-28 20:57:30 +00:00
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
if (!xElement.HasElements) //Normal node
|
|
|
|
|
{
|
2012-10-02 22:05:42 +00:00
|
|
|
|
string key = xElement.Name.LocalName;
|
|
|
|
|
object value = XmlContentToObject(xElement);
|
|
|
|
|
props.Add(key, value);
|
2012-10-02 21:28:13 +00:00
|
|
|
|
}
|
|
|
|
|
else //List or Dictionary
|
|
|
|
|
{
|
2012-10-02 22:05:42 +00:00
|
|
|
|
var theItem = xElement.Descendants("Item");
|
|
|
|
|
if (theItem.Any())
|
2012-10-02 21:28:13 +00:00
|
|
|
|
{
|
2012-10-02 22:05:42 +00:00
|
|
|
|
if (theItem.Descendants("Key").Any() && theItem.Descendants("Value").Any()) // is a dictionary
|
2012-09-29 16:17:59 +00:00
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
var dic = new Dictionary<string, object>();
|
|
|
|
|
foreach (var item in xElement.Descendants("Item"))
|
2012-09-29 16:17:59 +00:00
|
|
|
|
{
|
2012-10-02 21:28:13 +00:00
|
|
|
|
var key = item.Descendants("Key").ToArray()[0].Value;
|
2012-10-02 22:05:42 +00:00
|
|
|
|
object value = XmlContentToObject(item.Descendants("Value").ToArray()[0]);
|
2012-10-02 21:28:13 +00:00
|
|
|
|
dic.Add(key, value);
|
2012-09-29 16:17:59 +00:00
|
|
|
|
}
|
2012-10-02 21:28:13 +00:00
|
|
|
|
props.Add(xElement.Name.LocalName, dic);
|
|
|
|
|
}
|
|
|
|
|
else //must be a list
|
|
|
|
|
{
|
2012-10-02 22:05:42 +00:00
|
|
|
|
var list = xElement.Descendants("Item").Select(XmlContentToObject).ToList();
|
2012-10-02 21:28:13 +00:00
|
|
|
|
props.Add(xElement.Name.LocalName, list);
|
|
|
|
|
}
|
2012-09-29 16:17:59 +00:00
|
|
|
|
}
|
2012-10-02 21:28:13 +00:00
|
|
|
|
}
|
2012-09-28 20:57:30 +00:00
|
|
|
|
}
|
|
|
|
|
//Activate instance
|
2012-10-02 20:05:12 +00:00
|
|
|
|
var constructors = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
|
|
|
|
|
var result = constructors[0].Invoke(new object[] {});
|
2012-09-28 20:57:30 +00:00
|
|
|
|
|
2012-10-02 20:05:12 +00:00
|
|
|
|
var properties = type.GetFields(BindingFlags.Instance | BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Public);
|
|
|
|
|
foreach (var property in properties)
|
|
|
|
|
{
|
|
|
|
|
var attribs = property.GetCustomAttributes(typeof (ContentSerializerAttribute), true);
|
|
|
|
|
if (attribs.Length == 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (props.ContainsKey(((ContentSerializerAttribute)attribs[0]).ElementName))
|
|
|
|
|
{
|
|
|
|
|
property.SetValue(result, props[((ContentSerializerAttribute)attribs[0]).ElementName]);
|
|
|
|
|
props.Remove(((ContentSerializerAttribute)attribs[0]).ElementName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (props.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
logger.LogWarning("", null, "There are unset properties left!", result);
|
|
|
|
|
Debugger.Break();
|
|
|
|
|
}
|
2012-09-28 20:57:30 +00:00
|
|
|
|
|
|
|
|
|
//Return the whole construct
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2012-09-29 16:17:59 +00:00
|
|
|
|
|
2012-10-02 22:13:26 +00:00
|
|
|
|
public static object XmlContentToObject(XElement item)
|
2012-09-29 16:17:59 +00:00
|
|
|
|
{
|
2012-10-02 22:05:42 +00:00
|
|
|
|
if (!item.HasAttributes && !item.HasElements) // String
|
|
|
|
|
{
|
|
|
|
|
return item.Value;
|
|
|
|
|
}
|
|
|
|
|
else if (item.HasAttributes && !item.HasElements)
|
|
|
|
|
{
|
|
|
|
|
var stuffs = item.Attributes("Type").ToArray();
|
|
|
|
|
string typeString = stuffs[0].Value;
|
|
|
|
|
var type = GetType(typeString);
|
|
|
|
|
if (type == typeof(Single))
|
|
|
|
|
return Convert.ToSingle(item.Value);
|
2012-10-02 22:13:26 +00:00
|
|
|
|
if (type == typeof(Int32))
|
|
|
|
|
return Convert.ToInt32(item.Value);
|
|
|
|
|
if (type == typeof(Int64))
|
|
|
|
|
return Convert.ToInt64(item.Value);
|
|
|
|
|
if (type == typeof(Double))
|
|
|
|
|
return Convert.ToDouble(item.Value);
|
|
|
|
|
if (type == typeof(Boolean))
|
|
|
|
|
return Convert.ToBoolean(item.Value);
|
2012-10-02 22:05:42 +00:00
|
|
|
|
throw new NotSupportedException("Sorry, conversion of type \"" + type + "\" is currently not supported.");
|
|
|
|
|
}
|
|
|
|
|
throw new NotSupportedException("Conversion of nested stuff is not supported! If you have the time, go ahead and implement it! :P");
|
2012-09-29 16:17:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-09-28 20:57:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|