public void DefaultValuesTest() { AtomResourceCollectionMetadata resourceCollection = new AtomResourceCollectionMetadata(); this.Assert.IsNull(resourceCollection.Title, "Expected null default value for property 'Title'."); this.Assert.IsNull(resourceCollection.Accept, "Expected null default value for property 'Accept'."); this.Assert.IsNull(resourceCollection.Categories, "Expected null default value for property 'Categories'."); }
public void PropertySettersNullTest() { AtomResourceCollectionMetadata resourceCollection = new AtomResourceCollectionMetadata() { Title = null, Accept = null, Categories = null, }; this.Assert.IsNull(resourceCollection.Title, "Expected null value for property 'Title'."); this.Assert.IsNull(resourceCollection.Accept, "Expected null value for property 'Accept'."); this.Assert.IsNull(resourceCollection.Categories, "Expected null value for property 'Categories'."); }
/// <summary>Determines an extension method to get the <see cref="T:Microsoft.OData.Core.Atom.AtomResourceCollectionMetadata" /> for an entity set in service document.</summary> /// <returns>An <see cref="T:Microsoft.OData.Core.Atom.AtomResourceCollectionMetadata" /> instance or null if no annotation of that type exists.</returns> /// <param name="entitySet">The entity set in service document to get the annotation from.</param> public static AtomResourceCollectionMetadata Atom(this ODataEntitySetInfo entitySet) { ExceptionUtils.CheckArgumentNotNull(entitySet, "entitySet"); AtomResourceCollectionMetadata collectionMetadata = entitySet.GetAnnotation <AtomResourceCollectionMetadata>(); if (collectionMetadata == null) { collectionMetadata = new AtomResourceCollectionMetadata(); entitySet.SetAnnotation(collectionMetadata); } return(collectionMetadata); }
/// <summary> /// Reads an "app:accept" element and adds the new information to <paramref name="collectionMetadata"/>. /// </summary> /// <param name="collectionMetadata">The non-null collection metadata object to augment.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The start of the app:accept element. /// Post-Condition: Any - The next node after the app:accept element. /// </remarks> internal void ReadAcceptElementInCollection(AtomResourceCollectionMetadata collectionMetadata) { Debug.Assert(collectionMetadata != null, "collectionMetadata != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.XmlReader.LocalName == AtomConstants.AtomPublishingAcceptElementName, "Expected element named 'accept'."); Debug.Assert(this.XmlReader.NamespaceURI == AtomConstants.AtomPublishingNamespace, "Element 'accept' should be in the atom publishing namespace."); if (collectionMetadata.Accept != null) { throw new ODataException(Strings.ODataAtomServiceDocumentMetadataDeserializer_MultipleAcceptElementsFoundInCollection); } collectionMetadata.Accept = this.XmlReader.ReadElementValue(); }
public void PropertyGettersAndSettersTest() { AtomTextConstruct title = new AtomTextConstruct(); string accept = "mime/type"; AtomCategoriesMetadata categories = new AtomCategoriesMetadata(); AtomResourceCollectionMetadata resourceCollection = new AtomResourceCollectionMetadata() { Title = title, Accept = accept, Categories = categories }; this.Assert.AreSame(title, resourceCollection.Title, "Expected reference equal values for property 'Title'."); this.Assert.AreSame(accept, resourceCollection.Accept, "Expected reference equal values for property 'Accept'."); this.Assert.AreSame(categories, resourceCollection.Categories, "Expected reference equal values for property 'Categories'."); }
/// <summary> /// Reads an atom:title element and adds the new information to <paramref name="odataServiceDocumentElement"/> and (if ATOM metadata reading is on) <paramref name="collectionMetadata"/>. /// </summary> /// <param name="collectionMetadata">The collection metadata object to augment, or null if metadata reading is not on.</param> /// <param name="odataServiceDocumentElement">The non-null service document element info object being populated.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The start of the title element. /// Post-Condition: Any - The next node after the title element. /// </remarks> internal void ReadTitleElementInCollection(AtomResourceCollectionMetadata collectionMetadata, ODataServiceDocumentElement odataServiceDocumentElement) { Debug.Assert(!this.ReadAtomMetadata || collectionMetadata != null, "collectionMetadata parameter should be non-null when ATOM metadata reading is enabled."); Debug.Assert(odataServiceDocumentElement != null, "collectionInfo != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.XmlReader.LocalName == AtomConstants.AtomTitleElementName, "Expected element named 'title'."); Debug.Assert(this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace, "Element 'title' should be in the atom namespace."); AtomTextConstruct titleTextConstruct = this.ReadTitleElement(); if (odataServiceDocumentElement.Name == null) { odataServiceDocumentElement.Name = titleTextConstruct.Text; } if (this.ReadAtomMetadata) { collectionMetadata.Title = titleTextConstruct; } }
/// <summary> /// Reads the service document element and returns the new element instance. /// </summary> /// <typeparam name="T">Type of service element to read.</typeparam> /// <returns>Service Element instance.</returns> private T ReadServiceDocumentElement <T>() where T : ODataServiceDocumentElement, new() { T serviceDocumentElement = new T(); string href = this.XmlReader.GetAttribute(this.AtomHRefAttributeName, this.EmptyNamespace); ValidationUtils.ValidateServiceDocumentElementUrl(href); serviceDocumentElement.Url = this.ProcessUriFromPayload(href, this.XmlReader.XmlBaseUri); bool enableAtomMetadataReading = this.MessageReaderSettings.EnableAtomMetadataReading; string name = this.XmlReader.GetAttribute(this.ODataNameAttribute, this.ODataMetadataNamespace); serviceDocumentElement.Name = name; AtomResourceCollectionMetadata collectionMetadata = null; if (enableAtomMetadataReading) { collectionMetadata = new AtomResourceCollectionMetadata(); } if (!this.XmlReader.IsEmptyElement) { // read over the service document element. this.XmlReader.ReadStartElement(); bool atomTitlesReadAlready = false; do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.AtomPublishingNamespace)) { if (this.XmlReader.LocalNameEquals(this.AtomPublishingCategoriesElementName)) { if (enableAtomMetadataReading) { this.ServiceDocumentMetadataDeserializer.ReadCategoriesElementInCollection(collectionMetadata); } else { this.XmlReader.Skip(); } } else if (this.XmlReader.LocalNameEquals(this.AtomPublishingAcceptElementName)) { if (enableAtomMetadataReading) { this.ServiceDocumentMetadataDeserializer.ReadAcceptElementInCollection(collectionMetadata); } else { this.XmlReader.Skip(); } } else { // Throw error if we find anything other then a 'app:categories' or an 'app:accept' element in the ATOM publishing namespace. throw new ODataException(Strings.ODataAtomServiceDocumentDeserializer_UnexpectedElementInResourceCollection(this.XmlReader.LocalName)); } } else if (this.XmlReader.NamespaceEquals(this.AtomNamespace)) { if (this.XmlReader.LocalNameEquals(this.AtomTitleElementName)) { if (atomTitlesReadAlready) { throw new ODataException(Strings.ODataAtomServiceDocumentMetadataDeserializer_MultipleTitleElementsFound(AtomConstants.AtomPublishingCollectionElementName)); } this.ServiceDocumentMetadataDeserializer.ReadTitleElementInCollection(collectionMetadata, serviceDocumentElement); atomTitlesReadAlready = true; } else { // Skip all other elements in the atom namespace this.XmlReader.Skip(); } } else { // For now, skip all other elements. this.XmlReader.Skip(); } break; case XmlNodeType.EndElement: // end of service document element. break; default: // ignore all other nodes. this.XmlReader.Skip(); break; } }while (this.XmlReader.NodeType != XmlNodeType.EndElement); } this.AssertXmlCondition(true, XmlNodeType.EndElement); // read over the end tag of the service document element or the start tag if the collection element is empty. this.XmlReader.Read(); if (enableAtomMetadataReading) { serviceDocumentElement.SetAnnotation(collectionMetadata); } return(serviceDocumentElement); }
/// <summary> /// Writes the ATOM metadata for a single entity set element. /// </summary> /// <param name="entitySetInfo">The entity set element to get the metadata for and write it.</param> internal void WriteEntitySetInfoMetadata(ODataEntitySetInfo entitySetInfo) { Debug.Assert(entitySetInfo != null, "collection != null"); Debug.Assert(entitySetInfo.Url != null, "collection.Url should have been validated at this point"); AtomResourceCollectionMetadata metadata = entitySetInfo.GetAnnotation <AtomResourceCollectionMetadata>(); AtomTextConstruct title = null; if (metadata != null) { title = metadata.Title; } if (entitySetInfo.Name != null) { if (title == null) { title = new AtomTextConstruct { Text = entitySetInfo.Name }; } else if (string.CompareOrdinal(title.Text, entitySetInfo.Name) != 0) { throw new ODataException(ODataErrorStrings.ODataAtomServiceDocumentMetadataSerializer_ResourceCollectionNameAndTitleMismatch(entitySetInfo.Name, title.Text)); } } // The ATOMPUB specification requires a title. // <atom:title>title</atom:title> // Note that this will write an empty atom:title element even if the title is null. if (this.UseServerFormatBehavior && title.Kind == AtomTextConstructKind.Text) { // For WCF DS server we must not write the type attribute, just a simple <atom:title>title<atom:title> this.WriteElementWithTextContent( AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, title.Text); } else { this.WriteTextConstruct(AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, title); } if (metadata != null) { string accept = metadata.Accept; if (accept != null) { // <app:accept>accept</app:accept> this.WriteElementWithTextContent( string.Empty, AtomConstants.AtomPublishingAcceptElementName, AtomConstants.AtomPublishingNamespace, accept); } AtomCategoriesMetadata categories = metadata.Categories; if (categories != null) { // <app:categories> this.XmlWriter.WriteStartElement(string.Empty, AtomConstants.AtomPublishingCategoriesElementName, AtomConstants.AtomPublishingNamespace); Uri href = categories.Href; bool? fixedValue = categories.Fixed; string scheme = categories.Scheme; IEnumerable <AtomCategoryMetadata> categoriesCollection = categories.Categories; if (href != null) { // Out of line categories document if (fixedValue.HasValue || scheme != null || (categoriesCollection != null && categoriesCollection.Any())) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_CategoriesHrefWithOtherValues); } this.XmlWriter.WriteAttributeString(AtomConstants.AtomHRefAttributeName, this.UriToUrlAttributeValue(href)); } else { // Inline categories document // fixed='yes|no' if (fixedValue.HasValue) { this.XmlWriter.WriteAttributeString( AtomConstants.AtomPublishingFixedAttributeName, fixedValue.Value ? AtomConstants.AtomPublishingFixedYesValue : AtomConstants.AtomPublishingFixedNoValue); } // scheme='scheme' if (scheme != null) { this.XmlWriter.WriteAttributeString(AtomConstants.AtomCategorySchemeAttributeName, scheme); } if (categoriesCollection != null) { foreach (AtomCategoryMetadata category in categoriesCollection) { // <atom:category/> this.WriteCategory(AtomConstants.NonEmptyAtomNamespacePrefix, category.Term, category.Scheme, category.Label); } } } // </app:categories> this.XmlWriter.WriteEndElement(); } } }
/// <summary> /// Reads an app:categories element as well as each atom:category element contained within it, and adds the new information to <paramref name="collectionMetadata"/>. /// </summary> /// <param name="collectionMetadata">The non-null collection metadata object to augment.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The start of the app:categories element. /// Post-Condition: Any - The next node after the app:categories element. /// </remarks> internal void ReadCategoriesElementInCollection(AtomResourceCollectionMetadata collectionMetadata) { Debug.Assert(collectionMetadata != null, "collectionMetadata != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.XmlReader.LocalName == AtomConstants.AtomPublishingCategoriesElementName, "Expected element named 'categories'."); Debug.Assert(this.XmlReader.NamespaceURI == AtomConstants.AtomPublishingNamespace, "Element 'categories' should be in the atom publishing namespace."); AtomCategoriesMetadata categoriesMetadata = new AtomCategoriesMetadata(); List <AtomCategoryMetadata> categoryList = new List <AtomCategoryMetadata>(); while (this.XmlReader.MoveToNextAttribute()) { string attributeValue = this.XmlReader.Value; if (this.XmlReader.NamespaceEquals(this.EmptyNamespace)) { if (this.XmlReader.LocalNameEquals(this.AtomHRefAttributeName)) { categoriesMetadata.Href = this.ProcessUriFromPayload(attributeValue, this.XmlReader.XmlBaseUri); } else if (this.XmlReader.LocalNameEquals(this.AtomPublishingFixedAttributeName)) { if (String.CompareOrdinal(attributeValue, AtomConstants.AtomPublishingFixedYesValue) == 0) { categoriesMetadata.Fixed = true; } else if (String.CompareOrdinal(attributeValue, AtomConstants.AtomPublishingFixedNoValue) == 0) { categoriesMetadata.Fixed = false; } else { throw new ODataException(Strings.ODataAtomServiceDocumentMetadataDeserializer_InvalidFixedAttributeValue(attributeValue)); } } else if (this.XmlReader.LocalNameEquals(this.AtomCategorySchemeAttributeName)) { categoriesMetadata.Scheme = attributeValue; } } } this.XmlReader.MoveToElement(); if (!this.XmlReader.IsEmptyElement) { // read over the categories element this.XmlReader.ReadStartElement(); do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.AtomNamespace) && this.XmlReader.LocalNameEquals(this.AtomCategoryElementName)) { categoryList.Add(this.ReadCategoryElementInCollection()); } break; case XmlNodeType.EndElement: // end of 'categories' element. break; default: // ignore all other nodes. this.XmlReader.Skip(); break; } }while (this.XmlReader.NodeType != XmlNodeType.EndElement); } // if (!this.XmlReader.IsEmptyElement) // read over the end tag of the categories element or the start tag if the categories element is empty. this.XmlReader.Read(); categoriesMetadata.Categories = new ReadOnlyEnumerable <AtomCategoryMetadata>(categoryList); collectionMetadata.Categories = categoriesMetadata; }
/// <summary>Determines an extension method to get the <see cref="T:Microsoft.OData.Core.Atom.AtomResourceCollectionMetadata" /> for an entity set in service document.</summary> /// <returns>An <see cref="T:Microsoft.OData.Core.Atom.AtomResourceCollectionMetadata" /> instance or null if no annotation of that type exists.</returns> /// <param name="entitySet">The entity set in service document to get the annotation from.</param> public static AtomResourceCollectionMetadata Atom(this ODataEntitySetInfo entitySet) { ExceptionUtils.CheckArgumentNotNull(entitySet, "entitySet"); AtomResourceCollectionMetadata collectionMetadata = entitySet.GetAnnotation<AtomResourceCollectionMetadata>(); if (collectionMetadata == null) { collectionMetadata = new AtomResourceCollectionMetadata(); entitySet.SetAnnotation(collectionMetadata); } return collectionMetadata; }
public void CategoryMetadataOnWorkspaceCollectionCategoriesWriterTest() { var testCases = this.CreateAtomCategoryTestCases(); // Convert test cases to test descriptions var testDescriptors = testCases.Select(testCase => { AtomResourceCollectionMetadata metadata = new AtomResourceCollectionMetadata { Categories = new AtomCategoriesMetadata { Categories = new[] { testCase.Category } } }; ODataEntitySetInfo collection = new ODataEntitySetInfo { Url = new Uri("http://odata.org/collection") }; collection.SetAnnotation(metadata); ODataServiceDocument serviceDocument = new ODataServiceDocument { EntitySets = new[] { collection } }; return new PayloadWriterTestDescriptor<ODataServiceDocument>( this.Settings, serviceDocument, testConfiguration => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = testCase.Xml, ExpectedException2 = testCase.ExpectedException, FragmentExtractor = result => result .Element(TestAtomConstants.AtomPublishingXNamespace + TestAtomConstants.AtomPublishingWorkspaceElementName) .Element(TestAtomConstants.AtomPublishingXNamespace + TestAtomConstants.AtomPublishingCollectionElementName) .Element(TestAtomConstants.AtomPublishingXNamespace + TestAtomConstants.AtomPublishingCategoriesElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomCategoryElementName) }); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.WriterTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyTopLevelContent( testDescriptor, testConfiguration, (messageWriter) => messageWriter.WriteServiceDocument(testDescriptor.PayloadItems.Single()), this.Assert, baselineLogger:this.Logger); }); }
public void AtomCategoriesMetadataTest() { var testCases = new [] { // Empty categories new { CategoriesMetadata = new AtomCategoriesMetadata(), Xml = "<categories xmlns='http://www.w3.org/2007/app'/>", ExpectedException = (ExpectedException)null }, // Categories with href new { CategoriesMetadata = new AtomCategoriesMetadata() { Href = new Uri("http://odata.org/href") }, Xml = "<categories href='http://odata.org/href' xmlns='http://www.w3.org/2007/app'/>", ExpectedException = (ExpectedException)null }, // Categories with href and non-null empty categories (null and empty collection should be treated the same) new { CategoriesMetadata = new AtomCategoriesMetadata() { Href = new Uri("http://odata.org/href"), Categories = new AtomCategoryMetadata[0] }, Xml = "<categories href='http://odata.org/href' xmlns='http://www.w3.org/2007/app'/>", ExpectedException = (ExpectedException)null }, // Categories with fixed yes new { CategoriesMetadata = new AtomCategoriesMetadata() { Fixed = true }, Xml = "<categories fixed='yes' xmlns='http://www.w3.org/2007/app'/>", ExpectedException = (ExpectedException)null }, // Categories with fixed no new { CategoriesMetadata = new AtomCategoriesMetadata() { Fixed = false }, Xml = "<categories fixed='no' xmlns='http://www.w3.org/2007/app'/>", ExpectedException = (ExpectedException)null }, // Categories with scheme new { CategoriesMetadata = new AtomCategoriesMetadata() { Scheme = "http://odata.org/scheme" }, Xml = "<categories scheme='http://odata.org/scheme' xmlns='http://www.w3.org/2007/app'/>", ExpectedException = (ExpectedException)null }, // Categories with scheme and fixed new { CategoriesMetadata = new AtomCategoriesMetadata() { Fixed = true, Scheme = "http://odata.org/scheme" }, Xml = "<categories fixed='yes' scheme='http://odata.org/scheme' xmlns='http://www.w3.org/2007/app'/>", ExpectedException = (ExpectedException)null }, // Categories with single category new { CategoriesMetadata = new AtomCategoriesMetadata() { Categories = new [] { new AtomCategoryMetadata { Term = "myterm", Scheme = "http://odata.org/scheme" } } }, Xml = "<categories xmlns='http://www.w3.org/2007/app'><atom:category term='myterm' scheme='http://odata.org/scheme' xmlns:atom='http://www.w3.org/2005/Atom'/></categories>", ExpectedException = (ExpectedException)null }, // Categories with two categories new { CategoriesMetadata = new AtomCategoriesMetadata() { Categories = new [] { new AtomCategoryMetadata { Term = "myterm", Scheme = "http://odata.org/scheme" }, new AtomCategoryMetadata { Term = "second", Scheme = "http://odata.org/scheme2" } } }, Xml = "<categories xmlns='http://www.w3.org/2007/app'>" + "<atom:category term='myterm' scheme='http://odata.org/scheme' xmlns:atom='http://www.w3.org/2005/Atom'/>" + "<atom:category term='second' scheme='http://odata.org/scheme2' xmlns:atom='http://www.w3.org/2005/Atom'/>" + "</categories>", ExpectedException = (ExpectedException)null }, // Categories with href and fixed (error) new { CategoriesMetadata = new AtomCategoriesMetadata() { Href = new Uri("http://odata.org/href"), Fixed = true }, Xml = string.Empty, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_CategoriesHrefWithOtherValues") }, // Categories with href and scheme (error) new { CategoriesMetadata = new AtomCategoriesMetadata() { Href = new Uri("http://odata.org/href"), Scheme = "http://odata.org/scheme" }, Xml = string.Empty, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_CategoriesHrefWithOtherValues") }, // Categories with href and non-empty categories (error) new { CategoriesMetadata = new AtomCategoriesMetadata() { Href = new Uri("http://odata.org/href"), Categories = new [] { new AtomCategoryMetadata() } }, Xml = string.Empty, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_CategoriesHrefWithOtherValues") }, }; var testDescriptors = testCases.Select(testCase => { ODataEntitySetInfo collection = new ODataEntitySetInfo { Url = new Uri("http://odata.org/url") }; AtomResourceCollectionMetadata metadata = new AtomResourceCollectionMetadata() { Categories = testCase.CategoriesMetadata }; collection.SetAnnotation(metadata); ODataServiceDocument serviceDocument = new ODataServiceDocument { EntitySets = new [] { collection } }; return new PayloadWriterTestDescriptor<ODataServiceDocument>( this.Settings, new [] { serviceDocument }, tc => { if (testCase.ExpectedException != null) { return new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testCase.ExpectedException }; } else { return new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = testCase.Xml, FragmentExtractor = result => result .Element(TestAtomConstants.AtomPublishingXNamespace + TestAtomConstants.AtomPublishingWorkspaceElementName) .Element(TestAtomConstants.AtomPublishingXNamespace + TestAtomConstants.AtomPublishingCollectionElementName) .Element(TestAtomConstants.AtomPublishingXNamespace + TestAtomConstants.AtomPublishingCategoriesElementName) }; } }); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.WriterTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyTopLevelContent( testDescriptor, testConfiguration, (messageWriter) => messageWriter.WriteServiceDocument(testDescriptor.PayloadItems.Single()), this.Assert, baselineLogger: this.Logger); }); }
/// <summary> /// Visits an ATOM resource collection metadata. /// </summary> /// <param name="atomResourceCollectionMetadata">The resource collection metadata to visit.</param> protected virtual void VisitAtomResourceCollectionMetadata(AtomResourceCollectionMetadata atomResourceCollectionMetadata) { this.VisitAtomMetadata(atomResourceCollectionMetadata.Title); this.VisitAtomMetadata(atomResourceCollectionMetadata.Categories); }
/// <summary> /// Reads an app:categories element as well as each atom:category element contained within it, and adds the new information to <paramref name="collectionMetadata"/>. /// </summary> /// <param name="collectionMetadata">The non-null collection metadata object to augment.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The start of the app:categories element. /// Post-Condition: Any - The next node after the app:categories element. /// </remarks> internal void ReadCategoriesElementInCollection(AtomResourceCollectionMetadata collectionMetadata) { Debug.Assert(collectionMetadata != null, "collectionMetadata != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.XmlReader.LocalName == AtomConstants.AtomPublishingCategoriesElementName, "Expected element named 'categories'."); Debug.Assert(this.XmlReader.NamespaceURI == AtomConstants.AtomPublishingNamespace, "Element 'categories' should be in the atom publishing namespace."); AtomCategoriesMetadata categoriesMetadata = new AtomCategoriesMetadata(); List<AtomCategoryMetadata> categoryList = new List<AtomCategoryMetadata>(); while (this.XmlReader.MoveToNextAttribute()) { string attributeValue = this.XmlReader.Value; if (this.XmlReader.NamespaceEquals(this.EmptyNamespace)) { if (this.XmlReader.LocalNameEquals(this.AtomHRefAttributeName)) { categoriesMetadata.Href = this.ProcessUriFromPayload(attributeValue, this.XmlReader.XmlBaseUri); } else if (this.XmlReader.LocalNameEquals(this.AtomPublishingFixedAttributeName)) { if (String.CompareOrdinal(attributeValue, AtomConstants.AtomPublishingFixedYesValue) == 0) { categoriesMetadata.Fixed = true; } else if (String.CompareOrdinal(attributeValue, AtomConstants.AtomPublishingFixedNoValue) == 0) { categoriesMetadata.Fixed = false; } else { throw new ODataException(Strings.ODataAtomServiceDocumentMetadataDeserializer_InvalidFixedAttributeValue(attributeValue)); } } else if (this.XmlReader.LocalNameEquals(this.AtomCategorySchemeAttributeName)) { categoriesMetadata.Scheme = attributeValue; } } } this.XmlReader.MoveToElement(); if (!this.XmlReader.IsEmptyElement) { // read over the categories element this.XmlReader.ReadStartElement(); do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.AtomNamespace) && this.XmlReader.LocalNameEquals(this.AtomCategoryElementName)) { categoryList.Add(this.ReadCategoryElementInCollection()); } break; case XmlNodeType.EndElement: // end of 'categories' element. break; default: // ignore all other nodes. this.XmlReader.Skip(); break; } } while (this.XmlReader.NodeType != XmlNodeType.EndElement); } // if (!this.XmlReader.IsEmptyElement) // read over the end tag of the categories element or the start tag if the categories element is empty. this.XmlReader.Read(); categoriesMetadata.Categories = new ReadOnlyEnumerable<AtomCategoryMetadata>(categoryList); collectionMetadata.Categories = categoriesMetadata; }