/// <summary> /// Deserializes the XML reperesentation of a key-value pair, as specified, and returns /// a <c>KeyValuePair</c> instance containing the deserialized data. /// </summary> /// <param name="baseElement">The element contating the XML reperesentation of a key-value pair.</param> /// <returns>a <c>KeyValuePair</c> instance containing the deserialized data</returns> private object DeserializeKeyValuePair(XElement baseElement) { Type[] genArgs = m_type.GetGenericArguments(); Type keyType = genArgs[0]; Type valueType = genArgs[1]; XName xnameKey = TypeNamespace.IfEmptyThenNone() + "Key"; XName xnameValue = TypeNamespace.IfEmptyThenNone() + "Value"; object keyValue, valueValue; if (ReflectionUtils.IsBasicType(keyType)) { try { keyValue = ReflectionUtils.ConvertBasicType( baseElement.Element(xnameKey).Value, keyType); } catch (NullReferenceException) { keyValue = null; } } else if (ReflectionUtils.IsStringConvertibleIFormattable(keyType)) { keyValue = keyType.InvokeMember(string.Empty, BindingFlags.CreateInstance, null, null, new object[] { baseElement.Element(xnameKey).Value }); } else if (ReflectionUtils.IsCollectionType(keyType)) { keyValue = DeserializeCollectionValue(keyType, baseElement.Element(xnameKey), xnameKey, null); } else { var ser = new YAXSerializer(keyType, m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); ser.m_documentDefaultNamespace = m_documentDefaultNamespace; ser.SetNamespaceToOverrideEmptyNamespace(xnameKey.Namespace.IfEmptyThenNone()); keyValue = ser.DeserializeBase(baseElement.Element(xnameKey)); m_parsingErrors.AddRange(ser.ParsingErrors); } if (ReflectionUtils.IsBasicType(valueType)) { try { valueValue = ReflectionUtils.ConvertBasicType(baseElement.Element(xnameValue).Value, valueType); } catch (NullReferenceException) { valueValue = null; } } else if (ReflectionUtils.IsStringConvertibleIFormattable(valueType)) { valueValue = valueType.InvokeMember(string.Empty, BindingFlags.CreateInstance, null, null, new object[] { baseElement.Element(xnameValue).Value }); } else if (ReflectionUtils.IsCollectionType(valueType)) { valueValue = DeserializeCollectionValue(valueType, baseElement.Element(xnameValue), xnameValue, null); } else { var ser = new YAXSerializer(valueType, m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); ser.m_documentDefaultNamespace = m_documentDefaultNamespace; ser.SetNamespaceToOverrideEmptyNamespace(xnameValue.Namespace.IfEmptyThenNone()); valueValue = ser.DeserializeBase(baseElement.Element(xnameValue)); m_parsingErrors.AddRange(ser.ParsingErrors); } object pair = m_type.InvokeMember(string.Empty, System.Reflection.BindingFlags.CreateInstance, null, null, new object[] { keyValue, valueValue }); return pair; }
/// <summary> /// Retreives the collection value. /// </summary> /// <param name="colType">Type of the collection to be retrieved.</param> /// <param name="xelemValue">The value of xml element.</param> /// <param name="memberAlias">The member's alias, used only in exception titles.</param> /// <param name="colAttrInstance">The collection attribute instance.</param> /// <returns></returns> private object DeserializeCollectionValue(Type colType, XElement xelemValue, XName memberAlias, YAXCollectionAttribute colAttrInstance) { object containerObj = null; if (ReflectionUtils.IsInstantiableCollection(colType)) { var containerSer = new YAXSerializer(colType, m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); containerSer.m_documentDefaultNamespace = m_documentDefaultNamespace; containerSer.SetNamespaceToOverrideEmptyNamespace( memberAlias.Namespace. IfEmptyThen(TypeNamespace). IfEmptyThenNone()); containerSer.IsCraetedToDeserializeANonCollectionMember = true; containerSer.RemoveDeserializedXmlNodes = true; containerObj = containerSer.DeserializeBase(xelemValue); m_parsingErrors.AddRange(containerSer.ParsingErrors); } var lst = new List<object>(); // this will hold the actual data items Type itemType = ReflectionUtils.GetCollectionItemType(colType); if (ReflectionUtils.IsBasicType(itemType) && colAttrInstance != null && colAttrInstance.SerializationType == YAXCollectionSerializationTypes.Serially) { // What if the collection was serialized serially char[] seps = colAttrInstance.SeparateBy.ToCharArray(); // can white space characters be added to the separators? if (colAttrInstance.IsWhiteSpaceSeparator) { seps = seps.Union(new [] { ' ', '\t', '\r', '\n' }).ToArray(); } string elemValue = xelemValue.Value; string[] items = elemValue.Split(seps, StringSplitOptions.RemoveEmptyEntries); foreach (string wordItem in items) { try { lst.Add(ReflectionUtils.ConvertBasicType(wordItem, itemType)); } catch { OnExceptionOccurred(new YAXBadlyFormedInput(memberAlias.ToString(), elemValue), m_defaultExceptionType); } } } else //if the collection was serialized recursively { bool isPrimitive = ReflectionUtils.IsBasicType(itemType); XName eachElemName = null; if (colAttrInstance != null && colAttrInstance.EachElementName != null) { eachElemName = StringUtils.RefineSingleElement(colAttrInstance.EachElementName); eachElemName = eachElemName.OverrideNsIfEmpty(memberAlias.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } var elemsToSearch = eachElemName == null ? xelemValue.Elements() : xelemValue.Elements(eachElemName); foreach (XElement childElem in elemsToSearch) { Type curElementType = itemType; bool curElementIsPrimitive = isPrimitive; XAttribute realTypeAttribute = childElem.Attribute_NamespaceSafe(m_yaxLibNamespaceUri + m_trueTypeAttrName, m_documentDefaultNamespace); if (realTypeAttribute != null) { Type theRealType = ReflectionUtils.GetTypeByName(realTypeAttribute.Value); if (theRealType != null) { curElementType = theRealType; curElementIsPrimitive = ReflectionUtils.IsBasicType(curElementType); } } // TODO: check if curElementType is derived or is the same is itemType, for speed concerns perform this check only when elementName is null if (eachElemName == null && (curElementType == typeof(object) || !ReflectionUtils.IsTypeEqualOrInheritedFromType(curElementType, itemType))) continue; if (curElementIsPrimitive) { try { lst.Add(ReflectionUtils.ConvertBasicType(childElem.Value, curElementType)); } catch { OnExceptionOccurred(new YAXBadlyFormedInput(childElem.Name.ToString(), childElem.Value), m_defaultExceptionType); } } else { var ser = new YAXSerializer(curElementType, m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); ser.m_documentDefaultNamespace = m_documentDefaultNamespace; ser.SetNamespaceToOverrideEmptyNamespace( memberAlias.Namespace. IfEmptyThen(TypeNamespace). IfEmptyThenNone()); lst.Add(ser.DeserializeBase(childElem)); m_parsingErrors.AddRange(ser.ParsingErrors); } } } // end of else if // Now what should I do with the filled list: lst Type dicKeyType, dicValueType; if (ReflectionUtils.IsArray(colType)) { XAttribute dimsAttr = xelemValue.Attribute_NamespaceSafe(m_yaxLibNamespaceUri + m_dimsAttrName, m_documentDefaultNamespace); int[] dims = new int[0]; if (dimsAttr != null) { dims = StringUtils.ParseArrayDimsString(dimsAttr.Value); } Array arrayInstance = null; if (dims.Length > 0) { var lowerBounds = new int[dims.Length]; // an array of zeros arrayInstance = Array.CreateInstance(itemType, dims, lowerBounds); // create the array int count = Math.Min(arrayInstance.Length, lst.Count); // now fill the array for (int i = 0; i < count; i++) { int[] inds = GetArrayDimentionalIndex(i, dims); try { arrayInstance.SetValue(lst[i], inds); } catch { OnExceptionOccurred( new YAXCannotAddObjectToCollection(memberAlias.ToString(), lst[i]), m_defaultExceptionType); } } } else { arrayInstance = Array.CreateInstance(itemType, lst.Count); // create the array int count = Math.Min(arrayInstance.Length, lst.Count); // now fill the array for (int i = 0; i < count; i++) { try { arrayInstance.SetValue(lst[i], i); } catch { OnExceptionOccurred( new YAXCannotAddObjectToCollection(memberAlias.ToString(), lst[i]), m_defaultExceptionType); } } } return arrayInstance; } else if (ReflectionUtils.IsIDictionary(colType, out dicKeyType, out dicValueType)) { //The collection is a Dictionary object dic = containerObj; foreach (var lstItem in lst) { object key = itemType.GetProperty("Key").GetValue(lstItem, null); object value = itemType.GetProperty("Value").GetValue(lstItem, null); try { colType.InvokeMember("Add", BindingFlags.InvokeMethod, null, dic, new[] { key, value }); } catch { OnExceptionOccurred(new YAXCannotAddObjectToCollection(memberAlias.ToString(), lstItem), m_defaultExceptionType); } } return dic; } else if (ReflectionUtils.IsNonGenericIDictionary(colType)) { object col = containerObj; foreach (var lstItem in lst) { object key = lstItem.GetType().GetProperty("Key", BindingFlags.Instance | BindingFlags.Public).GetValue(lstItem, null); object value = lstItem.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public).GetValue(lstItem, null); try { colType.InvokeMember("Add", BindingFlags.InvokeMethod, null, col, new[] { key, value }); } catch { OnExceptionOccurred(new YAXCannotAddObjectToCollection(memberAlias.ToString(), lstItem), m_defaultExceptionType); } } return col; } else if (ReflectionUtils.IsTypeEqualOrInheritedFromType(colType, typeof(BitArray))) { var bArray = new bool[lst.Count]; for (int i = 0; i < bArray.Length; i++) { try { bArray[i] = (bool)lst[i]; } catch { } } object col = colType.InvokeMember(string.Empty, System.Reflection.BindingFlags.CreateInstance, null, null, new object[] { bArray }); return col; } else if (ReflectionUtils.IsTypeEqualOrInheritedFromType(colType, typeof(Stack)) || ReflectionUtils.IsTypeEqualOrInheritedFromType(colType, typeof(Stack<>))) { //object col = colType.InvokeMember(string.Empty, System.Reflection.BindingFlags.CreateInstance, null, null, new object[0]); object col = containerObj; const string additionMethodName = "Push"; for (int i = lst.Count - 1; i >= 0; i--) // the loop must be from end to front { try { colType.InvokeMember(additionMethodName, BindingFlags.InvokeMethod, null, col, new[] { lst[i] }); } catch { OnExceptionOccurred(new YAXCannotAddObjectToCollection(memberAlias.ToString(), lst[i]), m_defaultExceptionType); } } return col; } else if (ReflectionUtils.IsIEnumerable(colType)) { if (containerObj == null) return lst; object col = containerObj; string additionMethodName = "Add"; if (ReflectionUtils.IsTypeEqualOrInheritedFromType(colType, typeof(Queue)) || ReflectionUtils.IsTypeEqualOrInheritedFromType(colType, typeof(Queue<>))) { additionMethodName = "Enqueue"; } else if (ReflectionUtils.IsTypeEqualOrInheritedFromType(colType, typeof(LinkedList<>))) { additionMethodName = "AddLast"; } foreach (var lstItem in lst) { try { colType.InvokeMember(additionMethodName, BindingFlags.InvokeMethod, null, col, new object[] { lstItem }); } catch { OnExceptionOccurred(new YAXCannotAddObjectToCollection(memberAlias.ToString(), lstItem), this.m_defaultExceptionType); } } return col; } return null; }
private object DeserializeTaggedDictionaryValue(XElement xelemValue, XName alias, Type type, YAXCollectionAttribute colAttributeInstance, YAXDictionaryAttribute dicAttrInstance) { // otherwise the "else if(member.IsTreatedAsCollection)" block solves the problem Type keyType, valueType; if (!ReflectionUtils.IsIDictionary(type, out keyType, out valueType)) { throw new Exception("elemValue must be a Dictionary"); } // deserialize non-collection fields var containerSer = new YAXSerializer(type, m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); containerSer.m_documentDefaultNamespace = m_documentDefaultNamespace; containerSer.SetNamespaceToOverrideEmptyNamespace( alias.Namespace. IfEmptyThen(TypeNamespace). IfEmptyThenNone()); containerSer.IsCraetedToDeserializeANonCollectionMember = true; containerSer.RemoveDeserializedXmlNodes = true; object dic = containerSer.DeserializeBase(xelemValue); m_parsingErrors.AddRange(containerSer.ParsingErrors); // now try to deserialize collection fields Type pairType = null; ReflectionUtils.IsIEnumerable(type, out pairType); XName eachElementName = StringUtils.RefineSingleElement(ReflectionUtils.GetTypeFriendlyName(pairType)); bool isKeyAttrib = false; bool isValueAttrib = false; bool isKeyContent = false; bool isValueContent = false; XName keyAlias = alias.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone() + "Key"; XName valueAlias = alias.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone() + "Value"; if (colAttributeInstance != null && colAttributeInstance.EachElementName != null) { eachElementName = StringUtils.RefineSingleElement(colAttributeInstance.EachElementName); eachElementName = eachElementName.OverrideNsIfEmpty(alias.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } if (dicAttrInstance != null) { if (dicAttrInstance.EachPairName != null) { eachElementName = StringUtils.RefineSingleElement(dicAttrInstance.EachPairName); eachElementName = eachElementName.OverrideNsIfEmpty(alias.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } if (dicAttrInstance.SerializeKeyAs == YAXNodeTypes.Attribute) { isKeyAttrib = ReflectionUtils.IsBasicType(keyType); } else if (dicAttrInstance.SerializeKeyAs == YAXNodeTypes.Content) { isKeyContent = ReflectionUtils.IsBasicType(keyType); } if (dicAttrInstance.SerializeValueAs == YAXNodeTypes.Attribute) { isValueAttrib = ReflectionUtils.IsBasicType(valueType); } else if (dicAttrInstance.SerializeValueAs == YAXNodeTypes.Content) { isValueContent = ReflectionUtils.IsBasicType(valueType); } if (dicAttrInstance.KeyName != null) { keyAlias = StringUtils.RefineSingleElement(dicAttrInstance.KeyName); keyAlias = keyAlias.OverrideNsIfEmpty(alias.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } if (dicAttrInstance.ValueName != null) { valueAlias = StringUtils.RefineSingleElement(dicAttrInstance.ValueName); valueAlias = valueAlias.OverrideNsIfEmpty(alias.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } } foreach (XElement childElem in xelemValue.Elements(eachElementName)) { object key = null, value = null; YAXSerializer keySer = null, valueSer = null; bool isKeyFound = VerifyDictionaryPairElements(ref keyType, ref isKeyAttrib, ref isKeyContent, keyAlias, childElem); bool isValueFound = VerifyDictionaryPairElements(ref valueType, ref isValueAttrib, ref isValueContent, valueAlias, childElem); if (!isKeyFound && !isValueFound) continue; if (isKeyFound) { if (isKeyAttrib) { key = ReflectionUtils.ConvertBasicType(childElem.Attribute_NamespaceSafe(keyAlias, m_documentDefaultNamespace).Value, keyType); } else if (isKeyContent) { key = ReflectionUtils.ConvertBasicType(childElem.GetXmlContent(), keyType); } else if (ReflectionUtils.IsBasicType(keyType)) { key = ReflectionUtils.ConvertBasicType(childElem.Element(keyAlias).Value, keyType); } else { if (keySer == null) { keySer = new YAXSerializer(keyType, m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); keySer.m_documentDefaultNamespace = m_documentDefaultNamespace; keySer.SetNamespaceToOverrideEmptyNamespace(keyAlias.Namespace); } key = keySer.DeserializeBase(childElem.Element(keyAlias)); m_parsingErrors.AddRange(keySer.ParsingErrors); } } if (isValueFound) { if (isValueAttrib) { value = ReflectionUtils.ConvertBasicType(childElem.Attribute_NamespaceSafe(valueAlias, m_documentDefaultNamespace).Value, valueType); } else if (isValueContent) { value = ReflectionUtils.ConvertBasicType(childElem.GetXmlContent(), valueType); } else if (ReflectionUtils.IsBasicType(valueType)) { value = ReflectionUtils.ConvertBasicType(childElem.Element(valueAlias).Value, valueType); } else { if (valueSer == null) { valueSer = new YAXSerializer(valueType, m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); valueSer.m_documentDefaultNamespace = m_documentDefaultNamespace; valueSer.SetNamespaceToOverrideEmptyNamespace(valueAlias.Namespace); } value = valueSer.DeserializeBase(childElem.Element(valueAlias)); m_parsingErrors.AddRange(valueSer.ParsingErrors); } } try { type.InvokeMember("Add", BindingFlags.InvokeMethod, null, dic, new object[] { key, value }); } catch { OnExceptionOccurred( new YAXCannotAddObjectToCollection(alias.LocalName, new KeyValuePair<object, object>(key, value)), m_defaultExceptionType); } } return dic; }
/// <summary> /// Retreives the value of the element from the specified XML element or attribute. /// </summary> /// <param name="o">The object to store the retrieved value at.</param> /// <param name="member">The member of the specified object whose value we intent to retreive.</param> /// <param name="elemValue">The value of the element stored as string.</param> /// <param name="xelemValue">The XML element value to be retreived. If the value to be retreived /// has been stored in an XML attribute, this reference is <c>null</c>.</param> private void RetreiveElementValue(object o, MemberWrapper member, string elemValue, XElement xelemValue) { Type memberType = member.MemberType; // try to retrieve the real-type if specified if (xelemValue != null) { XAttribute realTypeAttribute = xelemValue.Attribute_NamespaceSafe(m_yaxLibNamespaceUri + m_trueTypeAttrName, m_documentDefaultNamespace); if (realTypeAttribute != null) { Type realType = ReflectionUtils.GetTypeByName(realTypeAttribute.Value); if (realType != null) { memberType = realType; } } } if (xelemValue != null && XMLUtils.IsElementCompletelyEmpty(xelemValue) && !ReflectionUtils.IsBasicType(memberType) && !member.IsTreatedAsCollection && !member.IsTreatedAsDictionary && !AtLeastOneOfMembersExists(xelemValue, memberType)) { try { member.SetValue(o, member.DefaultValue); } catch { OnExceptionOccurred(new YAXDefaultValueCannotBeAssigned(member.Alias.LocalName, member.DefaultValue), member.TreatErrorsAs); } } else if (memberType == typeof(string)) { if (String.IsNullOrEmpty(elemValue) && xelemValue != null) { elemValue = xelemValue.IsEmpty ? null : String.Empty; } try { member.SetValue(o, elemValue); } catch { OnExceptionOccurred(new YAXPropertyCannotBeAssignedTo(member.Alias.LocalName), m_defaultExceptionType); } } else if (ReflectionUtils.IsBasicType(memberType)) { object convertedObj; if (ReflectionUtils.IsNullable(memberType) && String.IsNullOrEmpty(elemValue)) { convertedObj = member.DefaultValue; } else { convertedObj = ReflectionUtils.ConvertBasicType(elemValue, memberType); } try { try { member.SetValue(o, convertedObj); } catch { OnExceptionOccurred(new YAXPropertyCannotBeAssignedTo(member.Alias.LocalName), m_defaultExceptionType); } } catch (Exception ex) { if (ex is YAXException) { throw; } OnExceptionOccurred(new YAXBadlyFormedInput(member.Alias.LocalName, elemValue), member.TreatErrorsAs); try { member.SetValue(o, member.DefaultValue); } catch { OnExceptionOccurred(new YAXDefaultValueCannotBeAssigned(member.Alias.LocalName, member.DefaultValue), m_defaultExceptionType); } } } else if (member.IsTreatedAsDictionary && member.DictionaryAttributeInstance != null) { DeserializeTaggedDictionaryMember(o, member, xelemValue); } else if (member.IsTreatedAsCollection) { DeserializeCollectionMember(o, member, memberType, elemValue, xelemValue); } else { var ser = new YAXSerializer(memberType, m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); ser.m_documentDefaultNamespace = m_documentDefaultNamespace; ser.SetNamespaceToOverrideEmptyNamespace( member.Namespace. IfEmptyThen(TypeNamespace). IfEmptyThenNone()); ser.IsCraetedToDeserializeANonCollectionMember = !(member.IsTreatedAsDictionary || member.IsTreatedAsCollection); if (m_desObject != null) // i.e. it is in resuming mode ser.SetDeserializationBaseObject(member.GetValue(o)); object convertedObj = ser.DeserializeBase(xelemValue); m_parsingErrors.AddRange(ser.ParsingErrors); try { member.SetValue(o, convertedObj); } catch { OnExceptionOccurred(new YAXPropertyCannotBeAssignedTo(member.Alias.LocalName), m_defaultExceptionType); } } }