File: System\ServiceModel\Syndication\AtomPub10ServiceDocumentFormatter.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel.Syndication
{
    using System.Collections.ObjectModel;
    using System.Runtime.Serialization;
    using System.Xml.Serialization;
    using System.Collections.Generic;
    using System.Xml;
    using System.Xml.Schema;
    using System.ServiceModel.Channels;
    using System.Diagnostics;
    using System.ServiceModel.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime.CompilerServices;
 
    internal delegate InlineCategoriesDocument CreateInlineCategoriesDelegate();
    internal delegate ReferencedCategoriesDocument CreateReferencedCategoriesDelegate();
 
    [TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
    [XmlRoot(ElementName = App10Constants.Service, Namespace = App10Constants.Namespace)]
    public class AtomPub10ServiceDocumentFormatter : ServiceDocumentFormatter, IXmlSerializable
    {
        Type documentType;
        int maxExtensionSize;
        bool preserveAttributeExtensions;
        bool preserveElementExtensions;
 
        public AtomPub10ServiceDocumentFormatter()
            : this(typeof(ServiceDocument))
        {
        }
 
        public AtomPub10ServiceDocumentFormatter(Type documentTypeToCreate)
            : base()
        {
            if (documentTypeToCreate == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("documentTypeToCreate");
            }
            if (!typeof(ServiceDocument).IsAssignableFrom(documentTypeToCreate))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("documentTypeToCreate",
                    SR.GetString(SR.InvalidObjectTypePassed, "documentTypeToCreate", "ServiceDocument"));
            }
            this.maxExtensionSize = int.MaxValue;
            this.preserveAttributeExtensions = true;
            this.preserveElementExtensions = true;
            this.documentType = documentTypeToCreate;
        }
 
        public AtomPub10ServiceDocumentFormatter(ServiceDocument documentToWrite)
            : base(documentToWrite)
        {
            // No need to check that the parameter passed is valid - it is checked by the c'tor of the base class
            this.maxExtensionSize = int.MaxValue;
            preserveAttributeExtensions = true;
            preserveElementExtensions = true;
            this.documentType = documentToWrite.GetType();
        }
 
        public override string Version
        {
            get { return App10Constants.Namespace; }
        }
 
        public override bool CanRead(XmlReader reader)
        {
            if (reader == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }
            return reader.IsStartElement(App10Constants.Service, App10Constants.Namespace);
        }
 
        [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")]
        XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }
 
        [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")]
        void IXmlSerializable.ReadXml(XmlReader reader)
        {
            if (reader == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }
            TraceServiceDocumentReadBegin();
            ReadDocument(reader);
            TraceServiceDocumentReadEnd();
        }
 
        [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")]
        void IXmlSerializable.WriteXml(XmlWriter writer)
        {
            if (writer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
            }
            if (this.Document == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DocumentFormatterDoesNotHaveDocument)));
            }
            TraceServiceDocumentWriteBegin();
            WriteDocument(writer);
            TraceServiceDocumentWriteEnd();
        }
 
        public override void ReadFrom(XmlReader reader)
        {
            if (reader == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }
            reader.MoveToContent();
            if (!CanRead(reader))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.UnknownDocumentXml, reader.LocalName, reader.NamespaceURI)));
            }
            TraceServiceDocumentReadBegin();
            ReadDocument(reader);
            TraceServiceDocumentReadEnd();
        }
 
        public override void WriteTo(XmlWriter writer)
        {
            if (writer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
            }
            if (this.Document == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DocumentFormatterDoesNotHaveDocument)));
            }
            TraceServiceDocumentWriteBegin();
            writer.WriteStartElement(App10Constants.Prefix, App10Constants.Service, App10Constants.Namespace);
            WriteDocument(writer);
            writer.WriteEndElement();
            TraceServiceDocumentWriteEnd();
        }
 
        internal static CategoriesDocument ReadCategories(XmlReader reader, Uri baseUri, CreateInlineCategoriesDelegate inlineCategoriesFactory, CreateReferencedCategoriesDelegate referencedCategoriesFactory, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)
        {
            string link = reader.GetAttribute(App10Constants.Href, string.Empty);
            if (string.IsNullOrEmpty(link))
            {
                InlineCategoriesDocument inlineCategories = inlineCategoriesFactory();
                ReadInlineCategories(reader, inlineCategories, baseUri, version, preserveElementExtensions, preserveAttributeExtensions, maxExtensionSize);
                return inlineCategories;
            }
            else
            {
                ReferencedCategoriesDocument referencedCategories = referencedCategoriesFactory();
                ReadReferencedCategories(reader, referencedCategories, baseUri, new Uri(link, UriKind.RelativeOrAbsolute), version, preserveElementExtensions, preserveAttributeExtensions, maxExtensionSize);
                return referencedCategories;
            }
        }
 
        internal static void TraceServiceDocumentReadBegin()
        {
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.SyndicationReadServiceDocumentBegin, SR.GetString(SR.TraceCodeSyndicationReadServiceDocumentBegin));
            }
        }
 
        internal static void TraceServiceDocumentReadEnd()
        {
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.SyndicationReadServiceDocumentEnd, SR.GetString(SR.TraceCodeSyndicationReadServiceDocumentEnd));
            }
        }
 
        internal static void TraceServiceDocumentWriteBegin()
        {
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.SyndicationWriteServiceDocumentBegin, SR.GetString(SR.TraceCodeSyndicationWriteServiceDocumentBegin));
            }
        }
 
        internal static void TraceServiceDocumentWriteEnd()
        {
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.SyndicationWriteServiceDocumentEnd, SR.GetString(SR.TraceCodeSyndicationWriteServiceDocumentEnd));
            }
        }
 
        internal static void WriteCategoriesInnerXml(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version)
        {
            Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, categories.BaseUri);
            if (baseUriToWrite != null)
            {
                WriteXmlBase(writer, baseUriToWrite);
            }
            if (!string.IsNullOrEmpty(categories.Language))
            {
                WriteXmlLang(writer, categories.Language);
            }
            if (categories.IsInline)
            {
                WriteInlineCategoriesContent(writer, (InlineCategoriesDocument)categories, version);
            }
            else
            {
                WriteReferencedCategoriesContent(writer, (ReferencedCategoriesDocument)categories, version);
            }
        }
 
        protected override ServiceDocument CreateDocumentInstance()
        {
            if (this.documentType == typeof(ServiceDocument))
            {
                return new ServiceDocument();
            }
            else
            {
                return (ServiceDocument)Activator.CreateInstance(this.documentType);
            }
        }
 
        static void ReadInlineCategories(XmlReader reader, InlineCategoriesDocument inlineCategories, Uri baseUri, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)
        {
            inlineCategories.BaseUri = baseUri;
            if (reader.HasAttributes)
            {
                while (reader.MoveToNextAttribute())
                {
                    if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
                    {
                        inlineCategories.BaseUri = FeedUtils.CombineXmlBase(inlineCategories.BaseUri, reader.Value);
                    }
                    else if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
                    {
                        inlineCategories.Language = reader.Value;
                    }
                    else if (reader.LocalName == App10Constants.Fixed && reader.NamespaceURI == string.Empty)
                    {
                        inlineCategories.IsFixed = (reader.Value == "yes");
                    }
                    else if (reader.LocalName == Atom10Constants.SchemeTag && reader.NamespaceURI == string.Empty)
                    {
                        inlineCategories.Scheme = reader.Value;
                    }
                    else
                    {
                        string ns = reader.NamespaceURI;
                        string name = reader.LocalName;
                        if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
                        {
                            continue;
                        }
                        string val = reader.Value;
                        if (!TryParseAttribute(name, ns, val, inlineCategories, version))
                        {
                            if (preserveAttributeExtensions)
                            {
                                inlineCategories.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
                            }
                            else
                            {
                                SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                            }
                        }
                    }
                }
            }
            SyndicationFeedFormatter.MoveToStartElement(reader);
            bool isEmptyElement = reader.IsEmptyElement;
            reader.ReadStartElement();
            if (!isEmptyElement)
            {
                XmlBuffer buffer = null;
                XmlDictionaryWriter extWriter = null;
                try
                {
                    while (reader.IsStartElement())
                    {
                        if (reader.IsStartElement(Atom10Constants.CategoryTag, Atom10Constants.Atom10Namespace))
                        {
                            SyndicationCategory category = CreateCategory(inlineCategories);
                            Atom10FeedFormatter.ReadCategory(reader, category, version, preserveAttributeExtensions, preserveElementExtensions, maxExtensionSize);
                            if (category.Scheme == null)
                            {
                                category.Scheme = inlineCategories.Scheme;
                            }
                            inlineCategories.Categories.Add(category);
                        }
                        else if (!TryParseElement(reader, inlineCategories, version))
                        {
                            if (preserveElementExtensions)
                            {
                                SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize);
                            }
                            else
                            {
                                SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                                reader.Skip();
                            }
                        }
                    }
                    LoadElementExtensions(buffer, extWriter, inlineCategories);
                }
                finally
                {
                    if (extWriter != null)
                    {
                        extWriter.Close();
                    }
                }
                reader.ReadEndElement();
            }
        }
 
        static void ReadReferencedCategories(XmlReader reader, ReferencedCategoriesDocument referencedCategories, Uri baseUri, Uri link, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)
        {
            referencedCategories.BaseUri = baseUri;
            referencedCategories.Link = link;
            if (reader.HasAttributes)
            {
                while (reader.MoveToNextAttribute())
                {
                    if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
                    {
                        referencedCategories.BaseUri = FeedUtils.CombineXmlBase(referencedCategories.BaseUri, reader.Value);
                    }
                    else if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
                    {
                        referencedCategories.Language = reader.Value;
                    }
                    else if (reader.LocalName == App10Constants.Href && reader.NamespaceURI == string.Empty)
                    {
                        continue;
                    }
                    else
                    {
                        string ns = reader.NamespaceURI;
                        string name = reader.LocalName;
                        if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
                        {
                            continue;
                        }
                        string val = reader.Value;
                        if (!TryParseAttribute(name, ns, val, referencedCategories, version))
                        {
                            if (preserveAttributeExtensions)
                            {
                                referencedCategories.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
                            }
                            else
                            {
                                SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                            }
                        }
                    }
                }
            }
            reader.MoveToElement();
            bool isEmptyElement = reader.IsEmptyElement;
            reader.ReadStartElement();
            if (!isEmptyElement)
            {
                XmlBuffer buffer = null;
                XmlDictionaryWriter extWriter = null;
                try
                {
                    while (reader.IsStartElement())
                    {
                        if (!TryParseElement(reader, referencedCategories, version))
                        {
                            if (preserveElementExtensions)
                            {
                                SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize);
                            }
                            else
                            {
                                SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                                reader.Skip();
                            }
                        }
                    }
                    LoadElementExtensions(buffer, extWriter, referencedCategories);
                }
                finally
                {
                    if (extWriter != null)
                    {
                        extWriter.Close();
                    }
                }
                reader.ReadEndElement();
            }
        }
 
        static void WriteCategories(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version)
        {
            writer.WriteStartElement(App10Constants.Prefix, App10Constants.Categories, App10Constants.Namespace);
            WriteCategoriesInnerXml(writer, categories, baseUri, version);
            writer.WriteEndElement();
        }
 
        static void WriteInlineCategoriesContent(XmlWriter writer, InlineCategoriesDocument categories, string version)
        {
            if (!string.IsNullOrEmpty(categories.Scheme))
            {
                writer.WriteAttributeString(Atom10Constants.SchemeTag, categories.Scheme);
            }
            // by default, categories are not fixed
            if (categories.IsFixed)
            {
                writer.WriteAttributeString(App10Constants.Fixed, "yes");
            }
            WriteAttributeExtensions(writer, categories, version);
            for (int i = 0; i < categories.Categories.Count; ++i)
            {
                Atom10FeedFormatter.WriteCategory(writer, categories.Categories[i], version);
            }
            WriteElementExtensions(writer, categories, version);
        }
 
        static void WriteReferencedCategoriesContent(XmlWriter writer, ReferencedCategoriesDocument categories, string version)
        {
            if (categories.Link != null)
            {
                writer.WriteAttributeString(App10Constants.Href, FeedUtils.GetUriString(categories.Link));
            }
            WriteAttributeExtensions(writer, categories, version);
            WriteElementExtensions(writer, categories, version);
        }
 
        static void WriteXmlBase(XmlWriter writer, Uri baseUri)
        {
            writer.WriteAttributeString("xml", "base", Atom10FeedFormatter.XmlNs, FeedUtils.GetUriString(baseUri));
        }
 
        static void WriteXmlLang(XmlWriter writer, string lang)
        {
            writer.WriteAttributeString("xml", "lang", Atom10FeedFormatter.XmlNs, lang);
 
        }
 
        ResourceCollectionInfo ReadCollection(XmlReader reader, Workspace workspace)
        {
            ResourceCollectionInfo result = CreateCollection(workspace);
            result.BaseUri = workspace.BaseUri;
            if (reader.HasAttributes)
            {
                while (reader.MoveToNextAttribute())
                {
                    if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
                    {
                        result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value);
                    }
                    else if (reader.LocalName == App10Constants.Href && reader.NamespaceURI == string.Empty)
                    {
                        result.Link = new Uri(reader.Value, UriKind.RelativeOrAbsolute);
                    }
                    else
                    {
                        string ns = reader.NamespaceURI;
                        string name = reader.LocalName;
                        if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
                        {
                            continue;
                        }
                        string val = reader.Value;
                        if (!TryParseAttribute(name, ns, val, result, this.Version))
                        {
                            if (this.preserveAttributeExtensions)
                            {
                                result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
                            }
                            else
                            {
                                SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                            }
                        }
                    }
                }
            }
 
            XmlBuffer buffer = null;
            XmlDictionaryWriter extWriter = null;
 
            reader.ReadStartElement();
            try
            {
                while (reader.IsStartElement())
                {
                    if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace))
                    {
                        result.Title = Atom10FeedFormatter.ReadTextContentFrom(reader, "//app:service/app:workspace/app:collection/atom:title[@type]", this.preserveAttributeExtensions);
                    }
                    else if (reader.IsStartElement(App10Constants.Categories, App10Constants.Namespace))
                    {
                        result.Categories.Add(ReadCategories(reader,
                            result.BaseUri,
                            delegate()
                            {
                                return CreateInlineCategories(result);
                            },
 
                            delegate()
                            {
                                return CreateReferencedCategories(result);
                            },
                            this.Version,
                            this.preserveElementExtensions,
                            this.preserveAttributeExtensions,
                            this.maxExtensionSize));
                    }
                    else if (reader.IsStartElement(App10Constants.Accept, App10Constants.Namespace))
                    {
                        result.Accepts.Add(reader.ReadElementString());
                    }
                    else if (!TryParseElement(reader, result, this.Version))
                    {
                        if (this.preserveElementExtensions)
                        {
                            SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize);
                        }
                        else
                        {
                            SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                            reader.Skip();
                        }
                    }
                }
                LoadElementExtensions(buffer, extWriter, result);
            }
            finally
            {
                if (extWriter != null)
                {
                    extWriter.Close();
                }
            }
            reader.ReadEndElement();
            return result;
        }
 
        void ReadDocument(XmlReader reader)
        {
            ServiceDocument result = CreateDocumentInstance();
            try
            {
                SyndicationFeedFormatter.MoveToStartElement(reader);
                bool elementIsEmpty = reader.IsEmptyElement;
                if (reader.HasAttributes)
                {
                    while (reader.MoveToNextAttribute())
                    {
                        if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
                        {
                            result.Language = reader.Value;
                        }
                        else if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
                        {
                            result.BaseUri = new Uri(reader.Value, UriKind.RelativeOrAbsolute);
                        }
                        else
                        {
                            string ns = reader.NamespaceURI;
                            string name = reader.LocalName;
                            if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
                            {
                                continue;
                            }
                            string val = reader.Value;
                            if (!TryParseAttribute(name, ns, val, result, this.Version))
                            {
                                if (this.preserveAttributeExtensions)
                                {
                                    result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
                                }
                                else
                                {
                                    SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                                }
                            }
                        }
                    }
                }
                XmlBuffer buffer = null;
                XmlDictionaryWriter extWriter = null;
 
                reader.ReadStartElement();
                if (!elementIsEmpty)
                {
                    try
                    {
                        while (reader.IsStartElement())
                        {
                            if (reader.IsStartElement(App10Constants.Workspace, App10Constants.Namespace))
                            {
                                result.Workspaces.Add(ReadWorkspace(reader, result));
                            }
                            else if (!TryParseElement(reader, result, this.Version))
                            {
                                if (this.preserveElementExtensions)
                                {
                                    SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize);
                                }
                                else
                                {
                                    SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                                    reader.Skip();
                                }
                            }
                        }
                        LoadElementExtensions(buffer, extWriter, result);
                    }
                    finally
                    {
                        if (extWriter != null)
                        {
                            extWriter.Close();
                        }
                    }
                }
                reader.ReadEndElement();
            }
            catch (FormatException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDocument), e));
            }
            catch (ArgumentException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDocument), e));
            }
            SetDocument(result);
        }
 
        Workspace ReadWorkspace(XmlReader reader, ServiceDocument document)
        {
            Workspace result = CreateWorkspace(document);
            result.BaseUri = document.BaseUri;
            if (reader.HasAttributes)
            {
                while (reader.MoveToNextAttribute())
                {
                    if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
                    {
                        result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value);
                    }
                    else
                    {
                        string ns = reader.NamespaceURI;
                        string name = reader.LocalName;
                        if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
                        {
                            continue;
                        }
                        string val = reader.Value;
                        if (!TryParseAttribute(name, ns, val, result, this.Version))
                        {
                            if (this.preserveAttributeExtensions)
                            {
                                result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
                            }
                            else
                            {
                                SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                            }
                        }
                    }
                }
            }
 
            XmlBuffer buffer = null;
            XmlDictionaryWriter extWriter = null;
 
            reader.ReadStartElement();
            try
            {
                while (reader.IsStartElement())
                {
                    if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace))
                    {
                        result.Title = Atom10FeedFormatter.ReadTextContentFrom(reader, "//app:service/app:workspace/atom:title[@type]", this.preserveAttributeExtensions);
                    }
                    else if (reader.IsStartElement(App10Constants.Collection, App10Constants.Namespace))
                    {
                        result.Collections.Add(ReadCollection(reader, result));
                    }
                    else if (!TryParseElement(reader, result, this.Version))
                    {
                        if (this.preserveElementExtensions)
                        {
                            SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize);
                        }
                        else
                        {
                            SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
                            reader.Skip();
                        }
                    }
                }
                LoadElementExtensions(buffer, extWriter, result);
            }
            finally
            {
                if (extWriter != null)
                {
                    extWriter.Close();
                }
            }
            reader.ReadEndElement();
            return result;
        }
 
        void WriteCollection(XmlWriter writer, ResourceCollectionInfo collection, Uri baseUri)
        {
            writer.WriteStartElement(App10Constants.Prefix, App10Constants.Collection, App10Constants.Namespace);
            Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, collection.BaseUri);
            if (baseUriToWrite != null)
            {
                baseUri = collection.BaseUri;
                WriteXmlBase(writer, baseUriToWrite);
            }
            if (collection.Link != null)
            {
                writer.WriteAttributeString(App10Constants.Href, FeedUtils.GetUriString(collection.Link));
            }
            WriteAttributeExtensions(writer, collection, this.Version);
            if (collection.Title != null)
            {
                collection.Title.WriteTo(writer, Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace);
            }
            for (int i = 0; i < collection.Accepts.Count; ++i)
            {
                writer.WriteElementString(App10Constants.Prefix, App10Constants.Accept, App10Constants.Namespace, collection.Accepts[i]);
            }
            for (int i = 0; i < collection.Categories.Count; ++i)
            {
                WriteCategories(writer, collection.Categories[i], baseUri, this.Version);
            }
            WriteElementExtensions(writer, collection, this.Version);
            writer.WriteEndElement();
        }
 
        void WriteDocument(XmlWriter writer)
        {
            // declare the atom10 namespace upfront for compactness
            writer.WriteAttributeString(Atom10Constants.Atom10Prefix, Atom10FeedFormatter.XmlNsNs, Atom10Constants.Atom10Namespace);
            if (!string.IsNullOrEmpty(this.Document.Language))
            {
                WriteXmlLang(writer, this.Document.Language);
            }
            Uri baseUri = this.Document.BaseUri;
            if (baseUri != null)
            {
                WriteXmlBase(writer, baseUri);
            }
            WriteAttributeExtensions(writer, this.Document, this.Version);
 
            for (int i = 0; i < this.Document.Workspaces.Count; ++i)
            {
                WriteWorkspace(writer, this.Document.Workspaces[i], baseUri);
            }
            WriteElementExtensions(writer, this.Document, this.Version);
        }
 
        void WriteWorkspace(XmlWriter writer, Workspace workspace, Uri baseUri)
        {
            writer.WriteStartElement(App10Constants.Prefix, App10Constants.Workspace, App10Constants.Namespace);
            Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, workspace.BaseUri);
            if (baseUriToWrite != null)
            {
                baseUri = workspace.BaseUri;
                WriteXmlBase(writer, baseUriToWrite);
            }
            WriteAttributeExtensions(writer, workspace, this.Version);
            if (workspace.Title != null)
            {
                workspace.Title.WriteTo(writer, Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace);
            }
            for (int i = 0; i < workspace.Collections.Count; ++i)
            {
                WriteCollection(writer, workspace.Collections[i], baseUri);
            }
            WriteElementExtensions(writer, workspace, this.Version);
            writer.WriteEndElement();
        }
    }
 
    [TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
    [XmlRoot(ElementName = App10Constants.Service, Namespace = App10Constants.Namespace)]
    public class AtomPub10ServiceDocumentFormatter<TServiceDocument> : AtomPub10ServiceDocumentFormatter
        where TServiceDocument : ServiceDocument, new()
    {
        public AtomPub10ServiceDocumentFormatter() :
            base(typeof(TServiceDocument))
        {
        }
 
        public AtomPub10ServiceDocumentFormatter(TServiceDocument documentToWrite)
            : base(documentToWrite)
        {
        }
 
        protected override ServiceDocument CreateDocumentInstance()
        {
            return new TServiceDocument();
        }
    }
}