Skip to content

Instantly share code, notes, and snippets.

@derekantrican
Last active October 24, 2019 15:52
Show Gist options
  • Save derekantrican/a8bcd0b50c11bcb78f32f28839f16e9e to your computer and use it in GitHub Desktop.
Save derekantrican/a8bcd0b50c11bcb78f32f28839f16e9e to your computer and use it in GitHub Desktop.
An example about how to salvage an XML file when it is improperly formatted
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace SalvageXML
{
public static class SalvageXML
{
private static string settingsPath = Path.Combine(Common.UserSettings, "Settings.xml");
public static Settings SalvageSettings(string xmlPath)
{
Logger.Log("Attempting to upgrade settings", "SettingsUpgrader", updateLogLocations: false);
string xml = File.ReadAllText(xmlPath);
xml = xml.Replace(Environment.NewLine, "");
Settings result = Settings.GetDefaultValues();
foreach (PropertyInfo prop in typeof(Settings).GetProperties())
{
string match = Regex.Match(xml, $"<{prop.Name}>(.+)</{prop.Name}>").Groups[1].Value;
if (!string.IsNullOrEmpty(match))
{
try
{
SetPropValue(match, prop, result);
Logger.Log($"Upgraded {prop.Name}", "SettingsUpgrader", updateLogLocations: false);
}
catch (Exception ex)
{
Logger.LogError($"Could not parse setting from {match} ({{0}})", ex, updateLogLocations: false);
}
}
}
return result;
}
private static void SetPropValue(string value, PropertyInfo targetProp, dynamic targetClass)
{
if (targetProp.GetValue(targetClass) is IList && targetProp.PropertyType.IsGenericType)
{
IList list = targetProp.GetValue(targetClass) as IList;
list.Clear();
Type listType = GetListType(targetProp);
foreach (Match match in Regex.Matches(value, "<.*?>(.*?)</.*?>", RegexOptions.IgnoreCase))
{
string itemString = match.Groups[1].Value;
list.Add(Convert.ChangeType(itemString, listType));
}
targetProp.SetValue(targetClass, list);
}
else if (targetProp.PropertyType.IsEnum)
{
//Convert enums that have changed values
if (targetProp.PropertyType == typeof(Enums.ReminderType) &&
value == "Notification")
value = "Popup";
else if (targetProp.PropertyType == typeof(Enums.CalendarVisibility) &&
value == "CalendarDefault")
value = "Default";
else if (targetProp.PropertyType == typeof(Enums.ChangeDurationMethod) &&
value == "Specific")
value = "SpecificAmount";
targetProp.SetValue(targetClass, Enum.Parse(targetProp.PropertyType, value));
}
else if (targetProp.PropertyType == typeof(ModalSearch))
{
ModalSearch searchResult = ModalSearch.Instance;
foreach (PropertyInfo searchProp in typeof(ModalSearch).GetProperties())
{
string searchMatch = Regex.Match(value, $"<{searchProp.Name}>(.+)</{searchProp.Name}>", RegexOptions.IgnoreCase).Groups[1].Value;
if (!string.IsNullOrEmpty(searchMatch))
SetPropValue(searchMatch, searchProp, searchResult);
}
targetProp.SetValue(targetClass, searchResult);
}
else if (targetProp.PropertyType == typeof(ModalFilter))
{
ModalFilter filterResult = ModalFilter.Instance;
foreach (PropertyInfo filterProp in typeof(ModalFilter).GetProperties())
{
string filterMatch = Regex.Match(value, $"<{filterProp.Name}>(.+)</{filterProp.Name}>", RegexOptions.IgnoreCase).Groups[1].Value;
if (!string.IsNullOrEmpty(filterMatch))
SetPropValue(filterMatch, filterProp, filterResult);
}
targetProp.SetValue(targetClass, filterResult);
}
else if (targetProp.PropertyType == typeof(ModalEditor))
{
ModalEditor editorResult = ModalEditor.Instance;
foreach (PropertyInfo editorProp in typeof(ModalEditor).GetProperties())
{
string editorMatch = Regex.Match(value, $"<{editorProp.Name}>(.+)</{editorProp.Name}>", RegexOptions.IgnoreCase).Groups[1].Value;
if (!string.IsNullOrEmpty(editorMatch))
SetPropValue(editorMatch, editorProp, editorResult);
}
targetProp.SetValue(targetClass, editorResult);
}
else
targetProp.SetValue(targetClass, Convert.ChangeType(value, targetProp.PropertyType));
}
private static Type GetListType(PropertyInfo listProp)
{
//Credit: https://stackoverflow.com/a/13608408/2246411
Func<Type, Type> interfaceTest = new Func<Type, Type>(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>) ? i.GetGenericArguments().Single() : null);
Type innerType = interfaceTest(listProp.PropertyType);
if (innerType != null)
return innerType;
foreach (Type i in listProp.PropertyType.GetInterfaces())
{
innerType = interfaceTest(i);
if (innerType != null)
return innerType;
}
return default(Type);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment