Darabonba/Utils/XmlUtils.cs (336 lines of code) (raw):
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
using Darabonba;
namespace Darabonba.Utils
{
public class XmlUtils
{
public static Dictionary<string, object> ParseXml(string body, Type response)
{
return DeserializeXml(body, response);
}
public static string ToXML(Dictionary<string, object> body)
{
return SerializeXml(body);
}
internal static Dictionary<string, object> DeserializeXml(string xmlStr, Type type)
{
Dictionary<string, object> result = new Dictionary<string, object>();
XmlDocument contentXmlDoc = new XmlDocument();
contentXmlDoc.LoadXml(xmlStr);
XmlNodeList nodeList = contentXmlDoc.ChildNodes;
for (int i = 0; i < nodeList.Count; i++)
{
XmlNode root = nodeList.Item(i);
if (type != null)
{
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo p in properties)
{
Type propertyType = p.PropertyType;
NameInMapAttribute attribute = p.GetCustomAttribute(typeof(NameInMapAttribute)) as NameInMapAttribute;
string realName = attribute == null ? p.Name : attribute.Name;
if (root.Name == realName)
{
if (!typeof(Model).IsAssignableFrom(propertyType))
{
result.Add(realName, root.InnerText);
}
else
{
result.Add(realName, GetDictFromXml(root, propertyType));
}
}
}
}
else
{
ElementToDict(root, result);
}
}
if (result.ContainsKey("xml") && result["xml"].ToString().Contains("version=\"1.0\""))
{
result.Remove("xml");
}
return result;
}
private static Dictionary<string, object> GetDictFromXml(XmlNode element, Type type)
{
Dictionary<string, object> nodeDict = new Dictionary<string, object>();
PropertyInfo[] properties = type.GetProperties();
for (int i = 0; i < properties.Length; i++)
{
PropertyInfo p = properties[i];
Type propertyType = p.PropertyType;
NameInMapAttribute attribute = p.GetCustomAttribute(typeof(NameInMapAttribute)) as NameInMapAttribute;
string realName = attribute == null ? p.Name : attribute.Name;
XmlNodeList node = element.SelectNodes(realName);
if (node != null && node.Count > 0)
{
int count = (node[0].OuterXml.Length - node[0].OuterXml.Replace(realName, "").Length) / realName.Length;
if (count > 1)
{
if (typeof(IList).IsAssignableFrom(propertyType))
{
Type innerPropertyType = propertyType.GetGenericArguments()[0];
if (typeof(Model).IsAssignableFrom(innerPropertyType))
{
IList dicList = new List<Dictionary<string, object>>();
for (int j = 0; j < node.Count; j++)
{
dicList.Add(GetDictFromXml(node.Item(j), innerPropertyType));
}
nodeDict.Add(realName, dicList);
}
else
{
var dicList = (IList)Activator.CreateInstance(propertyType);
for (int j = 0; j < node.Count; j++)
{
var value = mapObj(innerPropertyType, node.Item(j).InnerText);
dicList.Add(value);
}
nodeDict.Add(realName, dicList);
}
}
else if (typeof(Model).IsAssignableFrom(propertyType))
{
nodeDict.Add(realName, GetDictFromXml(node.Item(0), propertyType));
}
else
{
string value = node.Item(0).InnerText;
nodeDict.Add(realName, mapObj(propertyType, value));
}
}
}
else
{
nodeDict.Add(realName, null);
}
}
return nodeDict;
}
private static object mapObj(Type propertyType, string value)
{
if (value == null)
{
return null;
}
else if (propertyType == typeof(int?))
{
return Convert.ToInt32(value);
}
else if (propertyType == typeof(long?))
{
return Convert.ToInt64(value);
}
else if (propertyType == typeof(float?))
{
return Convert.ToSingle(value);
}
else if (propertyType == typeof(double?))
{
return Convert.ToDouble(value);
}
else if (propertyType == typeof(bool?))
{
return Convert.ToBoolean(value);
}
else if (propertyType == typeof(short?))
{
return Convert.ToInt16(value);
}
else if (propertyType == typeof(ushort?))
{
return Convert.ToUInt16(value);
}
else if (propertyType == typeof(uint?))
{
return Convert.ToUInt32(value);
}
else if (propertyType == typeof(ulong?))
{
return Convert.ToUInt64(value);
}
else
{
return Convert.ChangeType(value, propertyType);
}
}
private static object ElementToDict(XmlNode element, Dictionary<string, object> nodeDict)
{
XmlNodeList elements = element.ChildNodes;
if (elements.Count == 0 || (elements.Count == 1 && !elements[0].HasChildNodes))
{
string context = string.IsNullOrEmpty(element.InnerText.Trim()) ? null : element.InnerText.Trim();
if (nodeDict != null)
{
nodeDict.Add(element.Name, context);
}
return context;
}
else
{
Dictionary<string, object> subDict = new Dictionary<string, object>();
if (nodeDict != null)
{
nodeDict.Add(element.Name, subDict);
}
foreach (XmlNode subNode in elements)
{
if (subDict.ContainsKey(subNode.Name))
{
object o = subDict[subNode.Name];
Type type = o.GetType();
if (typeof(IList).IsAssignableFrom(type))
{
((IList)o).Add(ElementToDict(subNode, null));
}
else if (typeof(IDictionary).IsAssignableFrom(type))
{
List<object> list = new List<object>();
Dictionary<string, object> remove = (Dictionary<string, object>)subDict[subNode.Name];
subDict.Remove(subNode.Name);
list.Add(remove);
list.Add(ElementToDict(subNode, null));
subDict.Add(subNode.Name, list);
}
else
{
List<object> list = new List<object>();
list.Add(o);
subDict.Remove(subNode.Name);
list.Add(ElementToDict(subNode, null));
subDict.Add(subNode.Name, list);
}
}
else
{
ElementToDict(subNode, subDict);
}
}
return subDict;
}
}
internal static string SerializeXml(object obj)
{
Type type = obj.GetType();
if (typeof(Model).IsAssignableFrom(type))
{
return SerializeXmlByModel((Model)obj);
}
else if (obj is Dictionary<string, object>)
{
return SerializeXmlByDict((Dictionary<string, object>)obj);
}
else
{
return string.Empty;
}
}
internal static string SerializeXmlByModel(Model obj)
{
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();
if (obj == null || properties.Length == 0)
{
return string.Empty;
}
PropertyInfo propertyInfo = properties[0];
NameInMapAttribute attribute = propertyInfo.GetCustomAttribute(typeof(NameInMapAttribute)) as NameInMapAttribute;
string realName = attribute == null ? propertyInfo.Name : attribute.Name;
object rootObj = propertyInfo.GetValue(obj);
XElement element = new XElement(realName);
GetXmlFactory(rootObj, element);
return element.ToString();
}
private static string SerializeXmlByDict(Dictionary<string, object> dict)
{
if (dict == null || dict.Count == 0)
{
return string.Empty;
}
string nodeName = dict.Keys.ToList()[0];
XElement element = new XElement(nodeName);
GetXmlFactory(dict[nodeName], element);
return element.ToString();
}
private static void GetXmlFactory(object obj, XElement element, XElement xParent = null)
{
if (obj == null)
{
return;
}
Type type = obj.GetType();
if (typeof(IList).IsAssignableFrom(type))
{
if (xParent == null)
{
throw new ArgumentException("unsupported nest list.");
}
IList list = (IList)obj;
string nodeName = element.Name.LocalName;
for (int j = 0; j < list.Count; j++)
{
XElement xNode = new XElement(nodeName);
GetXmlFactory(list[j], xNode);
xParent.Add(xNode);
}
return;
}
if (typeof(Model).IsAssignableFrom(type))
{
GetXml((Model)obj, element);
}
else if (typeof(IDictionary).IsAssignableFrom(type))
{
Dictionary<string, object> newDict = CastDict((IDictionary)obj)
.ToDictionary(entry => (string)entry.Key, entry => entry.Value);
GetXml(newDict, element);
}
else
{
element.Add(obj);
}
if (xParent != null)
{
xParent.Add(element);
}
}
private static IEnumerable<DictionaryEntry> CastDict(IDictionary dictionary)
{
foreach (DictionaryEntry entry in dictionary)
{
yield return entry;
}
}
private static void GetXml(Dictionary<string, object> dict, XElement element)
{
foreach (var keypair in dict)
{
XElement xNode = new XElement(keypair.Key);
GetXmlFactory(keypair.Value, xNode, element);
}
}
private static void GetXml(Model model, XElement element)
{
Type type = model.GetType();
PropertyInfo[] properties = type.GetProperties();
for (int i = 0; i < properties.Length; i++)
{
PropertyInfo propertyInfo = properties[i];
Type property = propertyInfo.PropertyType;
NameInMapAttribute attribute = propertyInfo.GetCustomAttribute(typeof(NameInMapAttribute)) as NameInMapAttribute;
string realName = attribute == null ? propertyInfo.Name : attribute.Name;
XElement node = new XElement(realName);
GetXmlFactory(propertyInfo.GetValue(model), node, element);
}
}
}
}