/// <returns>The root element of the tree</returns> public static ObjectElement RecreateObjectTree(SerializableNode[] nodes) { // Recreate all objects ObjectElement root = null; var elements = new Dictionary <int, ObjectElement>(); foreach (var obj in nodes) { ObjectElement element; switch (obj.Type) { case ObjectElement.Types.Root: element = ObjectElement.CreateRoot(); if (root != null) { throw new ApplicationException("There is more than 1 root element in the XML document."); } root = element; break; case ObjectElement.Types.Exception: { string str; if (obj.ValueTranslatable != null) { element = ObjectElement.CreateException(obj.ValueTranslatable.CreateTranslatableElement(), obj.Class, obj.StackTrace); } else if ((str = obj.ValuePrimitive.Value as string) != null) { element = ObjectElement.CreateException(str, obj.Class, obj.StackTrace); } else { System.Diagnostics.Debug.Fail("Unsupported element type '" + obj.ValuePrimitive.Value.GetType().FullName + "'"); continue; } break; } case ObjectElement.Types.Object: if (obj.NameTranslatable != null) { element = ObjectElement.CreateObject(obj.NameTranslatable.CreateTranslatableElement(), obj.Class); } else { element = ObjectElement.CreateObject(obj.NameString, obj.Class); } break; case ObjectElement.Types.Field: if (obj.NameTranslatable != null) { element = ObjectElement.CreateField(obj.NameTranslatable.CreateTranslatableElement(), obj.Class, obj.ValuePrimitive != null ? obj.ValuePrimitive.Value : obj.ValueTranslatable); } else { element = ObjectElement.CreateField(obj.NameString, obj.Class, obj.ValuePrimitive != null ? obj.ValuePrimitive.Value : obj.ValueTranslatable); } break; default: throw new NotImplementedException("The object type '" + obj.Type.ToString() + "' is not supported"); } elements.Add(obj.ID, element); } if (root == null) { throw new ApplicationException("There is no root element in the XML document."); } // Recreate parent/child links between objects foreach (var obj in nodes) { var parentElement = elements[obj.ID]; if (obj.Children != null) { foreach (var childObj in obj.Children) { parentElement.Children.Add(elements[childObj]); } } } return(root); }
private ObjectElement Explore(string fieldName, string fieldType, object currentObject, int currentDepth) { try { System.Diagnostics.Debug.Assert(fieldName != null); System.Diagnostics.Debug.Assert(fieldType != null); System.Diagnostics.Debug.Assert(currentDepth <= MaximumDepth); System.Diagnostics.Debug.Assert(VisitedObjects != null); if (currentObject == null) { return(ObjectElement.CreateField(fieldName, fieldType, NullValue)); } // Check that this object has not been visited yet ObjectElement visited; VisitedObjects.TryGetValue(currentObject, out visited); if (visited != null) { return(ObjectElement.CloneElement(fieldName, fieldType, visited)); } // Create the ObjectElement for this object and register it as visited ObjectElement currentElement; Type currentType = currentObject.GetType(); BaseException currentBaseException = null; Exception currentException = null; IDictionary currentDictionary = null; IEnumerable currentEnumerable = null; var fieldsToSkip = new Dictionary <string, object>(); string[] stackTrace = null; bool exploreChildren; if (IsDirectlyInterpretable(currentType)) { exploreChildren = false; currentElement = ObjectElement.CreateField(fieldName, currentType.FullName, currentObject); } else { exploreChildren = true; if ((currentBaseException = currentObject as BaseException) != null) { currentException = currentBaseException; if (currentBaseException.TranslatableMessage == null) { // Treat as regular exception currentBaseException = null; } fieldsToSkip.Add("InnerException", null); fieldsToSkip.Add("Message", null); fieldsToSkip.Add("TranslatableMessage", null); fieldsToSkip.Add("StackTrace", null); stackTrace = currentException.StackTrace.Split(new char[] { '\n' }); for (int i = 0; i < stackTrace.Length; ++i) { stackTrace[i] = stackTrace[i].Trim(); } } else if ((currentException = currentObject as Exception) != null) { fieldsToSkip.Add("InnerException", null); fieldsToSkip.Add("Message", null); fieldsToSkip.Add("StackTrace", null); stackTrace = currentException.StackTrace.Split(new char[] { '\n' }); for (int i = 0; i < stackTrace.Length; ++i) { stackTrace[i] = stackTrace[i].Trim(); } } if ((currentDictionary = currentObject as IDictionary) != null) { fieldsToSkip.Add("Keys", null); fieldsToSkip.Add("Values", null); fieldsToSkip.Add("Item", null); //exploreChildren = false; } else if ((currentEnumerable = currentObject as IEnumerable) != null) { //exploreChildren = false; } if (currentBaseException != null) { currentElement = ObjectElement.CreateException(currentBaseException.TranslatableMessage, currentBaseException.GetType().FullName, stackTrace); } else if (currentException != null) { currentElement = ObjectElement.CreateException(currentException.Message, currentException.GetType().FullName, stackTrace); } else { currentElement = ObjectElement.CreateObject(fieldName, currentObject.GetType().FullName); } } if (currentDepth >= MaximumDepth) { // Stop exploring exploreChildren = false; } VisitedObjects.Add(currentObject, currentElement); var childDepth = currentDepth + 1; if ((currentException == null) && (currentEnumerable == null) && (currentDictionary == null) && currentType.FullName.StartsWith("System.")) { // Don't explore childs of objects of type 'System.*' (except exceptions, enumerables and dictionaries) childDepth = MaximumDepth; } if (exploreChildren) { // Explore children foreach (var childMember in currentObject.GetType().GetMembers()) { if (fieldsToSkip.ContainsKey(childMember.Name)) { continue; } // Get the child type/value string childType; object childObject; switch (childMember.MemberType) { case MemberTypes.Field: { var field = (FieldInfo)childMember; childType = field.FieldType.FullName; childObject = field.GetValue(currentObject); break; } case MemberTypes.Property: { var property = (PropertyInfo)childMember; var propertyType = property.PropertyType; childType = propertyType.FullName; try { childObject = property.GetGetMethod().Invoke(currentObject, new object[] {}); } catch (System.Exception ex) { // Error calling the getter => Replace by an error string and continue string errorString = string.Format(GetterError, ex.GetType().FullName, ex.Message); var childElement2 = ObjectElement.CreateField(childMember.Name, childType, errorString); currentElement.Children.Add(childElement2); continue; } break; } default: // Nothing to explore continue; } // Recursive call var childElement = Explore(childMember.Name, childType, childObject, childDepth); currentElement.Children.Add(childElement); } if (currentDictionary != null) { // Add dictionary entries foreach (DictionaryEntry entry in currentDictionary) { string name; try { object key = entry.Key; if (key == null) { name = "<NULL>"; } else { name = key.ToString(); if (name.Length > MaxDictKeyLen) { name = name.Substring(0, MaxDictKeyLen); } name = "[" + name + "]"; } } catch (System.Exception ex) { // Error converting the Key to string => Replace by an error string and continue name = string.Format(GetterError, ex.GetType().FullName, ex.Message); } // Recursive call var childElement = Explore(name, typeof(object).ToString(), entry.Value, childDepth); currentElement.Children.Add(childElement); } } else if (currentEnumerable != null) { // Add enumerable entries int i = 0; foreach (object entry in currentEnumerable) { // Recursive call string name = string.Format("[{0}]", i++); var childElement = Explore(name, typeof(object).ToString(), entry, childDepth); currentElement.Children.Add(childElement); } } } return(currentElement); } catch (System.Exception ex) { // Error exploring => Replace by an error field System.Diagnostics.Debug.Fail("Explore error"); var element = ObjectElement.CreateField(fieldName, fieldType, string.Format(ExploreError, ex.GetType(), ex.Message)); return(element); } }