/// <summary> /// Sets the field to its default value if it has one (specified as DefaultValueAttribute or an empty collection if it is an embedded one) /// </summary> /// <param name="result"></param> /// <param name="field"></param> /// <returns>True if default value was set</returns> private static bool _CheckAndSetDefaultValue(object result, SFieldInfo field) { if (field.IsEmbeddedList) { _AddList(result, field, new List <object>()); return(true); } if (!field.HasDefaultValue) { return(false); } field.SetValue(result, field.DefaultValue); return(true); }
/// <summary> /// Reads childnodes of the given node (either nodes or attributes) /// </summary> /// <param name="parent">Node to process</param> /// <param name="o">Object to put the values in</param> /// <param name="attributes">True for processing attributes, false for nodes</param> private void _ReadChildNodes(XmlNode parent, object o, bool attributes) { IEnumerable nodes; if (parent == null) { nodes = null; } else if (attributes) { nodes = parent.Attributes; } else { nodes = parent.ChildNodes; } List <SFieldInfo> fields = o.GetType().GetFields(attributes); if (nodes != null) { //Dictionary of all embedded lists to allow interleaved/mixed elements Dictionary <string, Tuple <SFieldInfo, List <object> > > embLists = new Dictionary <string, Tuple <SFieldInfo, List <object> > >(); foreach (XmlNode node in nodes) { if (node is XmlComment || node.LocalName == "xsd" || node.LocalName == "xsi") { continue; } SFieldInfo field = new SFieldInfo(); int curField; for (curField = 0; curField < fields.Count; curField++) { field = fields[curField]; if (field.Name == node.Name || field.AltName == node.Name || (field.IsEmbeddedList && node.Name.StartsWith(field.Name))) { break; } } if (curField >= fields.Count) { string msg = "Unexpected element: %n"; if (fields.Count > 0) { msg += " Expected: " + string.Join(", ", fields.Select(f => f.Name)); } _ErrorHandler.HandleError(new CXmlException(msg, node)); continue; } if (field.IsByteArray) { fields.RemoveAt(curField); //Do this also on error byte[] value; try { value = Convert.FromBase64String(node.InnerText); } catch (Exception) { _ErrorHandler.HandleError(new CXmlInvalidValueException("Invalid value in %n: %v", node, node.InnerText)); if (!_CheckAndSetDefaultValue(o, field)) { _ErrorHandler.HandleError(new CXmlException("No default value for %n", node)); } continue; } field.SetValue(o, value); } else if (field.IsEmbeddedList) { Tuple <SFieldInfo, List <object> > entry; if (!embLists.TryGetValue(field.Name, out entry)) { entry = new Tuple <SFieldInfo, List <object> >(field, new List <object>()); embLists.Add(field.Name, entry); } object subValue = _GetValue(node, field.SubType); if (subValue != null) { entry.Item2.Add(subValue); } } else { fields.RemoveAt(curField); //Do this also on error object value = _GetValue(node, field.Type, field.ArrayItemName); if (value == null) { if (_CheckAndSetDefaultValue(o, field)) { continue; } if (!field.IsNullable) { _ErrorHandler.HandleError(new CXmlException("No default value for unset field at %n", node)); continue; } } if (field.Ranged != null && value != null && !field.Ranged.IsValid(field.IsNullable ? field.SubType : field.Type, value)) { _ErrorHandler.HandleError(new CXmlInvalidValueException("Value in %n is not in the range " + field.Ranged + ". (Value=%v)", node, value.ToString())); } field.SetValue(o, value); } } //Add embedded lists foreach (Tuple <SFieldInfo, List <object> > entry in embLists.Values) { _AddList(o, entry.Item1, entry.Item2); fields.Remove(entry.Item1); } } foreach (SFieldInfo field in fields) { if (!_CheckAndSetDefaultValue(o, field)) { if (parent != null) { _ErrorHandler.HandleError(new CXmlMissingElementException(parent, field)); } object value = _GetValue(null, field.Type, field.ArrayItemName, field.GetValue(o)); if (value != null) { field.SetValue(o, value); } } } }
/// <summary> /// Creates a collection (array or list) and puts it into the specified field /// </summary> /// <param name="o">Object which listField belongs to</param> /// <param name="listField">Field that will contain the list</param> /// <param name="values">Collection of values that are used to fill the list</param> private static void _AddList(object o, SFieldInfo listField, ICollection values) { listField.SetValue(o, _CreateList(listField.Type, values)); }