/* * Converts an object to an XML element string. */ public static string ConvertToElement(string name, object objectToConvert, XMLVersion version) { // Return a serialized XML element if it is an XML element. if (objectToConvert is VersionedXMLElement) { return(((VersionedXMLElement)objectToConvert).Serialize(version, name)); } // Return the object as a string. return("<" + name + ">" + ConvertToString(objectToConvert, version) + "</" + name + ">"); }
/* * Converts a string to an object. */ public static object DeserializeToObject(string value, Type propertyType, XMLVersion version) { // Get the underlying type if it is nullable. if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable <>)) { propertyType = propertyType.GetGenericArguments()[0]; } // Return an enum if a name matches. if (propertyType.IsEnum) { // Return if an attribute matches. foreach (var enumItem in Enum.GetValues(propertyType)) { foreach (XMLEnum attribute in propertyType.GetField(enumItem.ToString()).GetCustomAttributes(typeof(XMLEnum), false)) { if (attribute.IsVersionValid(version) && attribute.Name == value) { return(enumItem); } } } // Return if a name matches. foreach (var enumItem in Enum.GetValues(propertyType)) { if (enumItem.ToString() == value && propertyType.GetField(enumItem.ToString()).GetCustomAttributes(typeof(XMLEnum), false).Length == 0) { return(enumItem); } } // Throw an exception. throw new InvalidVersionException(propertyType.Name + "." + value, version); } // Return a converted string. var typeConverter = TypeDescriptor.GetConverter(propertyType); return(typeConverter.ConvertFromString(value)); }
/* * Serializes the element. */ public string Serialize(XMLVersion version) { // Get the name. string name = null; bool attributeDefined = false; var selfType = this.GetType(); foreach (XMLElement attribute in selfType.GetCustomAttributes(typeof(XMLElement), true)) { attributeDefined = true; if (attribute.IsVersionValid(version)) { if (name == null) { // Set the name if it is null. name = attribute.Name; } else { // Throw an exception if overlapping names exist (could cause unexpected behavior). throw new OverlappingVersionsException(selfType.Name, version); } } } // Throw an exception if an attribute is defined but the name isn't. This happens // when the serializing version is invalid. if (name == null && attributeDefined) { throw new InvalidVersionException(selfType.Name, version); } // Set the name to the object name if no attribute is present. if (name == null) { name = selfType.Name; } // Serialize the object. return(this.Serialize(version, name)); }
/* * Returns if a version is valid. */ public bool IsVersionValid(XMLVersion otherVersion) { // Create the versions to compare. If they are null, the versions will be null. var firstVersion = XMLVersion.FromString(this.FirstVersion); var removedVersion = XMLVersion.FromString(this.RemovedVersion); // Return if the version is valid. if (firstVersion != null && removedVersion != null) { return(firstVersion <= otherVersion && removedVersion > otherVersion); } else if (firstVersion != null) { return(firstVersion <= otherVersion); } else if (removedVersion != null) { return(removedVersion > otherVersion); } // Return true (first and removed versions not defined). return(true); }
/* * Converts an XML element to an object. */ public static object DeserializeToObject(XElement xmlElement, Type propertyType, XMLVersion version) { // Return a parsed XML element. if (IsOfType(propertyType, typeof(VersionedXMLElement))) { if (xmlElement.Value != "" || xmlElement.FirstAttribute != null) { return(DeserializeType(xmlElement.ToString(), version, propertyType)); } else { return(null); } } // Return a converted string. return(DeserializeToObject(xmlElement.Value, propertyType, version)); }
/* * Deserializes a string to an XML element. */ public static T Deserialize <T>(string xmlString, XMLVersion version) { return((T)DeserializeType(xmlString, version, typeof(T))); }
/* * Deserializes an object. */ public static object DeserializeType(string xmlString, XMLVersion version, Type type) { xmlString = xmlString.Trim(); // Create the new object. var newObject = Convert.ChangeType(Activator.CreateInstance(type, new object[] { }), type); var selfType = newObject.GetType(); var members = selfType.GetMembers(); // Create an XML parser and get the attributes and elements. var xmlDocument = XDocument.Parse(xmlString); var elements = xmlDocument.Root.Elements().ToArray(); var attributes = xmlDocument.Root.Attributes().ToArray(); // Set the attributes. foreach (var xmlAttribute in attributes) { // Find the attribute to add to. MemberInfo memberToSet = null; foreach (var member in members) { foreach (XMLAttribute attribute in member.GetCustomAttributes(typeof(XMLAttribute), true)) { var property = selfType.GetProperty(member.Name); if (property != null) { if (attribute.IsVersionValid(version) && attribute.Name.ToLower() == xmlAttribute.Name.LocalName.ToLower()) { if (memberToSet != null) { // Throw an exception if the attribute overlaps. throw new OverlappingVersionsException(member.Name, version); } else { memberToSet = member; } } } else { // Throw an exception if the property is null ("{ get; set; }" is missing). throw new MissingGetterException(member.Name); } } } // If the attribute exists, set the value. if (memberToSet != null) { var property = selfType.GetProperty(memberToSet.Name); var deserializedObject = DeserializeToObject(xmlAttribute.Value, property.PropertyType, version); property.SetValue(newObject, deserializedObject); } } // Set the elements. var unknownElements = new List <string>(); foreach (var xmlElement in elements) { // Find the attribute to add to. MemberInfo memberToSet = null; foreach (var member in members) { foreach (XMLElement attribute in member.GetCustomAttributes(typeof(XMLElement), true)) { var property = selfType.GetProperty(member.Name); if (property != null) { if (attribute.IsVersionValid(version) && attribute.Name.ToLower() == xmlElement.Name.LocalName.ToLower()) { if (memberToSet != null) { // Throw an exception if the attribute overlaps. throw new OverlappingVersionsException(member.Name, version); } else { memberToSet = member; } } } else { // Throw an exception if the property is null ("{ get; set; }" is missing). throw new MissingGetterException(member.Name); } } } // If the attribute exists, set the value. if (memberToSet != null) { // Set the value. var property = selfType.GetProperty(memberToSet.Name); var propertyType = property.PropertyType; if (IsOfType(propertyType, typeof(IList))) { var deserializedObject = DeserializeToObject(xmlElement, propertyType.GetGenericArguments()[0], version); ((IList)property.GetValue(newObject)).Add(deserializedObject); } else { var deserializedObject = DeserializeToObject(xmlElement, propertyType, version); property.SetValue(newObject, deserializedObject); } } else { unknownElements.Add(xmlElement.ToString()); } } // Parse unknown elements. var method = type.GetMethod("ParseAdditionalElements"); if (method != null) { method.Invoke(newObject, new object[2] { version, unknownElements }); } // Return the new object. return(newObject); }
public InvalidVersionException(string name, XMLVersion version) : base(name + " can't be used for version " + version.MainVersion + "." + version.SubVersion + ".") { }
public OverlappingVersionsException(string name, XMLVersion version) : base(name + " has overlapping version information for version " + version.MainVersion + "." + version.SubVersion + ". This makes the serialization ambiguous.") { }
/* * Parses elements that aren't defined by properties. */ public virtual void ParseAdditionalElements(XMLVersion version, List <string> elements) { }
/* * Returns additional elements to add when serializing. * This method must handle all escaping of special characters. */ public virtual List <string> GetAdditionalElements(XMLVersion version) { return(this.additionalElements); }
/* * Invoked before serializing the object to finalize * setting of elements. */ public virtual void PreSerialize(XMLVersion version) { }
/* * Converts an object to a string. */ public static string ConvertToString(object objectToConvert, XMLVersion version) { // Return an XML string if it is an XML object. if (objectToConvert is VersionedXMLElement) { return(((VersionedXMLElement)objectToConvert).Serialize(version)); } // Return an XSD time if it is a DateTime. if (objectToConvert is DateTime) { // Get the components. var dateTime = (DateTime)objectToConvert; var year = dateTime.Year.ToString(); var month = dateTime.Month.ToString(); var day = dateTime.Day.ToString(); // Add the leading zeros. if (dateTime.Month < 10) { month = "0" + month; } if (dateTime.Day < 10) { day = "0" + day; } // Return the formatted time. return(year + "-" + month + "-" + day); } // Return a boolean as lowercase if it is a bool. if (objectToConvert is bool) { return(objectToConvert.ToString().ToLower()); } // Return an enum value if it is an enum. if (objectToConvert.GetType().IsEnum) { // Get the name of the enum. var enumType = objectToConvert.GetType(); var enumName = Enum.GetName(enumType, objectToConvert); var attributeDefined = false; var nameDefined = false; foreach (XMLEnum attribute in enumType.GetField(enumName).GetCustomAttributes(typeof(XMLEnum), false)) { attributeDefined = true; if (attribute.IsVersionValid(version)) { if (nameDefined == false) { // Set the name if it is null. nameDefined = true; enumName = attribute.Name; } else { // Throw an exception if overlapping names exist (could cause unexpected behavior). throw new OverlappingVersionsException(enumType.Name + "." + Enum.GetName(enumType, objectToConvert), version); } } } // Throw an exception if the attribute is defined but not set. if (attributeDefined && !nameDefined) { throw new InvalidVersionException(objectToConvert.GetType().Name + "." + enumName, version); } // Return the escaped enum value. return(SecurityElement.Escape(enumName)); } // Return the ToString result. return(SecurityElement.Escape(objectToConvert.ToString())); }
/* * Serializes the element with a give name. */ public string Serialize(XMLVersion version, string elementName) { var selfType = this.GetType(); var members = selfType.GetMembers(); var xmlString = "<" + elementName; // Pre-serialize the object. this.PreSerialize(version); // Add the attributes. foreach (var member in members) { bool attributeAdded = false; foreach (XMLAttribute attribute in member.GetCustomAttributes(typeof(XMLAttribute), true)) { var property = selfType.GetProperty(member.Name); if (property != null) { if (attribute.IsVersionValid(version)) { if (attributeAdded) { // Throw an exception if the attribute overlaps. throw new OverlappingVersionsException(member.Name, version); } else { // Add the attribute if it isn't null. attributeAdded = true; var value = property.GetValue(this, null); if (value != null) { // Add the attribute. xmlString += " " + attribute.Name + "=\"" + ConvertToString(value, version) + "\""; } } } } else { // Throw an exception if the property is null ("{ get; set; }" is missing). throw new MissingGetterException(member.Name); } } } // Add the additional attributes. foreach (var attributeName in this.additionalAttributes.Keys) { xmlString += " " + attributeName + "=\"" + this.additionalAttributes[attributeName] + "\""; } xmlString += ">"; // Add the child elements. foreach (var member in members) { bool elementAdded = false; foreach (XMLElement attribute in member.GetCustomAttributes(typeof(XMLElement), true)) { var property = selfType.GetProperty(member.Name); if (property != null) { var value = property.GetValue(this, null); if (value != null) { if (attribute.IsVersionValid(version)) { if (elementAdded) { // Throw an exception if the element overlaps. throw new OverlappingVersionsException(member.Name, version); } else { // Add the child element. elementAdded = true; if (value is IList) { foreach (var listObject in (IList)value) { xmlString += ConvertToElement(attribute.Name, listObject, version); } } else { xmlString += ConvertToElement(attribute.Name, value, version); } } } } } else { // Throw an exception if the property is null ("{ get; set; }" is missing). throw new MissingGetterException(member.Name); } } } // Add additional child elements. var additionalElements = this.GetAdditionalElements(version); if (additionalElements != null) { foreach (var additionalElement in additionalElements) { xmlString += additionalElement; } } // Return the final string with the ending tag. return(xmlString + "</" + elementName + ">"); }