.Net中的XmlSerializer非常好用,但是有时候也不能完全满足要求。比如XmlSerializer完全按照对象内容展开,而不管引用关系,造成在反序列化后对象结构和原始的会不一致,如果循环引用还会出现死循环;需要显式制定对象中所有的自定义类型,不够方便;不支持范型,不能用接口作为变量类型等等。
自己写了一段程序,某些时候用起来比较方便,也为了熟悉一下Xml操作。很久以前写的了,现在看一下还是有一些不足之处,以后有需要再修改吧。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml;
- using System.IO;
- using System.Reflection;
- using System.Runtime.Serialization;
- using System.Collections;
- namespace System
- {
- public static class XMLConvert
- {
- private const string tag_reference = "ref ";
- private const string tag_type = "type ";
- private const string tag_param = "params ";
- private const char char_left = '( ';
- private const char char_right = ') ';
- private static Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
- public static string ToXML(object o)
- {
- return ToXML( "class ", o);
- }
- public static string ToXML(string name, object o)
- {
- StringBuilder stringBuilder = new StringBuilder();
- XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(stringBuilder));
- xmlWriter.Formatting = Formatting.Indented;
- xmlWriter.WriteStartDocument();
- ToXML(name, o, xmlWriter, new Hashtable());
- xmlWriter.WriteEndDocument();
- return stringBuilder.ToString();
- }
- public static object ToObject(string strXML)
- {
- XmlDocument xml = new XmlDocument();
- xml.LoadXml(strXML);
- return ToObject(xml);
- }
- public static object ToObject(XmlDocument xml)
- {
- Hashtable refMap = new Hashtable(xml.ChildNodes.Count * 4);
- object value = ToObject(xml.LastChild, refMap);
- return value;
- }
- private static void ToXML(string name, object value, XmlWriter xmlWriter, Hashtable refMap)
- {
- xmlWriter.WriteStartElement(name);
- if (value != null)
- {
- if (refMap.ContainsKey(new Ref(value)))
- {
- xmlWriter.WriteAttributeString(tag_reference, refMap[new Ref(value)].ToString());
- }
- else
- {
- Type type = value.GetType();
- TypeToXML(type, xmlWriter);
- if (!type.IsValueType)
- {
- xmlWriter.WriteAttributeString(tag_reference, refMap.Count.ToString());
- refMap.Add(new Ref(value), refMap.Count);
- }
- if (type.IsPrimitive || type.Equals(typeof(string)))
- {
- xmlWriter.WriteString(Convert.ToString(value));
- }
- else if (type.IsArray)
- {
- foreach (object subvalue in (value as Array))
- {
- ToXML( "element ", subvalue, xmlWriter, refMap);
- }
- }
- else
- {
- ToXML(type, value, xmlWriter, refMap);
- }
- }
- }
- xmlWriter.WriteEndElement();
- }
- private static void ToXML(Type type, object value, XmlWriter xmlWriter, Hashtable refMap)
- {
- if (type == null || type.Equals(typeof(object))) return;
- FieldInfo[] fields = type.GetFields(BindingFlags.GetField | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- foreach (FieldInfo field in fields)
- {
- ToXML(field.Name, field.GetValue(value), xmlWriter, refMap);
- }
- ToXML(type.BaseType, value, xmlWriter, refMap);
- }
- private static void TypeToXML(Type type, XmlWriter xmlWriter)
- {
- if (type.IsGenericType)
- {
- Type genericType = type.GetGenericTypeDefinition();
- xmlWriter.WriteAttributeString(tag_type, genericType.FullName);
- Type[] genericArguments = type.GetGenericArguments();
- xmlWriter.WriteAttributeString(tag_param, ToParamsName(genericArguments));
- }
- else
- {
- xmlWriter.WriteAttributeString(tag_type, type.FullName);
- }
- }
- private static string ToParamsName(Type[] genericArguments)
- {
- string[] names = new string[genericArguments.Length];
- for (int i = 0; i < genericArguments.Length; i++)
- {
- if (genericArguments[i].IsGenericType)
- names[i] = genericArguments[i].GetGenericTypeDefinition().FullName + char_left + ToParamsName(genericArguments[i].GetGenericArguments()) + char_right;
- else
- names[i] = genericArguments[i].FullName;
- }
- return String.Join( ", ", names);
- }
- private static object ToObject(XmlNode node, Hashtable refMap)
- {
- if (node == null || node.Attributes.Count == 0) return null;
- if (node.Attributes[tag_reference] != null && refMap[Int32.Parse(node.Attributes[tag_reference].Value)] != null) return refMap[Int32.Parse(node.Attributes[tag_reference].Value)];
- Type type = GetType(node.Attributes[tag_type].Value);
- if (type.IsGenericTypeDefinition)
- {
- string paramName = node.Attributes[tag_param].Value;
- type = GetGenericType(type, paramName);
- }
- object value = null;
- if (type.Equals(typeof(IntPtr)))
- {
- value = (IntPtr)Convert.ToInt32(node.InnerText);
- }
- else if (type.IsPrimitive || type.Equals(typeof(string)))
- {
- value = Convert.ChangeType(node.InnerText, type);
- }
- else if (type.IsArray)
- {
- value = Array.CreateInstance(type.GetElementType(), node.ChildNodes.Count);
- }
- else
- {
- value = FormatterServices.GetUninitializedObject(type);
- }
- if (node.Attributes[tag_reference] != null) refMap[Int32.Parse(node.Attributes[tag_reference].Value)] = value;
- if (type.Equals(typeof(IntPtr))) { }
- else if (type.IsPrimitive || type.Equals(typeof(string))) { }
- else if (type.IsArray)
- {
- for (int i = 0; i < node.ChildNodes.Count; i++)
- {
- (value as Array).SetValue(ToObject(node.ChildNodes[i], refMap), i);
- }
- }
- else
- {
- foreach (XmlNode xmlnode in node.ChildNodes)
- {
- FieldInfo field = GetField(type, xmlnode.Name);
- field.SetValue(value, ToObject(xmlnode, refMap));
- }
- }
- return value;
- }
- private static Type GetType(string name)
- {
- int index1 = name.IndexOf(char_left);
- int index2 = name.LastIndexOf(char_right);
- if (index1 < 0)
- {
- Type type = Type.GetType(name);
- if (type == null)
- {
- foreach (Assembly assembly in assemblies)
- {
- type = assembly.GetType(name);
- if (type != null) break;
- }
- }
- return type;
- }
- else
- {
- return GetGenericType(GetType(name.Substring(0, index1)), name.Substring(index1 + 1, index2 - index1 - 1));
- }
- }
- private static FieldInfo GetField(Type type, string name)
- {
- FieldInfo field = null;
- while (field == null && type != null)
- {
- field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- type = type.BaseType;
- }
- return field;
- }
- private static Type GetGenericType(Type type, string param)
- {
- string[] paramNames = Split(param, ', ', char_left, char_right);
- Type[] paramTypes = new Type[paramNames.Length];
- for (int i = 0; i < paramNames.Length; i++)
- {
- paramTypes[i] = GetType(paramNames[i]);
- }
- return type.MakeGenericType(paramTypes);
- }
- private static string[] Split(string str, char separator, char left, char right)
- {
- List <string> results = new List <string> (str.Length / 10);
- int start = 0;
- for (int i = 0, stack = 0; i < str.Length; i++)
- {
- if (str[i] == separator && stack == 0)
- {
- results.Add(str.Substring(start, i - start));
- start = i + 1;
- }
- if (str[i] == left) stack++;
- if (str[i] == right) stack--;
- }
- if (start < str.Length) results.Add(str.Substring(start));
- return results.ToArray();
- }
- class Ref
- {
- private object value = null;
- public Ref(object o)
- {
- value = o;
- }
- public override bool Equals(object obj)
- {
- if (obj is Ref && ReferenceEquals(value, (obj as Ref).value)) return true;
- else return false;
- }
- public override int GetHashCode()
- {
- if (value != null) return value.GetHashCode();
- else return 0;
- }
- }
- }
- }