예제 #1
0
        /// <summary>
        /// Convenience method to add a <see cref="MediaItemAspect"/> from the given <paramref name="aspectData"/> dictionary
        /// </summary>
        /// <param name="aspectData">Dictionary of MediaItemAspects.</param>
        /// <param name="value">Metadata values used for creation.</param>
        public static void AddOrUpdateAspect(IDictionary <Guid, IList <MediaItemAspect> > aspectData, MultipleMediaItemAspect value)
        {
            Guid aspectId = value.Metadata.AspectId;
            IList <MediaItemAspect> aspects;

            if (!aspectData.ContainsKey(aspectId))
            {
                aspects = aspectData[aspectId] = new List <MediaItemAspect>();
            }
            else
            {
                aspects = aspectData[aspectId];
            }

            int index = GetMatchingAspect(aspects, value);

            if (index >= 0)
            {
                aspects[index] = value;
            }
            else
            {
                aspects.Add(value);
            }
        }
예제 #2
0
        /// <summary>
        /// Convenience method to get a <see cref="MediaItemAspect"/> from the given <paramref name="aspects"/> dictionary or add a new instance to the
        /// dictionary and return it.
        /// </summary>
        /// <param name="aspects">Dictionary of MediaItemAspects.</param>
        /// <param name="mediaItemAspectMetadata">Definiton of metadata that is used for creation.</param>
        public static MultipleMediaItemAspect CreateAspect(IDictionary <Guid, IList <MediaItemAspect> > aspects, MultipleMediaItemAspectMetadata mediaItemAspectMetadata)
        {
            MultipleMediaItemAspect mediaAspect = new MultipleMediaItemAspect(mediaItemAspectMetadata);

            AddOrUpdateAspect(aspects, mediaAspect);
            return(mediaAspect);
        }
예제 #3
0
        private static string GetIdentifier(MultipleMediaItemAspect externalAspect, string externalIdType)
        {
            string source = externalAspect.GetAttributeValue <string>(ExternalIdentifierAspect.ATTR_SOURCE);
            string id     = externalAspect.GetAttributeValue <string>(ExternalIdentifierAspect.ATTR_ID);

            return(string.Format("{0} | {1} | {2}", source, externalIdType, id));
        }
예제 #4
0
 private static bool SpecificationsAreEqual(MediaItemAspect aspect, MultipleMediaItemAspect value, MediaItemAspectMetadata.AttributeSpecification spec)
 {
     if (aspect[spec] == null)
     {
         return(value[spec] == null);
     }
     return(aspect[spec].Equals(value[spec]));
 }
예제 #5
0
        public static void AddOrUpdateExternalIdentifier(IDictionary <Guid, IList <MediaItemAspect> > aspectData,
                                                         string source, string type, string id)
        {
            MultipleMediaItemAspect aspect = new MultipleMediaItemAspect(ExternalIdentifierAspect.Metadata);

            aspect.SetAttribute(ExternalIdentifierAspect.ATTR_SOURCE, source);
            aspect.SetAttribute(ExternalIdentifierAspect.ATTR_TYPE, type);
            aspect.SetAttribute(ExternalIdentifierAspect.ATTR_ID, id);
            AddOrUpdateAspect(aspectData, aspect);
        }
예제 #6
0
        public static void AddOrUpdateRelationship(IDictionary <Guid, IList <MediaItemAspect> > aspectData,
                                                   Guid role, Guid linkedRole, Guid linkedId, int linkedIndex)
        {
            MultipleMediaItemAspect aspect = new MultipleMediaItemAspect(RelationshipAspect.Metadata);

            aspect.SetAttribute(RelationshipAspect.ATTR_ROLE, role);
            aspect.SetAttribute(RelationshipAspect.ATTR_LINKED_ROLE, linkedRole);
            aspect.SetAttribute(RelationshipAspect.ATTR_LINKED_ID, linkedId);
            aspect.SetAttribute(RelationshipAspect.ATTR_RELATIONSHIP_INDEX, linkedIndex);
            AddOrUpdateAspect(aspectData, aspect);
        }
예제 #7
0
        private static int GetMatchingAspect(IList <MediaItemAspect> aspects, MultipleMediaItemAspect value)
        {
            for (int index = 0; index < aspects.Count; index++)
            {
                MediaItemAspect aspect = aspects[index];
                if (value.Metadata.UniqueAttributeSpecifications.All(spec => SpecificationsAreEqual(aspect, value, spec.Value)))
                {
                    return(index);
                }
            }

            return(-1);
        }
예제 #8
0
        public static IDictionary <Guid, IList <MediaItemAspect> > GetAspects(IEnumerable <MediaItemAspect> aspectData)
        {
            IDictionary <Guid, IList <MediaItemAspect> > aspects = new Dictionary <Guid, IList <MediaItemAspect> >();

            foreach (MediaItemAspect aspect in aspectData)
            {
                SingleMediaItemAspect singleAspect = aspect as SingleMediaItemAspect;
                if (singleAspect != null)
                {
                    SetAspect(aspects, singleAspect);
                }
                else
                {
                    MultipleMediaItemAspect multiAspect = aspect as MultipleMediaItemAspect;
                    if (multiAspect != null)
                    {
                        AddOrUpdateAspect(aspects, multiAspect);
                    }
                }
            }
            return(aspects);
        }
        public static bool MergeVideoResourceAspects(IDictionary <Guid, IList <MediaItemAspect> > extractedAspects, IDictionary <Guid, IList <MediaItemAspect> > existingAspects)
        {
            //Extracted aspects
            IList <MultipleMediaItemAspect> providerResourceAspects;

            if (!MediaItemAspect.TryGetAspects(extractedAspects, ProviderResourceAspect.Metadata, out providerResourceAspects))
            {
                return(false);
            }

            string       accessorPath = (string)providerResourceAspects.First().GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
            ResourcePath resourcePath = ResourcePath.Deserialize(accessorPath);

            IList <MultipleMediaItemAspect> videoAspects;

            MediaItemAspect.TryGetAspects(extractedAspects, VideoStreamAspect.Metadata, out videoAspects);

            IList <MultipleMediaItemAspect> videoAudioAspects;

            MediaItemAspect.TryGetAspects(extractedAspects, VideoAudioStreamAspect.Metadata, out videoAudioAspects);

            IList <MultipleMediaItemAspect> subtitleAspects;

            MediaItemAspect.TryGetAspects(extractedAspects, SubtitleAspect.Metadata, out subtitleAspects);

            //Existing aspects
            IList <MultipleMediaItemAspect> existingProviderResourceAspects;

            MediaItemAspect.TryGetAspects(existingAspects, ProviderResourceAspect.Metadata, out existingProviderResourceAspects);

            Dictionary <int, int> resourceIndexMap = new Dictionary <int, int>();
            int newResourceIndex = -1;

            if (existingProviderResourceAspects != null)
            {
                foreach (MultipleMediaItemAspect providerResourceAspect in existingProviderResourceAspects)
                {
                    int resouceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                    if (newResourceIndex < resouceIndex)
                    {
                        newResourceIndex = resouceIndex;
                    }
                }
            }
            newResourceIndex++;

            bool resourceExists = false; //Resource might already be added in the initial add

            foreach (MultipleMediaItemAspect providerResourceAspect in providerResourceAspects)
            {
                if (existingProviderResourceAspects != null)
                {
                    accessorPath = (string)providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);

                    foreach (MultipleMediaItemAspect exisitingProviderResourceAspect in existingProviderResourceAspects)
                    {
                        string existingAccessorPath = (string)exisitingProviderResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                        if (accessorPath.Equals(existingAccessorPath, StringComparison.InvariantCultureIgnoreCase))
                        {
                            resourceExists = true;
                            break;
                        }
                    }
                }

                if (resourceExists)
                {
                    continue;
                }

                int resouceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                if (!resourceIndexMap.ContainsKey(resouceIndex))
                {
                    resourceIndexMap.Add(resouceIndex, newResourceIndex);
                }
                newResourceIndex++;

                MultipleMediaItemAspect newPra = MediaItemAspect.CreateAspect(existingAspects, ProviderResourceAspect.Metadata);
                newPra.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[resouceIndex]);
                newPra.SetAttribute(ProviderResourceAspect.ATTR_TYPE, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_TYPE));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_MIME_TYPE));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_SIZE, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_SIZE));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_PARENT_DIRECTORY_ID, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_PARENT_DIRECTORY_ID));
                newPra.SetAttribute(ProviderResourceAspect.ATTR_SYSTEM_ID, providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_SYSTEM_ID));

                if (videoAspects != null)
                {
                    foreach (MultipleMediaItemAspect videoAspect in videoAspects)
                    {
                        int videoResourceIndex = videoAspect.GetAttributeValue <int>(VideoStreamAspect.ATTR_RESOURCE_INDEX);
                        if (videoResourceIndex == resouceIndex)
                        {
                            MultipleMediaItemAspect newVa = MediaItemAspect.CreateAspect(existingAspects, VideoStreamAspect.Metadata);
                            newVa.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                            newVa.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_STREAM_INDEX));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_ASPECTRATIO));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_DURATION, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_DURATION));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_FPS, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_FPS));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_HEIGHT));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEOBITRATE, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEOBITRATE));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEOENCODING));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_WIDTH, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_WIDTH));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_TYPE));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART_SET));
                            newVa.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET_NAME, videoAspect.GetAttributeValue(VideoStreamAspect.ATTR_VIDEO_PART_SET_NAME));
                        }
                    }
                }

                //Correct sets
                Dictionary <string, int> setList = new Dictionary <string, int>();
                MediaItemAspect.TryGetAspects(existingAspects, ProviderResourceAspect.Metadata, out existingProviderResourceAspects);
                IList <MultipleMediaItemAspect> existingVideoAspects;
                if (MediaItemAspect.TryGetAspects(existingAspects, VideoStreamAspect.Metadata, out existingVideoAspects))
                {
                    int newMediaSet = 0;
                    Dictionary <int, int> knownSets = new Dictionary <int, int>();
                    foreach (MultipleMediaItemAspect videoStreamAspect in existingVideoAspects)
                    {
                        string filename = null;
                        foreach (MultipleMediaItemAspect pra in existingProviderResourceAspects)
                        {
                            if (pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX) == videoStreamAspect.GetAttributeValue <int>(VideoStreamAspect.ATTR_RESOURCE_INDEX))
                            {
                                accessorPath = (string)pra.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                resourcePath = resourcePath = ResourcePath.Deserialize(accessorPath);
                                filename     = resourcePath.FileName ?? Path.GetFileName(resourcePath.BasePathSegment.Path);
                                break;
                            }
                        }
                        videoStreamAspect.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART_SET, GetMultipartSetNumber(ref setList, ref newMediaSet, filename));
                    }
                }

                if (videoAudioAspects != null)
                {
                    foreach (MultipleMediaItemAspect videoAudioAspect in videoAudioAspects)
                    {
                        int audioResourceIndex = videoAudioAspect.GetAttributeValue <int>(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX);
                        if (audioResourceIndex == resouceIndex)
                        {
                            MultipleMediaItemAspect newVaa = MediaItemAspect.CreateAspect(existingAspects, VideoAudioStreamAspect.Metadata);
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[audioResourceIndex]);
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_STREAM_INDEX));
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOBITRATE, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOBITRATE));
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS));
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOENCODING));
                            newVaa.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOLANGUAGE, videoAudioAspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOLANGUAGE));
                        }
                    }
                }

                //Internal subtitles
                if (subtitleAspects != null)
                {
                    foreach (MultipleMediaItemAspect subAspect in subtitleAspects)
                    {
                        int videoResourceIndex = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX);
                        int subResourceIndex   = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_RESOURCE_INDEX);
                        if (videoResourceIndex == resouceIndex && subResourceIndex == -1)
                        {
                            MultipleMediaItemAspect newSa = MediaItemAspect.CreateAspect(existingAspects, SubtitleAspect.Metadata);
                            newSa.SetAttribute(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                            newSa.SetAttribute(SubtitleAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[videoResourceIndex]);
                            newSa.SetAttribute(SubtitleAspect.ATTR_STREAM_INDEX, subAspect.GetAttributeValue(SubtitleAspect.ATTR_STREAM_INDEX));
                            newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_ENCODING, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_ENCODING));
                            newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_FORMAT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_FORMAT));
                            newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE));
                            newSa.SetAttribute(SubtitleAspect.ATTR_INTERNAL, subAspect.GetAttributeValue(SubtitleAspect.ATTR_INTERNAL));
                            newSa.SetAttribute(SubtitleAspect.ATTR_DEFAULT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_DEFAULT));
                            newSa.SetAttribute(SubtitleAspect.ATTR_FORCED, subAspect.GetAttributeValue(SubtitleAspect.ATTR_FORCED));
                        }
                    }
                }

                //External subtitles
                ResourcePath existingResourcePath;
                if (subtitleAspects != null)
                {
                    foreach (MultipleMediaItemAspect subAspect in subtitleAspects)
                    {
                        int subResourceIndex = subAspect.GetAttributeValue <int>(SubtitleAspect.ATTR_RESOURCE_INDEX);
                        if (subResourceIndex == resouceIndex)
                        {
                            //Find video resource
                            int videoResourceIndex = -1;
                            if (existingProviderResourceAspects != null)
                            {
                                foreach (MultipleMediaItemAspect existingProviderResourceAspect in existingProviderResourceAspects)
                                {
                                    accessorPath = (string)providerResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                    resourcePath = ResourcePath.Deserialize(accessorPath);

                                    accessorPath         = (string)existingProviderResourceAspect.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH);
                                    existingResourcePath = ResourcePath.Deserialize(accessorPath);

                                    if (ResourcePath.GetFileNameWithoutExtension(resourcePath).StartsWith(ResourcePath.GetFileNameWithoutExtension(existingResourcePath), StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        bool resPrimary = existingProviderResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_PRIMARY;
                                        if (resPrimary == true)
                                        {
                                            videoResourceIndex = providerResourceAspect.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX);
                                            break;
                                        }
                                    }
                                }
                            }

                            if (videoResourceIndex >= 0)
                            {
                                MultipleMediaItemAspect newSa = MediaItemAspect.CreateAspect(existingAspects, SubtitleAspect.Metadata);
                                newSa.SetAttribute(SubtitleAspect.ATTR_VIDEO_RESOURCE_INDEX, videoResourceIndex);
                                newSa.SetAttribute(SubtitleAspect.ATTR_RESOURCE_INDEX, resourceIndexMap[subResourceIndex]);
                                newSa.SetAttribute(SubtitleAspect.ATTR_STREAM_INDEX, subAspect.GetAttributeValue(SubtitleAspect.ATTR_STREAM_INDEX));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_ENCODING, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_ENCODING));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_FORMAT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_FORMAT));
                                newSa.SetAttribute(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE, subAspect.GetAttributeValue(SubtitleAspect.ATTR_SUBTITLE_LANGUAGE));
                                newSa.SetAttribute(SubtitleAspect.ATTR_INTERNAL, subAspect.GetAttributeValue(SubtitleAspect.ATTR_INTERNAL));
                                newSa.SetAttribute(SubtitleAspect.ATTR_DEFAULT, subAspect.GetAttributeValue(SubtitleAspect.ATTR_DEFAULT));
                                newSa.SetAttribute(SubtitleAspect.ATTR_FORCED, subAspect.GetAttributeValue(SubtitleAspect.ATTR_FORCED));
                            }
                        }
                    }
                }
            }
            return(true);
        }
예제 #10
0
        public static MediaItemAspect Deserialize(XmlReader reader)
        {
            if (!reader.MoveToAttribute("Id"))
            {
                throw new ArgumentException("Media item aspect cannot be deserialized: 'Id' attribute missing");
            }
            Guid aspectTypeId = new Guid(reader.ReadContentAsString());
            bool deleted      = false;

            if (reader.MoveToAttribute("Deleted"))
            {
                deleted = reader.ReadContentAsBoolean();
            }
            reader.MoveToElement();
            IMediaItemAspectTypeRegistration miatr = ServiceRegistration.Get <IMediaItemAspectTypeRegistration>();
            MediaItemAspectMetadata          miaType;

            if (!miatr.LocallyKnownMediaItemAspectTypes.TryGetValue(aspectTypeId, out miaType))
            {
                throw new ArgumentException(string.Format("Media item aspect cannot be deserialized: Unknown media item aspect type '{0}' in [{1} / {2}]", aspectTypeId, string.Join(",", miatr.LocallyKnownMediaItemAspectTypes.Keys), string.Join(",", miatr.LocallyKnownMediaItemAspectTypes.Values.ToList().Select(x => x.Name))));
            }
            MediaItemAspect result = null;

            if (miaType is SingleMediaItemAspectMetadata)
            {
                result = new SingleMediaItemAspect((SingleMediaItemAspectMetadata)miaType);
            }
            else if (miaType is MultipleMediaItemAspectMetadata)
            {
                result = new MultipleMediaItemAspect((MultipleMediaItemAspectMetadata)miaType);
            }
            result.Deleted = deleted;
            if (SoapHelper.ReadEmptyStartElement(reader, "Aspect"))
            {
                return(result);
            }
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                if (!reader.MoveToAttribute("Name"))
                {
                    throw new ArgumentException("Media item aspect attribute cannot be deserialized: 'Name' attribute missing");
                }
                String attributeName = reader.ReadContentAsString();
                reader.MoveToElement();
                if (SoapHelper.ReadEmptyStartElement(reader, "Attr"))
                {
                    continue;
                }
                MediaItemAspectMetadata.AttributeSpecification attributeSpec;
                if (!miaType.AttributeSpecifications.TryGetValue(attributeName, out attributeSpec))
                {
                    throw new ArgumentException(string.Format(
                                                    "Media item aspect attribute cannot be deserialized: Unknown attribute specification '{0}'", attributeName));
                }
                if (attributeSpec.IsCollectionAttribute)
                {
                    IList valuesCollection = attributeSpec.CreateValuesCollection();
                    while (reader.NodeType != XmlNodeType.EndElement)
                    {
                        valuesCollection.Add(DeserializeValue(reader, attributeSpec.AttributeType));
                    }
                    result.SetCollectionAttribute(attributeSpec, valuesCollection);
                }
                else
                {
                    result.SetAttribute(attributeSpec, DeserializeValue(reader, attributeSpec.AttributeType));
                }
                reader.ReadEndElement(); // Attr
            }
            reader.ReadEndElement();     // Aspect
            return(result);
        }