// Created by Mark Cordell // Last modified 2008-11-22 // Lacks support for base64 and some other stuff. //////////////////////////// using System; //using System.IO; //using System.Reflection; //using System.Xml; //using System.Xml.Serialization; public class Util { /// Serialize public static string ObjToXmlStr(T obj) { if (obj == null) return null; System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(T)); System.IO.StringWriter stringWriter = new System.IO.StringWriter(); ser.Serialize(stringWriter, obj); stringWriter.Flush(); return stringWriter.ToString(); } /// Deserialize public static T XmlStrToObj(string xml) { if (string.IsNullOrEmpty(xml)) return default(T); System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(T)); System.IO.StringReader stringReader = new System.IO.StringReader(xml); System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(stringReader); object obj = ser.Deserialize(xmlReader); return (T)obj; } /// Deserialize without strict namespaces public static T XmlStrToObjBestWeCan(string xml) { if (string.IsNullOrEmpty(xml)) return default(T); System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); doc.LoadXml(xml); object obj = Util.XmlNodeToObj(doc.DocumentElement, typeof(T), null); if (null == obj && (typeof(T).IsEnum || typeof(T).IsPrimitive)) { return default(T); } else { return (T)obj; } } #region Helper Methods public static object XmlNodeToObj(System.Xml.XmlNode node, Type objType, System.Reflection.MemberInfo member) { System.Xml.XmlAttribute nilAttr = node.Attributes["nil", "http://www.w3.org/2001/XMLSchema-instance"]; if (null == nilAttr) nilAttr = node.Attributes["nil"]; if (nilAttr != null && nilAttr.InnerText == "true") return null; if (objType == typeof(string)) { return node.InnerText; } else if (objType.IsEnum) { return Util.EnumParseSafe(objType, node.InnerText); } else if (objType == typeof(DateTime)) { return Convert.ToDateTime(node.InnerText); } else if (objType == typeof(Decimal)) { return Convert.ToDecimal(node.InnerText); } else if (objType.IsPrimitive) { if (!string.IsNullOrEmpty(node.InnerText)) { try { return Convert.ChangeType(node.InnerText, objType); } catch { return null; } } else { return null; } } else { Type listType = objType.GetInterface("IList"); if (listType != null) { return Util.XmlNodeToArray(node, objType, member); // recurse } else { return Util.XmlNodeToClass(node, objType, member); // recurse } } } /// Not used now but may be needed in the future. public static object XmlNodeToClass(System.Xml.XmlNode node, Type objType, System.Reflection.MemberInfo member) { // Works for structs too. object obj = null; if (objType.GetConstructor(Type.EmptyTypes) != null) { obj = objType.GetConstructor(Type.EmptyTypes).Invoke(null); // Default constructor. } else { return null; } foreach (System.Reflection.FieldInfo field in objType.GetFields()) { // Public member variables. Type memberType = field.FieldType; System.Xml.XmlNode child = Util.GetXmlChildForMember(node, field, ref memberType); if (child != null) { object val = Util.XmlNodeToObj(child, memberType, field); // recurse if (memberType.IsEnum || memberType.IsPrimitive) { if (val != null) { field.SetValue(obj, val); Util.SetSpecifiedFlag(obj, field.Name); } } else { field.SetValue(obj, val); } } } foreach (System.Reflection.PropertyInfo prop in objType.GetProperties()) { // Public properties. Type memberType = prop.PropertyType; System.Xml.XmlNode child = Util.GetXmlChildForMember(node, prop, ref memberType); if (child != null) { object val = Util.XmlNodeToObj(child, memberType, prop); // recurse if (memberType.IsEnum || memberType.IsPrimitive) { if (val != null) { prop.SetValue(obj, val, null); Util.SetSpecifiedFlag(obj, prop.Name); } } else { prop.SetValue(obj, val, null); } } } return obj; } public static object XmlNodeToArray(System.Xml.XmlNode node, Type objType, System.Reflection.MemberInfo member) { object obj = null; if (objType.GetConstructor(Type.EmptyTypes) != null) { obj = objType.GetConstructor(Type.EmptyTypes).Invoke(null); // Default constructor. } Type listElemType = objType.GetElementType(); if (null == listElemType) listElemType = typeof(object); System.Collections.IList listObj = obj as System.Collections.IList; if (null == listObj) { listObj = new System.Collections.ArrayList(); } System.Xml.Serialization.XmlElementAttribute elemAttr = null; if (member != null) { foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlElementAttribute), false)) { elemAttr = (System.Xml.Serialization.XmlElementAttribute)attribute; if (string.IsNullOrEmpty(elemAttr.ElementName)) { elemAttr.ElementName = member.Name; } break; } } foreach (System.Xml.XmlNode chnode in node.ChildNodes) { System.Xml.XmlElement child = chnode as System.Xml.XmlElement; if (child != null && (null == elemAttr || elemAttr.ElementName == child.LocalName && (string.IsNullOrEmpty(child.NamespaceURI) || string.IsNullOrEmpty(elemAttr.Namespace) || child.NamespaceURI == elemAttr.Namespace))) { Type childType = null; // Is there an [XmlArrayItem] with matching name and namespace? if (member != null) { foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlArrayItemAttribute), false)) { System.Xml.Serialization.XmlArrayItemAttribute itemAttr = (System.Xml.Serialization.XmlArrayItemAttribute)attribute; if (itemAttr.ElementName == child.LocalName && (string.IsNullOrEmpty(itemAttr.Namespace) || string.IsNullOrEmpty(child.NamespaceURI) || itemAttr.Namespace == child.NamespaceURI)) { childType = itemAttr.Type; break; } } // Is there an [XmlArrayItem] with matching name ignoring namespace? if (null == childType) { foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlArrayItemAttribute), false)) { System.Xml.Serialization.XmlArrayItemAttribute itemAttr = (System.Xml.Serialization.XmlArrayItemAttribute)attribute; if (itemAttr.ElementName == child.LocalName) { childType = itemAttr.Type; break; } } } } if (null == childType) { string xsiType = child.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance"); if (string.IsNullOrEmpty(xsiType)) { xsiType = child.GetAttribute("type"); } if (!string.IsNullOrEmpty(xsiType)) { childType = Util.GetTypeFromXsdTypeName(xsiType); } } if (null == childType) { childType = Util.GetTypeFromXsdTypeName(child.LocalName); } if (null == childType) { childType = listElemType; } object listItem = Util.XmlNodeToObj(child, childType, null); listObj.Add(listItem); } } if (objType.IsArray && listObj is System.Collections.ArrayList) { Array arr = Array.CreateInstance(listElemType, listObj.Count); for (int i = 0; i < listObj.Count; i++) { if (!listElemType.IsValueType || listObj[i] != null) { if (null == listObj[i] || listElemType.IsAssignableFrom(listObj[i].GetType())) { arr.SetValue(listObj[i], i); } } } listObj = arr; } return listObj; } public static System.Xml.XmlNode GetXmlChildForMember(System.Xml.XmlNode node, System.Reflection.MemberInfo member, ref Type memberType) { string xmlName; string xmlNamespace; System.Xml.XmlNode child = null; if (memberType.GetInterface("IList") != null) { // Is there an [XmlElement]? foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlElementAttribute), false)) { memberType = ((System.Xml.Serialization.XmlElementAttribute)attribute).Type ?? memberType; return node; // treat parent as child in this case. } } // Is there an [XmlAttribute]? foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlAttributeAttribute), false)) { xmlName = ((System.Xml.Serialization.XmlAttributeAttribute)attribute).AttributeName; xmlNamespace = ((System.Xml.Serialization.XmlAttributeAttribute)attribute).Namespace; child = Util.GetFirstAttributeByName(node, xmlName, xmlNamespace); if (child != null) { memberType = ((System.Xml.Serialization.XmlAttributeAttribute)attribute).Type ?? memberType; return child; } } // Is there an [XmlElement]? foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlElementAttribute), false)) { xmlName = ((System.Xml.Serialization.XmlElementAttribute)attribute).ElementName; xmlNamespace = ((System.Xml.Serialization.XmlElementAttribute)attribute).Namespace; child = Util.GetFirstChildElemByTagName(node, xmlName, xmlNamespace); if (child != null) { memberType = ((System.Xml.Serialization.XmlElementAttribute)attribute).Type ?? memberType; return child; } } // Is there an [XmlArray]? foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlArrayAttribute), false)) { xmlName = ((System.Xml.Serialization.XmlArrayAttribute)attribute).ElementName; xmlNamespace = ((System.Xml.Serialization.XmlArrayAttribute)attribute).Namespace; child = Util.GetFirstChildElemByTagName(node, xmlName, xmlNamespace); if (child != null) return child; } // Try [XmlAttribute] again ignoring namespace. foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlAttributeAttribute), false)) { xmlName = ((System.Xml.Serialization.XmlAttributeAttribute)attribute).AttributeName; child = Util.GetFirstAttributeByName(node, xmlName, null); if (null == child) child = Util.GetFirstChildElemByTagName(node, xmlName, null); if (child != null) { memberType = ((System.Xml.Serialization.XmlAttributeAttribute)attribute).Type ?? memberType; return child; } } // Try [XmlElement] again ignoring namespace. foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlElementAttribute), false)) { xmlName = ((System.Xml.Serialization.XmlElementAttribute)attribute).ElementName; child = Util.GetFirstChildElemByTagName(node, xmlName, null); if (null == child) child = Util.GetFirstAttributeByName(node, xmlName, null); if (child != null) { memberType = ((System.Xml.Serialization.XmlElementAttribute)attribute).Type ?? memberType; return child; } } // Try [XmlArray] again ignoring namespace? foreach (object attribute in member.GetCustomAttributes(typeof(System.Xml.Serialization.XmlArrayAttribute), false)) { xmlName = ((System.Xml.Serialization.XmlArrayAttribute)attribute).ElementName; child = Util.GetFirstChildElemByTagName(node, xmlName, null); if (child != null) return child; } // Try by member name ignoring namespace. child = Util.GetFirstChildElemByTagName(node, member.Name, null); if (child != null) return child; child = Util.GetFirstAttributeByName(node, member.Name, null); return child; } public static System.Xml.XmlNode GetFirstChildElemByTagName(System.Xml.XmlNode parent, string name, string namespaceUri) { if (parent.ChildNodes != null) { foreach (System.Xml.XmlNode child in parent.ChildNodes) { if (child.LocalName == name) { if (string.IsNullOrEmpty(namespaceUri)) { return child; } else if (child.NamespaceURI == namespaceUri) { return child; } } } } return null; } public static System.Xml.XmlAttribute GetFirstAttributeByName(System.Xml.XmlNode parent, string name, string namespaceUri) { if (parent.Attributes != null) { foreach (System.Xml.XmlAttribute attr in parent.Attributes) { if (attr.LocalName == name) { if (string.IsNullOrEmpty(namespaceUri)) { return attr; } else if (attr.NamespaceURI == namespaceUri) { return attr; } } } } return null; } public static void SetSpecifiedFlag(object obj, string fieldName) { System.Reflection.FieldInfo field = obj.GetType().GetField(fieldName + "Specified"); if (field != null && field.FieldType == typeof(bool)) { field.SetValue(obj, true); return; } System.Reflection.PropertyInfo prop = obj.GetType().GetProperty(fieldName + "Specified"); if (prop != null && prop.PropertyType == typeof(bool)) { prop.SetValue(obj, true, null); } } public static Type GetTypeFromXsdTypeName(string xsdTypeName) { // http://msdn.microsoft.com/en-us/library/aa719879(VS.71).aspx // http://msdn.microsoft.com/en-us/library/ms256220.aspx if (string.IsNullOrEmpty(xsdTypeName)) return null; int colon = xsdTypeName.IndexOf(':'); if (colon >= 0) xsdTypeName = xsdTypeName.Substring(colon + 1); xsdTypeName = xsdTypeName.Trim(); switch (xsdTypeName) { case "Boolean": return typeof(System.Boolean); case "Byte": return typeof(System.SByte); case "Date": return typeof(System.DateTime); case "dateTime": return typeof(System.DateTime); case "decimal": return typeof(System.Decimal); case "Double": return typeof(System.Double); case "duration": return typeof(System.TimeSpan); case "Float": return typeof(System.Single); case "gDay": return typeof(System.DateTime); case "gMonthDay": return typeof(System.DateTime); case "gYear": return typeof(System.DateTime); case "gYearMonth": return typeof(System.DateTime); case "int": return typeof(System.Int32); case "integer": return typeof(System.Decimal); case "long": return typeof(System.Int64); case "short": return typeof(System.Int16); case "string": return typeof(System.String); case "time": return typeof(System.DateTime); case "unsignedByte": return typeof(System.Byte); case "unsignedInt": return typeof(System.UInt32); case "unsignedLong": return typeof(System.UInt64); case "unsignedShort": return typeof(System.UInt16); } Type t = Type.GetType(xsdTypeName, false, false); if (null == t) t = Type.GetType(xsdTypeName, false, true); if (null == t) { foreach (System.Reflection.Module mod in System.Reflection.Assembly.GetExecutingAssembly().GetModules(false)) { Type[] modtypes = mod.FindTypes(System.Reflection.Module.FilterTypeName, xsdTypeName); if (modtypes != null && modtypes.Length > 0) return modtypes[0]; } foreach (System.Reflection.Module mod in System.Reflection.Assembly.GetExecutingAssembly().GetModules(false)) { Type[] modtypes = mod.FindTypes(System.Reflection.Module.FilterTypeNameIgnoreCase, xsdTypeName); if (modtypes != null && modtypes.Length > 0) return modtypes[0]; } } return t; } public static object EnumParseSafe(Type t, string s) { try { return Enum.Parse(t, s, false); } catch { try { return Enum.Parse(t, s, true); } catch { return null; } } } #endregion }