/// <summary> /// Serializes a collection object. /// </summary> /// <param name="insertionLocation">The insertion location.</param> /// <param name="elementName">Name of the element.</param> /// <param name="elementValue">The object to be serailized.</param> /// <param name="collectionAttrInst">The collection attribute instance.</param> /// <param name="format">formatting string, which is going to be applied to all members of the collection.</param> /// <returns> /// an instance of <c>XElement</c> which will contain the serailized collection /// </returns> private XElement MakeCollectionElement( XElement insertionLocation, XName elementName, object elementValue, YAXCollectionAttribute collectionAttrInst, string format) { if (elementValue == null) { return new XElement(elementName); } if (!(elementValue is IEnumerable)) { throw new ArgumentException("elementValue must be an IEnumerable"); } // serialize other non-collection members var ser = new YAXSerializer(elementValue.GetType(), m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); ser.m_documentDefaultNamespace = m_documentDefaultNamespace; ser.SetNamespaceToOverrideEmptyNamespace(elementName.Namespace); ser.SetBaseElement(insertionLocation); XElement elemToAdd = ser.SerializeBase(elementValue, elementName); ImportNamespaces(ser); m_parsingErrors.AddRange(ser.ParsingErrors); // now iterate through collection members var collectionInst = elementValue as IEnumerable; var serType = YAXCollectionSerializationTypes.Recursive; string seperator = string.Empty; XName eachElementName = null; if (collectionAttrInst != null) { serType = collectionAttrInst.SerializationType; seperator = collectionAttrInst.SeparateBy; if (collectionAttrInst.EachElementName != null) { eachElementName = StringUtils.RefineSingleElement(collectionAttrInst.EachElementName); if (eachElementName.Namespace.IsEmpty()) RegisterNamespace(eachElementName.Namespace, null); eachElementName = eachElementName.OverrideNsIfEmpty(elementName.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } } Type colItemType = ReflectionUtils.GetCollectionItemType(elementValue.GetType()); if (serType == YAXCollectionSerializationTypes.Serially && !ReflectionUtils.IsBasicType(colItemType)) serType = YAXCollectionSerializationTypes.Recursive; UdtWrapper colItemsUdt = TypeWrappersPool.Pool.GetTypeWrapper(colItemType, this); if (serType == YAXCollectionSerializationTypes.Serially && elemToAdd.IsEmpty) { var sb = new StringBuilder(); bool isFirst = true; object objToAdd = null; foreach (object obj in collectionInst) { if (colItemsUdt.IsEnum) objToAdd = colItemsUdt.EnumWrapper.GetAlias(obj); else if (format != null) objToAdd = ReflectionUtils.TryFormatObject(obj, format); else objToAdd = obj; if (isFirst) { sb.Append(objToAdd.ToXmlValue()); isFirst = false; } else { sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", seperator, objToAdd); } } bool alreadyAdded = false; elemToAdd = MakeBaseElement(insertionLocation, elementName, sb.ToString(), out alreadyAdded); if (alreadyAdded) elemToAdd = null; } else { //var elem = new XElement(elementName, null); object objToAdd = null; foreach (object obj in collectionInst) { objToAdd = (format == null) ? obj : ReflectionUtils.TryFormatObject(obj, format); var curElemName = eachElementName; if(curElemName == null) { UdtWrapper udt = TypeWrappersPool.Pool.GetTypeWrapper(obj.GetType(), this); curElemName = udt.Alias; } XElement itemElem = this.AddObjectToElement(elemToAdd, curElemName.OverrideNsIfEmpty(elementName.Namespace), objToAdd); if (!obj.GetType().EqualsOrIsNullableOf(colItemType)) { itemElem.AddAttributeNamespaceSafe(m_yaxLibNamespaceUri + m_trueTypeAttrName, obj.GetType().FullName, m_documentDefaultNamespace); if (itemElem.Parent == null) // i.e., it has been removed, e.g., because all its members have been serialized outside the element elemToAdd.Add(itemElem); // return it back, or undelete this item RegisterYaxLibNamespace(); } } } int[] arrayDims = ReflectionUtils.GetArrayDimensions(elementValue); if (arrayDims != null && arrayDims.Length > 1) { elemToAdd.AddAttributeNamespaceSafe(m_yaxLibNamespaceUri + m_dimsAttrName, StringUtils.GetArrayDimsString(arrayDims), m_documentDefaultNamespace); RegisterYaxLibNamespace(); } return elemToAdd; }
/// <summary> /// Makes an XML element with the specified name, corresponding to the object specified. /// </summary> /// <param name="insertionLocation">The insertion location.</param> /// <param name="name">The name of the element.</param> /// <param name="value">The object to be serialized in an XML element.</param> /// <param name="alreadyAdded">if set to <c>true</c> specifies the element returned is /// already added to the parent element and should not be added once more.</param> /// <returns> /// an instance of <c>XElement</c> which will contain the serialized object, /// or <c>null</c> if the serialized object is already added to the base element /// </returns> private XElement MakeBaseElement(XElement insertionLocation, XName name, object value, out bool alreadyAdded) { alreadyAdded = false; if (value == null || ReflectionUtils.IsBasicType(value.GetType())) { if (value != null) value = value.ToXmlValue(); return new XElement(name, value); } else if (ReflectionUtils.IsStringConvertibleIFormattable(value.GetType())) { object elementValue = value.GetType().InvokeMember("ToString", BindingFlags.InvokeMethod, null, value, new object[0]); return new XElement(name, elementValue); } else { var ser = new YAXSerializer(value.GetType(), m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); ser.m_documentDefaultNamespace = m_documentDefaultNamespace; ser.SetNamespaceToOverrideEmptyNamespace(name.Namespace); ser.SetBaseElement(insertionLocation); XElement elem = ser.SerializeBase(value, name); ImportNamespaces(ser); m_parsingErrors.AddRange(ser.ParsingErrors); alreadyAdded = true; return elem; } }
/// <summary> /// Creates a dictionary element according to the specified options, as described /// by the attribute instances. /// </summary> /// <param name="insertionLocation">The insertion location.</param> /// <param name="elementName">Name of the element.</param> /// <param name="elementValue">The element value, corresponding to a dictionary object.</param> /// <param name="dicAttrInst">reference to the dictionary attribute instance.</param> /// <param name="collectionAttrInst">reference to collection attribute instance.</param> /// <returns> /// an instance of <c>XElement</c> which contains the dictionary object /// serialized properly /// </returns> private XElement MakeDictionaryElement( XElement insertionLocation, XName elementName, object elementValue, YAXDictionaryAttribute dicAttrInst, YAXCollectionAttribute collectionAttrInst) { if (elementValue == null) { return new XElement(elementName); } Type keyType, valueType; if (!ReflectionUtils.IsIDictionary(elementValue.GetType(), out keyType, out valueType)) { throw new ArgumentException("elementValue must be a Dictionary"); } // serialize other non-collection members var ser = new YAXSerializer(elementValue.GetType(), m_exceptionPolicy, m_defaultExceptionType, m_serializationOption); ser.m_documentDefaultNamespace = m_documentDefaultNamespace; ser.SetNamespaceToOverrideEmptyNamespace(elementName.Namespace); ser.SetBaseElement(insertionLocation); XElement elem = ser.SerializeBase(elementValue, elementName); ImportNamespaces(ser); m_parsingErrors.AddRange(ser.ParsingErrors); // now iterate through collection members var dicInst = elementValue as IEnumerable; bool isKeyAttrib = false; bool isValueAttrib = false; bool isKeyContent = false; bool isValueContent = false; string keyFormat = null; string valueFormat = null; XName keyAlias = elementName.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone() + "Key"; XName valueAlias = elementName.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone() + "Value"; XName eachElementName = null; if (collectionAttrInst != null && !String.IsNullOrEmpty(collectionAttrInst.EachElementName)) { eachElementName = StringUtils.RefineSingleElement(collectionAttrInst.EachElementName); if (eachElementName.Namespace.IsEmpty()) RegisterNamespace(eachElementName.Namespace, null); eachElementName = eachElementName.OverrideNsIfEmpty(elementName.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } if (dicAttrInst != null) { if (dicAttrInst.EachPairName != null) { eachElementName = StringUtils.RefineSingleElement(dicAttrInst.EachPairName); if (eachElementName.Namespace.IsEmpty()) RegisterNamespace(eachElementName.Namespace, null); eachElementName = eachElementName.OverrideNsIfEmpty(elementName.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } if (dicAttrInst.SerializeKeyAs == YAXNodeTypes.Attribute) { isKeyAttrib = ReflectionUtils.IsBasicType(keyType); } else if (dicAttrInst.SerializeKeyAs == YAXNodeTypes.Content) { isKeyContent = ReflectionUtils.IsBasicType(keyType); } if (dicAttrInst.SerializeValueAs == YAXNodeTypes.Attribute) { isValueAttrib = ReflectionUtils.IsBasicType(valueType); } else if (dicAttrInst.SerializeValueAs == YAXNodeTypes.Content) { isValueContent = ReflectionUtils.IsBasicType(valueType); } keyFormat = dicAttrInst.KeyFormatString; valueFormat = dicAttrInst.ValueFormatString; keyAlias = StringUtils.RefineSingleElement(dicAttrInst.KeyName ?? "Key"); if (keyAlias.Namespace.IsEmpty()) RegisterNamespace(keyAlias.Namespace, null); keyAlias = keyAlias.OverrideNsIfEmpty(elementName.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); valueAlias = StringUtils.RefineSingleElement(dicAttrInst.ValueName ?? "Value"); if (valueAlias.Namespace.IsEmpty()) RegisterNamespace(valueAlias.Namespace, null); valueAlias = valueAlias.OverrideNsIfEmpty(elementName.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } foreach (object obj in dicInst) { object keyObj = obj.GetType().GetProperty("Key").GetValue(obj, null); object valueObj = obj.GetType().GetProperty("Value").GetValue(obj, null); bool areKeyOfSameType = true; bool areValueOfSameType = true; if (keyObj != null && !keyObj.GetType().EqualsOrIsNullableOf(keyType)) areKeyOfSameType = false; if (valueObj != null && !valueObj.GetType().EqualsOrIsNullableOf(valueType)) areValueOfSameType = false; if (keyFormat != null) { keyObj = ReflectionUtils.TryFormatObject(keyObj, keyFormat); } if (valueFormat != null) { valueObj = ReflectionUtils.TryFormatObject(valueObj, valueFormat); } if (eachElementName == null) { eachElementName = StringUtils.RefineSingleElement(ReflectionUtils.GetTypeFriendlyName(obj.GetType())); eachElementName = eachElementName.OverrideNsIfEmpty(elementName.Namespace.IfEmptyThen(TypeNamespace).IfEmptyThenNone()); } var elemChild = new XElement(eachElementName, null); if (isKeyAttrib && areKeyOfSameType) { elemChild.AddAttributeNamespaceSafe(keyAlias, keyObj, m_documentDefaultNamespace); } else if (isKeyContent && areKeyOfSameType) { elemChild.AddXmlContent(keyObj); } else { XElement addedElem = AddObjectToElement(elemChild, keyAlias, keyObj); if (!areKeyOfSameType) { if (addedElem.Parent == null) { // sometimes empty elements are removed because its members are serialized in // other elements, therefore we need to make sure to re-add the element. elemChild.Add(addedElem); } addedElem.AddAttributeNamespaceSafe(m_yaxLibNamespaceUri + m_trueTypeAttrName, keyObj.GetType().FullName, m_documentDefaultNamespace); RegisterYaxLibNamespace(); } } if (isValueAttrib && areValueOfSameType) { elemChild.AddAttributeNamespaceSafe(valueAlias, valueObj, m_documentDefaultNamespace); } else if (isValueContent && areValueOfSameType) { elemChild.AddXmlContent(valueObj); } else { XElement addedElem = AddObjectToElement(elemChild, valueAlias, valueObj); if (!areValueOfSameType) { if (addedElem.Parent == null) { // sometimes empty elements are removed because its members are serialized in // other elements, therefore we need to make sure to re-add the element. elemChild.Add(addedElem); } addedElem.AddAttributeNamespaceSafe(m_yaxLibNamespaceUri + m_trueTypeAttrName, valueObj.GetType().FullName, m_documentDefaultNamespace); RegisterYaxLibNamespace(); } } elem.Add(elemChild); } return elem; }