private static void SerializeMembers( XDocument document, IXPathSerializable serializable, HashSet <object> objectsAlreadySerialized, SerializableMemberInfo[] membersToSerialize, MemberInfo[] useMembers = null, Mapping parentMapping = null, bool emitTypeInfo = false, int version = 0, IFormatProvider provider = null, XmlNamespaceManager resolver = null) { foreach (var member in membersToSerialize) { // Skip non-serializable members if (member.GetSingleCustomAttribute <NotForSerializationAttribute>() != null) { continue; } // Check if the member is serializable in the current version int serializedFromVersion = 0; var versionAttribute = member.GetSingleCustomAttribute <SerializedFromVersionAttribute>(); if (versionAttribute != null) { serializedFromVersion = versionAttribute.Version; } if (version < serializedFromVersion) { continue; } var mapping = member.GetMapping(serializable.GetType(), parentMapping); object value = member.GetValue(serializable); // Remember the type in case we need to emit it into the Xml Type deserializeAs = null; if (value != null && emitTypeInfo) { deserializeAs = value.GetType(); } var context = new SerializationContext(serializable, member, mapping, useMembers, deserializeAs, emitTypeInfo, version, provider, resolver); // TODO: what if mandatory? if (value != null && value.GetType().IsArray&& !mapping.AsBase64) { SerializeArrayMember(document, value, context, objectsAlreadySerialized); } else { if (value != null && typeof(IXPathSerializable).IsAssignableFrom(value.GetType())) { SerializeXPathSerializableMember(document, value, context, objectsAlreadySerialized); } else { SerializeSimpleMember(document, value, context); } } } }
private static void LoadMembersFromXml( XDocument document, IXPathSerializable serializable, SerializableMemberInfo[] membersToLoad, MemberInfo[] useMembers, Mapping parentMapping, int version, IFormatProvider provider, XmlNamespaceManager resolver) { foreach (var member in membersToLoad) { // Skip non-serializable members if (member.GetSingleCustomAttribute <NotForSerializationAttribute>() != null) { continue; } // Check if the member is serializable in the current version int serializedFromVersion = 0; var versionAttribute = member.GetSingleCustomAttribute <SerializedFromVersionAttribute>(); if (versionAttribute != null) { serializedFromVersion = versionAttribute.Version; } if (version < serializedFromVersion) { continue; } var mapping = member.GetMapping(serializable.GetType(), parentMapping); var mappedElement = document.Root.XPathSelectElement(mapping.ElementXPath, resolver); bool mappedToAttributeWhichIsNotFound = !String.IsNullOrWhiteSpace(mapping.AttributeName) && (mappedElement == null || mappedElement.Attribute(XPathHelper.ConvertToXName(mapping.AttributeName, resolver)) == null); // Ensure mandatory xml elements/attributes are present if (mapping.IsXmlMandatory) { if (mappedElement == null) { throw new SerializationException( String.Format( "Cannot deserialize {0} '{1}', type '{2}'. Could not find the element with path '{3}'", member.MemeberTypeString, member.Name, serializable.GetType(), mapping.ElementXPath)); } else if (mappedToAttributeWhichIsNotFound) { throw new SerializationException( String.Format( "Cannot deserialize {0} '{1}', type '{2}'. Could not find the attribute '{3}' of the element with path '{4}'", member.MemeberTypeString, member.Name, serializable.GetType(), mapping.AttributeName, mapping.ElementXPath)); } } // Short-circuit for nulls if (mappedElement == null || mappedToAttributeWhichIsNotFound) { member.SetValue(serializable, null); continue; } if (string.IsNullOrWhiteSpace(mapping.AttributeName)) { var isNullAttribute = mappedElement.Attribute(Constants.NullValueAttributeName); if (isNullAttribute != null) { member.SetValue(serializable, null); continue; } } // Determine the type of the deserialized value Type emittedType = null; if (mappedElement != null && string.IsNullOrWhiteSpace(mapping.AttributeName)) { var typeAttribute = mappedElement.Attribute(Constants.TypeInfoAttributeName); if (typeAttribute != null) { emittedType = Type.GetType(typeAttribute.Value); // TODO: handle all kind of exceptions } } Type deserializeAs; if (emittedType != null) { deserializeAs = emittedType; } else { deserializeAs = member.MemberType; } var context = new SerializationContext( serializable, member, mapping, useMembers, deserializeAs, version: version, formatProvider: provider, resolver: resolver); if (deserializeAs.IsArray && !mapping.AsBase64) { LoadArrayMemberFromXml(mappedElement, context); } else if (typeof(IXPathSerializable).IsAssignableFrom(deserializeAs)) { LoadXPathSerializableMemberFromXml(document, context); } else { LoadSimpleMemberFromXml(mappedElement, context); } } }
private static XDocument ToXmlInternal( XDocument document, IXPathSerializable serializable, HashSet <object> objectsAlreadySerialized, MemberInfo[] useMembers, Mapping parentMapping, bool emitTypeInfo, int version, IFormatProvider provider, XmlNamespaceManager resolver) { // Take care of circular references if (objectsAlreadySerialized.Contains(serializable)) { throw new SerializationException( String.Format("A circular reference was detected while serializing an object of type '{0}'", serializable.GetType())); } else { objectsAlreadySerialized.Add(serializable); } if (document == null) { document = new XDocument(); } // Initialize namespace resolver from class attributes if (resolver == null) { resolver = new XmlNamespaceManager(new NameTable()); } var namespaceAttributes = serializable.GetType().GetCustomAttributes(typeof(NamespacePrefixAttribute), true); foreach (NamespacePrefixAttribute namespaceAttribute in namespaceAttributes) { resolver.AddNamespace(namespaceAttribute.Prefix, namespaceAttribute.Uri); } // Ensure minimal xml structure var minimalXmlAttributes = serializable.GetType().GetCustomAttributes(typeof(MinimalXmlStructureAttribute), true); if (minimalXmlAttributes != null) { foreach (MinimalXmlStructureAttribute minimalXmlAttribute in minimalXmlAttributes) { string xPath = minimalXmlAttribute.ElementXPath; if (String.IsNullOrWhiteSpace(xPath)) { xPath = XmlConvert.EncodeName(serializable.GetType().Name); } XmlOperations.GetOrCreateElement(document, xPath, resolver); } } var typeInfo = SerializableTypeInfo.GetTypeInfo(serializable.GetType()); var membersToSerialize = typeInfo.Members.Where(x => useMembers == null || useMembers.Length == 0 || useMembers.Contains(x.MemberInfo)); SerializeMembers( document, serializable, objectsAlreadySerialized, membersToSerialize.ToArray(), useMembers, parentMapping, emitTypeInfo, version, provider, resolver); // Return resulting document return(document); }