1343 lines
56 KiB
C#
1343 lines
56 KiB
C#
|
//------------------------------------------------------------
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//------------------------------------------------------------
|
||
|
|
||
|
namespace System.ServiceModel.Syndication
|
||
|
{
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Collections.ObjectModel;
|
||
|
using System.Globalization;
|
||
|
using System.Text;
|
||
|
using System.Xml;
|
||
|
using System.Xml.Serialization;
|
||
|
using System.Diagnostics.CodeAnalysis;
|
||
|
using System.Xml.Schema;
|
||
|
using System.Collections;
|
||
|
using DiagnosticUtility = System.ServiceModel.DiagnosticUtility;
|
||
|
using System.ServiceModel.Channels;
|
||
|
using System.Runtime.CompilerServices;
|
||
|
|
||
|
[TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
|
||
|
[XmlRoot(ElementName = Atom10Constants.FeedTag, Namespace = Atom10Constants.Atom10Namespace)]
|
||
|
public class Atom10FeedFormatter : SyndicationFeedFormatter, IXmlSerializable
|
||
|
{
|
||
|
internal static readonly TimeSpan zeroOffset = new TimeSpan(0, 0, 0);
|
||
|
internal const string XmlNs = "http://www.w3.org/XML/1998/namespace";
|
||
|
internal const string XmlNsNs = "http://www.w3.org/2000/xmlns/";
|
||
|
static readonly XmlQualifiedName Atom10Href = new XmlQualifiedName(Atom10Constants.HrefTag, string.Empty);
|
||
|
static readonly XmlQualifiedName Atom10Label = new XmlQualifiedName(Atom10Constants.LabelTag, string.Empty);
|
||
|
static readonly XmlQualifiedName Atom10Length = new XmlQualifiedName(Atom10Constants.LengthTag, string.Empty);
|
||
|
static readonly XmlQualifiedName Atom10Relative = new XmlQualifiedName(Atom10Constants.RelativeTag, string.Empty);
|
||
|
static readonly XmlQualifiedName Atom10Scheme = new XmlQualifiedName(Atom10Constants.SchemeTag, string.Empty);
|
||
|
static readonly XmlQualifiedName Atom10Term = new XmlQualifiedName(Atom10Constants.TermTag, string.Empty);
|
||
|
static readonly XmlQualifiedName Atom10Title = new XmlQualifiedName(Atom10Constants.TitleTag, string.Empty);
|
||
|
static readonly XmlQualifiedName Atom10Type = new XmlQualifiedName(Atom10Constants.TypeTag, string.Empty);
|
||
|
static readonly UriGenerator idGenerator = new UriGenerator();
|
||
|
const string Rfc3339LocalDateTimeFormat = "yyyy-MM-ddTHH:mm:sszzz";
|
||
|
const string Rfc3339UTCDateTimeFormat = "yyyy-MM-ddTHH:mm:ssZ";
|
||
|
Type feedType;
|
||
|
int maxExtensionSize;
|
||
|
bool preserveAttributeExtensions;
|
||
|
bool preserveElementExtensions;
|
||
|
|
||
|
public Atom10FeedFormatter()
|
||
|
: this(typeof(SyndicationFeed))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public Atom10FeedFormatter(Type feedTypeToCreate)
|
||
|
: base()
|
||
|
{
|
||
|
if (feedTypeToCreate == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("feedTypeToCreate");
|
||
|
}
|
||
|
if (!typeof(SyndicationFeed).IsAssignableFrom(feedTypeToCreate))
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("feedTypeToCreate",
|
||
|
SR.GetString(SR.InvalidObjectTypePassed, "feedTypeToCreate", "SyndicationFeed"));
|
||
|
}
|
||
|
this.maxExtensionSize = int.MaxValue;
|
||
|
this.preserveAttributeExtensions = this.preserveElementExtensions = true;
|
||
|
this.feedType = feedTypeToCreate;
|
||
|
}
|
||
|
|
||
|
public Atom10FeedFormatter(SyndicationFeed feedToWrite)
|
||
|
: base(feedToWrite)
|
||
|
{
|
||
|
// 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 = preserveElementExtensions = true;
|
||
|
this.feedType = feedToWrite.GetType();
|
||
|
}
|
||
|
|
||
|
public bool PreserveAttributeExtensions
|
||
|
{
|
||
|
get { return this.preserveAttributeExtensions; }
|
||
|
set { this.preserveAttributeExtensions = value; }
|
||
|
}
|
||
|
|
||
|
public bool PreserveElementExtensions
|
||
|
{
|
||
|
get { return this.preserveElementExtensions; }
|
||
|
set { this.preserveElementExtensions = value; }
|
||
|
}
|
||
|
|
||
|
public override string Version
|
||
|
{
|
||
|
get { return SyndicationVersions.Atom10; }
|
||
|
}
|
||
|
|
||
|
protected Type FeedType
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this.feedType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool CanRead(XmlReader reader)
|
||
|
{
|
||
|
if (reader == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
|
||
|
}
|
||
|
return reader.IsStartElement(Atom10Constants.FeedTag, Atom10Constants.Atom10Namespace);
|
||
|
}
|
||
|
|
||
|
[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");
|
||
|
}
|
||
|
TraceFeedReadBegin();
|
||
|
ReadFeed(reader);
|
||
|
TraceFeedReadEnd();
|
||
|
}
|
||
|
|
||
|
[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");
|
||
|
}
|
||
|
TraceFeedWriteBegin();
|
||
|
WriteFeed(writer);
|
||
|
TraceFeedWriteEnd();
|
||
|
}
|
||
|
|
||
|
public override void ReadFrom(XmlReader reader)
|
||
|
{
|
||
|
TraceFeedReadBegin();
|
||
|
if (!CanRead(reader))
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.UnknownFeedXml, reader.LocalName, reader.NamespaceURI)));
|
||
|
}
|
||
|
ReadFeed(reader);
|
||
|
TraceFeedReadEnd();
|
||
|
}
|
||
|
|
||
|
public override void WriteTo(XmlWriter writer)
|
||
|
{
|
||
|
if (writer == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
|
||
|
}
|
||
|
TraceFeedWriteBegin();
|
||
|
writer.WriteStartElement(Atom10Constants.FeedTag, Atom10Constants.Atom10Namespace);
|
||
|
WriteFeed(writer);
|
||
|
writer.WriteEndElement();
|
||
|
TraceFeedWriteEnd();
|
||
|
}
|
||
|
|
||
|
internal static void ReadCategory(XmlReader reader, SyndicationCategory category, string version, bool preserveAttributeExtensions, bool preserveElementExtensions, int maxExtensionSize)
|
||
|
{
|
||
|
MoveToStartElement(reader);
|
||
|
bool isEmpty = reader.IsEmptyElement;
|
||
|
if (reader.HasAttributes)
|
||
|
{
|
||
|
while (reader.MoveToNextAttribute())
|
||
|
{
|
||
|
if (reader.LocalName == Atom10Constants.TermTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
category.Name = reader.Value;
|
||
|
}
|
||
|
else if (reader.LocalName == Atom10Constants.SchemeTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
category.Scheme = reader.Value;
|
||
|
}
|
||
|
else if (reader.LocalName == Atom10Constants.LabelTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
category.Label = reader.Value;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
string ns = reader.NamespaceURI;
|
||
|
string name = reader.LocalName;
|
||
|
if (FeedUtils.IsXmlns(name, ns))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
string val = reader.Value;
|
||
|
if (!TryParseAttribute(name, ns, val, category, version))
|
||
|
|
||
|
{
|
||
|
if (preserveAttributeExtensions)
|
||
|
{
|
||
|
category.AttributeExtensions.Add(new XmlQualifiedName(name, ns), val);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!isEmpty)
|
||
|
{
|
||
|
reader.ReadStartElement();
|
||
|
XmlBuffer buffer = null;
|
||
|
XmlDictionaryWriter extWriter = null;
|
||
|
try
|
||
|
{
|
||
|
while (reader.IsStartElement())
|
||
|
{
|
||
|
if (TryParseElement(reader, category, version))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
else if (!preserveElementExtensions)
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
reader.Skip();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize);
|
||
|
}
|
||
|
}
|
||
|
LoadElementExtensions(buffer, extWriter, category);
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if (extWriter != null)
|
||
|
{
|
||
|
((IDisposable) extWriter).Dispose();
|
||
|
}
|
||
|
}
|
||
|
reader.ReadEndElement();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
reader.ReadStartElement();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static TextSyndicationContent ReadTextContentFrom(XmlReader reader, string context, bool preserveAttributeExtensions)
|
||
|
{
|
||
|
string type = reader.GetAttribute(Atom10Constants.TypeTag);
|
||
|
return ReadTextContentFromHelper(reader, type, context, preserveAttributeExtensions);
|
||
|
}
|
||
|
|
||
|
internal static void WriteCategory(XmlWriter writer, SyndicationCategory category, string version)
|
||
|
{
|
||
|
writer.WriteStartElement(Atom10Constants.CategoryTag, Atom10Constants.Atom10Namespace);
|
||
|
WriteAttributeExtensions(writer, category, version);
|
||
|
string categoryName = category.Name ?? string.Empty;
|
||
|
if (!category.AttributeExtensions.ContainsKey(Atom10Term))
|
||
|
{
|
||
|
writer.WriteAttributeString(Atom10Constants.TermTag, categoryName);
|
||
|
}
|
||
|
if (!string.IsNullOrEmpty(category.Label) && !category.AttributeExtensions.ContainsKey(Atom10Label))
|
||
|
{
|
||
|
writer.WriteAttributeString(Atom10Constants.LabelTag, category.Label);
|
||
|
}
|
||
|
if (!string.IsNullOrEmpty(category.Scheme) && !category.AttributeExtensions.ContainsKey(Atom10Scheme))
|
||
|
{
|
||
|
writer.WriteAttributeString(Atom10Constants.SchemeTag, category.Scheme);
|
||
|
}
|
||
|
WriteElementExtensions(writer, category, version);
|
||
|
writer.WriteEndElement();
|
||
|
}
|
||
|
|
||
|
internal void ReadItemFrom(XmlReader reader, SyndicationItem result)
|
||
|
{
|
||
|
ReadItemFrom(reader, result, null);
|
||
|
}
|
||
|
|
||
|
internal bool TryParseFeedElementFrom(XmlReader reader, SyndicationFeed result)
|
||
|
{
|
||
|
if (reader.IsStartElement(Atom10Constants.AuthorTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Authors.Add(ReadPersonFrom(reader, result));
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.CategoryTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Categories.Add(ReadCategoryFrom(reader, result));
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.ContributorTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Contributors.Add(ReadPersonFrom(reader, result));
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.GeneratorTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Generator = reader.ReadElementString();
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.IdTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Id = reader.ReadElementString();
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.LinkTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Links.Add(ReadLinkFrom(reader, result));
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.LogoTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.ImageUrl = new Uri(reader.ReadElementString(), UriKind.RelativeOrAbsolute);
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.RightsTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Copyright = ReadTextContentFrom(reader, "//atom:feed/atom:rights[@type]");
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.SubtitleTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Description = ReadTextContentFrom(reader, "//atom:feed/atom:subtitle[@type]");
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Title = ReadTextContentFrom(reader, "//atom:feed/atom:title[@type]");
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.UpdatedTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
reader.ReadStartElement();
|
||
|
result.LastUpdatedTime = DateFromString(reader.ReadString(), reader);
|
||
|
reader.ReadEndElement();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
internal bool TryParseItemElementFrom(XmlReader reader, SyndicationItem result)
|
||
|
{
|
||
|
if (reader.IsStartElement(Atom10Constants.AuthorTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Authors.Add(ReadPersonFrom(reader, result));
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.CategoryTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Categories.Add(ReadCategoryFrom(reader, result));
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.ContentTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Content = ReadContentFrom(reader, result);
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.ContributorTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Contributors.Add(ReadPersonFrom(reader, result));
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.IdTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Id = reader.ReadElementString();
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.LinkTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Links.Add(ReadLinkFrom(reader, result));
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.PublishedTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
reader.ReadStartElement();
|
||
|
result.PublishDate = DateFromString(reader.ReadString(), reader);
|
||
|
reader.ReadEndElement();
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.RightsTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Copyright = ReadTextContentFrom(reader, "//atom:feed/atom:entry/atom:rights[@type]");
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.SourceFeedTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
reader.ReadStartElement();
|
||
|
result.SourceFeed = ReadFeedFrom(reader, new SyndicationFeed(), true); // isSourceFeed
|
||
|
reader.ReadEndElement();
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.SummaryTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Summary = ReadTextContentFrom(reader, "//atom:feed/atom:entry/atom:summary[@type]");
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Title = ReadTextContentFrom(reader, "//atom:feed/atom:entry/atom:title[@type]");
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.UpdatedTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
reader.ReadStartElement();
|
||
|
result.LastUpdatedTime = DateFromString(reader.ReadString(), reader);
|
||
|
reader.ReadEndElement();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
internal void WriteContentTo(XmlWriter writer, string elementName, SyndicationContent content)
|
||
|
{
|
||
|
if (content != null)
|
||
|
{
|
||
|
content.WriteTo(writer, elementName, Atom10Constants.Atom10Namespace);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void WriteElement(XmlWriter writer, string elementName, string value)
|
||
|
{
|
||
|
if (value != null)
|
||
|
{
|
||
|
writer.WriteElementString(elementName, Atom10Constants.Atom10Namespace, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void WriteFeedAuthorsTo(XmlWriter writer, Collection<SyndicationPerson> authors)
|
||
|
{
|
||
|
for (int i = 0; i < authors.Count; ++i)
|
||
|
{
|
||
|
SyndicationPerson p = authors[i];
|
||
|
WritePersonTo(writer, p, Atom10Constants.AuthorTag);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void WriteFeedContributorsTo(XmlWriter writer, Collection<SyndicationPerson> contributors)
|
||
|
{
|
||
|
for (int i = 0; i < contributors.Count; ++i)
|
||
|
{
|
||
|
SyndicationPerson p = contributors[i];
|
||
|
WritePersonTo(writer, p, Atom10Constants.ContributorTag);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void WriteFeedLastUpdatedTimeTo(XmlWriter writer, DateTimeOffset lastUpdatedTime, bool isRequired)
|
||
|
{
|
||
|
if (lastUpdatedTime == DateTimeOffset.MinValue && isRequired)
|
||
|
{
|
||
|
lastUpdatedTime = DateTimeOffset.UtcNow;
|
||
|
}
|
||
|
if (lastUpdatedTime != DateTimeOffset.MinValue)
|
||
|
{
|
||
|
WriteElement(writer, Atom10Constants.UpdatedTag, AsString(lastUpdatedTime));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void WriteItemAuthorsTo(XmlWriter writer, Collection<SyndicationPerson> authors)
|
||
|
{
|
||
|
for (int i = 0; i < authors.Count; ++i)
|
||
|
{
|
||
|
SyndicationPerson p = authors[i];
|
||
|
WritePersonTo(writer, p, Atom10Constants.AuthorTag);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void WriteItemContents(XmlWriter dictWriter, SyndicationItem item)
|
||
|
{
|
||
|
WriteItemContents(dictWriter, item, null);
|
||
|
}
|
||
|
|
||
|
internal void WriteItemContributorsTo(XmlWriter writer, Collection<SyndicationPerson> contributors)
|
||
|
{
|
||
|
for (int i = 0; i < contributors.Count; ++i)
|
||
|
{
|
||
|
SyndicationPerson p = contributors[i];
|
||
|
WritePersonTo(writer, p, Atom10Constants.ContributorTag);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void WriteItemLastUpdatedTimeTo(XmlWriter writer, DateTimeOffset lastUpdatedTime)
|
||
|
{
|
||
|
if (lastUpdatedTime == DateTimeOffset.MinValue)
|
||
|
{
|
||
|
lastUpdatedTime = DateTimeOffset.UtcNow;
|
||
|
}
|
||
|
writer.WriteElementString(Atom10Constants.UpdatedTag,
|
||
|
Atom10Constants.Atom10Namespace,
|
||
|
AsString(lastUpdatedTime));
|
||
|
}
|
||
|
|
||
|
internal void WriteLink(XmlWriter writer, SyndicationLink link, Uri baseUri)
|
||
|
{
|
||
|
writer.WriteStartElement(Atom10Constants.LinkTag, Atom10Constants.Atom10Namespace);
|
||
|
Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, link.BaseUri);
|
||
|
if (baseUriToWrite != null)
|
||
|
{
|
||
|
writer.WriteAttributeString("xml", "base", XmlNs, FeedUtils.GetUriString(baseUriToWrite));
|
||
|
}
|
||
|
link.WriteAttributeExtensions(writer, SyndicationVersions.Atom10);
|
||
|
if (!string.IsNullOrEmpty(link.RelationshipType) && !link.AttributeExtensions.ContainsKey(Atom10Relative))
|
||
|
{
|
||
|
writer.WriteAttributeString(Atom10Constants.RelativeTag, link.RelationshipType);
|
||
|
}
|
||
|
if (!string.IsNullOrEmpty(link.MediaType) && !link.AttributeExtensions.ContainsKey(Atom10Type))
|
||
|
{
|
||
|
writer.WriteAttributeString(Atom10Constants.TypeTag, link.MediaType);
|
||
|
}
|
||
|
if (!string.IsNullOrEmpty(link.Title) && !link.AttributeExtensions.ContainsKey(Atom10Title))
|
||
|
{
|
||
|
writer.WriteAttributeString(Atom10Constants.TitleTag, link.Title);
|
||
|
}
|
||
|
if (link.Length != 0 && !link.AttributeExtensions.ContainsKey(Atom10Length))
|
||
|
{
|
||
|
writer.WriteAttributeString(Atom10Constants.LengthTag, Convert.ToString(link.Length, CultureInfo.InvariantCulture));
|
||
|
}
|
||
|
if (!link.AttributeExtensions.ContainsKey(Atom10Href))
|
||
|
{
|
||
|
writer.WriteAttributeString(Atom10Constants.HrefTag, FeedUtils.GetUriString(link.Uri));
|
||
|
}
|
||
|
link.WriteElementExtensions(writer, SyndicationVersions.Atom10);
|
||
|
writer.WriteEndElement();
|
||
|
}
|
||
|
|
||
|
protected override SyndicationFeed CreateFeedInstance()
|
||
|
{
|
||
|
return SyndicationFeedFormatter.CreateFeedInstance(this.feedType);
|
||
|
}
|
||
|
|
||
|
protected virtual SyndicationItem ReadItem(XmlReader reader, SyndicationFeed feed)
|
||
|
{
|
||
|
if (feed == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("feed");
|
||
|
}
|
||
|
if (reader == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
|
||
|
}
|
||
|
SyndicationItem item = CreateItem(feed);
|
||
|
TraceItemReadBegin();
|
||
|
ReadItemFrom(reader, item, feed.BaseUri);
|
||
|
TraceItemReadEnd();
|
||
|
return item;
|
||
|
}
|
||
|
|
||
|
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "The out parameter is needed to enable implementations that read in items from the stream on demand")]
|
||
|
protected virtual IEnumerable<SyndicationItem> ReadItems(XmlReader reader, SyndicationFeed feed, out bool areAllItemsRead)
|
||
|
{
|
||
|
if (feed == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("feed");
|
||
|
}
|
||
|
if (reader == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
|
||
|
}
|
||
|
NullNotAllowedCollection<SyndicationItem> items = new NullNotAllowedCollection<SyndicationItem>();
|
||
|
while (reader.IsStartElement(Atom10Constants.EntryTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
items.Add(ReadItem(reader, feed));
|
||
|
}
|
||
|
areAllItemsRead = true;
|
||
|
return items;
|
||
|
}
|
||
|
|
||
|
protected virtual void WriteItem(XmlWriter writer, SyndicationItem item, Uri feedBaseUri)
|
||
|
{
|
||
|
TraceItemWriteBegin();
|
||
|
writer.WriteStartElement(Atom10Constants.EntryTag, Atom10Constants.Atom10Namespace);
|
||
|
WriteItemContents(writer, item, feedBaseUri);
|
||
|
writer.WriteEndElement();
|
||
|
TraceItemWriteEnd();
|
||
|
}
|
||
|
|
||
|
protected virtual void WriteItems(XmlWriter writer, IEnumerable<SyndicationItem> items, Uri feedBaseUri)
|
||
|
{
|
||
|
if (items == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
foreach (SyndicationItem item in items)
|
||
|
{
|
||
|
this.WriteItem(writer, item, feedBaseUri);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static TextSyndicationContent ReadTextContentFromHelper(XmlReader reader, string type, string context, bool preserveAttributeExtensions)
|
||
|
{
|
||
|
if (string.IsNullOrEmpty(type))
|
||
|
{
|
||
|
type = Atom10Constants.PlaintextType;
|
||
|
}
|
||
|
|
||
|
TextSyndicationContentKind kind;
|
||
|
switch (type)
|
||
|
{
|
||
|
case Atom10Constants.PlaintextType:
|
||
|
kind = TextSyndicationContentKind.Plaintext;
|
||
|
break;
|
||
|
case Atom10Constants.HtmlType:
|
||
|
kind = TextSyndicationContentKind.Html;
|
||
|
break;
|
||
|
case Atom10Constants.XHtmlType:
|
||
|
kind = TextSyndicationContentKind.XHtml;
|
||
|
break;
|
||
|
default:
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.GetString(SR.Atom10SpecRequiresTextConstruct, context, type))));
|
||
|
}
|
||
|
|
||
|
Dictionary<XmlQualifiedName, string> attrs = null;
|
||
|
if (reader.HasAttributes)
|
||
|
{
|
||
|
while (reader.MoveToNextAttribute())
|
||
|
{
|
||
|
if (reader.LocalName == Atom10Constants.TypeTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
string ns = reader.NamespaceURI;
|
||
|
string name = reader.LocalName;
|
||
|
if (FeedUtils.IsXmlns(name, ns))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
if (preserveAttributeExtensions)
|
||
|
{
|
||
|
string value = reader.Value;
|
||
|
if (attrs == null)
|
||
|
{
|
||
|
attrs = new Dictionary<XmlQualifiedName, string>();
|
||
|
}
|
||
|
attrs.Add(new XmlQualifiedName(name, ns), value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
reader.MoveToElement();
|
||
|
string val = (kind == TextSyndicationContentKind.XHtml) ? reader.ReadInnerXml() : reader.ReadElementString();
|
||
|
TextSyndicationContent result = new TextSyndicationContent(val, kind);
|
||
|
if (attrs != null)
|
||
|
{
|
||
|
foreach (XmlQualifiedName attr in attrs.Keys)
|
||
|
{
|
||
|
if (!FeedUtils.IsXmlns(attr.Name, attr.Namespace))
|
||
|
{
|
||
|
result.AttributeExtensions.Add(attr, attrs[attr]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
string AsString(DateTimeOffset dateTime)
|
||
|
{
|
||
|
if (dateTime.Offset == zeroOffset)
|
||
|
{
|
||
|
return dateTime.ToUniversalTime().ToString(Rfc3339UTCDateTimeFormat, CultureInfo.InvariantCulture);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return dateTime.ToString(Rfc3339LocalDateTimeFormat, CultureInfo.InvariantCulture);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DateTimeOffset DateFromString(string dateTimeString, XmlReader reader)
|
||
|
{
|
||
|
dateTimeString = dateTimeString.Trim();
|
||
|
if (dateTimeString.Length < 20)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
||
|
new XmlException(FeedUtils.AddLineInfo(reader,
|
||
|
SR.ErrorParsingDateTime)));
|
||
|
}
|
||
|
if (dateTimeString[19] == '.')
|
||
|
{
|
||
|
// remove any fractional seconds, we choose to ignore them
|
||
|
int i = 20;
|
||
|
while (dateTimeString.Length > i && char.IsDigit(dateTimeString[i]))
|
||
|
{
|
||
|
++i;
|
||
|
}
|
||
|
dateTimeString = dateTimeString.Substring(0, 19) + dateTimeString.Substring(i);
|
||
|
}
|
||
|
DateTimeOffset localTime;
|
||
|
if (DateTimeOffset.TryParseExact(dateTimeString, Rfc3339LocalDateTimeFormat,
|
||
|
CultureInfo.InvariantCulture.DateTimeFormat,
|
||
|
DateTimeStyles.None, out localTime))
|
||
|
{
|
||
|
return localTime;
|
||
|
}
|
||
|
DateTimeOffset utcTime;
|
||
|
if (DateTimeOffset.TryParseExact(dateTimeString, Rfc3339UTCDateTimeFormat,
|
||
|
CultureInfo.InvariantCulture.DateTimeFormat,
|
||
|
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out utcTime))
|
||
|
{
|
||
|
return utcTime;
|
||
|
}
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
||
|
new XmlException(FeedUtils.AddLineInfo(reader,
|
||
|
SR.ErrorParsingDateTime)));
|
||
|
}
|
||
|
|
||
|
void ReadCategory(XmlReader reader, SyndicationCategory category)
|
||
|
{
|
||
|
ReadCategory(reader, category, this.Version, this.PreserveAttributeExtensions, this.PreserveElementExtensions, this.maxExtensionSize);
|
||
|
}
|
||
|
|
||
|
SyndicationCategory ReadCategoryFrom(XmlReader reader, SyndicationFeed feed)
|
||
|
{
|
||
|
SyndicationCategory result = CreateCategory(feed);
|
||
|
ReadCategory(reader, result);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
SyndicationCategory ReadCategoryFrom(XmlReader reader, SyndicationItem item)
|
||
|
{
|
||
|
SyndicationCategory result = CreateCategory(item);
|
||
|
ReadCategory(reader, result);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
SyndicationContent ReadContentFrom(XmlReader reader, SyndicationItem item)
|
||
|
{
|
||
|
MoveToStartElement(reader);
|
||
|
string type = reader.GetAttribute(Atom10Constants.TypeTag, string.Empty);
|
||
|
|
||
|
SyndicationContent result;
|
||
|
if (TryParseContent(reader, item, type, this.Version, out result))
|
||
|
{
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
if (string.IsNullOrEmpty(type))
|
||
|
{
|
||
|
type = Atom10Constants.PlaintextType;
|
||
|
}
|
||
|
string src = reader.GetAttribute(Atom10Constants.SourceTag, string.Empty);
|
||
|
|
||
|
if (string.IsNullOrEmpty(src) && type != Atom10Constants.PlaintextType && type != Atom10Constants.HtmlType && type != Atom10Constants.XHtmlType)
|
||
|
{
|
||
|
return new XmlSyndicationContent(reader);
|
||
|
}
|
||
|
|
||
|
if (!string.IsNullOrEmpty(src))
|
||
|
{
|
||
|
result = new UrlSyndicationContent(new Uri(src, UriKind.RelativeOrAbsolute), type);
|
||
|
bool isEmpty = reader.IsEmptyElement;
|
||
|
if (reader.HasAttributes)
|
||
|
{
|
||
|
while (reader.MoveToNextAttribute())
|
||
|
{
|
||
|
if (reader.LocalName == Atom10Constants.TypeTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
else if (reader.LocalName == Atom10Constants.SourceTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
else if (!FeedUtils.IsXmlns(reader.LocalName, reader.NamespaceURI))
|
||
|
{
|
||
|
if (this.preserveAttributeExtensions)
|
||
|
{
|
||
|
result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
reader.ReadStartElement();
|
||
|
if (!isEmpty)
|
||
|
{
|
||
|
reader.ReadEndElement();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return ReadTextContentFromHelper(reader, type, "//atom:feed/atom:entry/atom:content[@type]", this.preserveAttributeExtensions);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ReadFeed(XmlReader reader)
|
||
|
{
|
||
|
SetFeed(CreateFeedInstance());
|
||
|
ReadFeedFrom(reader, this.Feed, false);
|
||
|
}
|
||
|
|
||
|
SyndicationFeed ReadFeedFrom(XmlReader reader, SyndicationFeed result, bool isSourceFeed)
|
||
|
{
|
||
|
reader.MoveToContent();
|
||
|
try
|
||
|
{
|
||
|
bool elementIsEmpty = false;
|
||
|
if (!isSourceFeed)
|
||
|
{
|
||
|
MoveToStartElement(reader);
|
||
|
elementIsEmpty = reader.IsEmptyElement;
|
||
|
if (reader.HasAttributes)
|
||
|
{
|
||
|
while (reader.MoveToNextAttribute())
|
||
|
{
|
||
|
if (reader.LocalName == "lang" && reader.NamespaceURI == XmlNs)
|
||
|
{
|
||
|
result.Language = reader.Value;
|
||
|
}
|
||
|
else if (reader.LocalName == "base" && reader.NamespaceURI == 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
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
reader.ReadStartElement();
|
||
|
}
|
||
|
|
||
|
XmlBuffer buffer = null;
|
||
|
XmlDictionaryWriter extWriter = null;
|
||
|
bool areAllItemsRead = true;
|
||
|
bool readItemsAtLeastOnce = false;
|
||
|
|
||
|
if (!elementIsEmpty)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
while (reader.IsStartElement())
|
||
|
{
|
||
|
if (TryParseFeedElementFrom(reader, result))
|
||
|
{
|
||
|
// nothing, we parsed something, great
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.EntryTag, Atom10Constants.Atom10Namespace) && !isSourceFeed)
|
||
|
{
|
||
|
if (readItemsAtLeastOnce)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.FeedHasNonContiguousItems, this.GetType().ToString())));
|
||
|
}
|
||
|
result.Items = ReadItems(reader, result, out areAllItemsRead);
|
||
|
readItemsAtLeastOnce = true;
|
||
|
// if the derived class is reading the items lazily, then stop reading from the stream
|
||
|
if (!areAllItemsRead)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!TryParseElement(reader, result, this.Version))
|
||
|
{
|
||
|
if (this.preserveElementExtensions)
|
||
|
{
|
||
|
CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
reader.Skip();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
LoadElementExtensions(buffer, extWriter, result);
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if (extWriter != null)
|
||
|
{
|
||
|
((IDisposable)extWriter).Dispose();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!isSourceFeed && areAllItemsRead)
|
||
|
{
|
||
|
reader.ReadEndElement(); // feed
|
||
|
}
|
||
|
}
|
||
|
catch (FormatException e)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingFeed), e));
|
||
|
}
|
||
|
catch (ArgumentException e)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingFeed), e));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void ReadItemFrom(XmlReader reader, SyndicationItem result, Uri feedBaseUri)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
result.BaseUri = feedBaseUri;
|
||
|
MoveToStartElement(reader);
|
||
|
bool isEmpty = reader.IsEmptyElement;
|
||
|
if (reader.HasAttributes)
|
||
|
{
|
||
|
while (reader.MoveToNextAttribute())
|
||
|
{
|
||
|
string ns = reader.NamespaceURI;
|
||
|
string name = reader.LocalName;
|
||
|
if (name == "base" && ns == XmlNs)
|
||
|
{
|
||
|
result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value);
|
||
|
continue;
|
||
|
}
|
||
|
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
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
reader.ReadStartElement();
|
||
|
if (!isEmpty)
|
||
|
{
|
||
|
XmlBuffer buffer = null;
|
||
|
XmlDictionaryWriter extWriter = null;
|
||
|
try
|
||
|
{
|
||
|
while (reader.IsStartElement())
|
||
|
{
|
||
|
if (TryParseItemElementFrom(reader, result))
|
||
|
{
|
||
|
// nothing, we parsed something, great
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!TryParseElement(reader, result, this.Version))
|
||
|
{
|
||
|
if (this.preserveElementExtensions)
|
||
|
{
|
||
|
CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
reader.Skip();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
LoadElementExtensions(buffer, extWriter, result);
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if (extWriter != null)
|
||
|
{
|
||
|
((IDisposable) extWriter).Dispose();
|
||
|
}
|
||
|
}
|
||
|
reader.ReadEndElement(); // item
|
||
|
}
|
||
|
}
|
||
|
catch (FormatException e)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingItem), e));
|
||
|
}
|
||
|
catch (ArgumentException e)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingItem), e));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ReadLink(XmlReader reader, SyndicationLink link, Uri baseUri)
|
||
|
{
|
||
|
bool isEmpty = reader.IsEmptyElement;
|
||
|
string mediaType = null;
|
||
|
string relationship = null;
|
||
|
string title = null;
|
||
|
string lengthStr = null;
|
||
|
string val = null;
|
||
|
link.BaseUri = baseUri;
|
||
|
if (reader.HasAttributes)
|
||
|
{
|
||
|
while (reader.MoveToNextAttribute())
|
||
|
{
|
||
|
if (reader.LocalName == "base" && reader.NamespaceURI == XmlNs)
|
||
|
{
|
||
|
link.BaseUri = FeedUtils.CombineXmlBase(link.BaseUri, reader.Value);
|
||
|
}
|
||
|
else if (reader.LocalName == Atom10Constants.TypeTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
mediaType = reader.Value;
|
||
|
}
|
||
|
else if (reader.LocalName == Atom10Constants.RelativeTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
relationship = reader.Value;
|
||
|
}
|
||
|
else if (reader.LocalName == Atom10Constants.TitleTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
title = reader.Value;
|
||
|
}
|
||
|
else if (reader.LocalName == Atom10Constants.LengthTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
lengthStr = reader.Value;
|
||
|
}
|
||
|
else if (reader.LocalName == Atom10Constants.HrefTag && reader.NamespaceURI == string.Empty)
|
||
|
{
|
||
|
val = reader.Value;
|
||
|
}
|
||
|
else if (!FeedUtils.IsXmlns(reader.LocalName, reader.NamespaceURI))
|
||
|
{
|
||
|
if (this.preserveAttributeExtensions)
|
||
|
{
|
||
|
link.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long length = 0;
|
||
|
if (!string.IsNullOrEmpty(lengthStr))
|
||
|
{
|
||
|
length = Convert.ToInt64(lengthStr, CultureInfo.InvariantCulture.NumberFormat);
|
||
|
}
|
||
|
reader.ReadStartElement();
|
||
|
if (!isEmpty)
|
||
|
{
|
||
|
XmlBuffer buffer = null;
|
||
|
XmlDictionaryWriter extWriter = null;
|
||
|
try
|
||
|
{
|
||
|
while (reader.IsStartElement())
|
||
|
{
|
||
|
if (TryParseElement(reader, link, this.Version))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
else if (!this.preserveElementExtensions)
|
||
|
{
|
||
|
SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
reader.Skip();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize);
|
||
|
}
|
||
|
}
|
||
|
LoadElementExtensions(buffer, extWriter, link);
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if (extWriter != null)
|
||
|
{
|
||
|
((IDisposable) extWriter).Dispose();
|
||
|
}
|
||
|
}
|
||
|
reader.ReadEndElement();
|
||
|
}
|
||
|
link.Length = length;
|
||
|
link.MediaType = mediaType;
|
||
|
link.RelationshipType = relationship;
|
||
|
link.Title = title;
|
||
|
link.Uri = (val != null) ? new Uri(val, UriKind.RelativeOrAbsolute) : null;
|
||
|
}
|
||
|
|
||
|
SyndicationLink ReadLinkFrom(XmlReader reader, SyndicationFeed feed)
|
||
|
{
|
||
|
SyndicationLink result = CreateLink(feed);
|
||
|
ReadLink(reader, result, feed.BaseUri);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
SyndicationLink ReadLinkFrom(XmlReader reader, SyndicationItem item)
|
||
|
{
|
||
|
SyndicationLink result = CreateLink(item);
|
||
|
ReadLink(reader, result, item.BaseUri);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
SyndicationPerson ReadPersonFrom(XmlReader reader, SyndicationFeed feed)
|
||
|
{
|
||
|
SyndicationPerson result = CreatePerson(feed);
|
||
|
ReadPersonFrom(reader, result);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
SyndicationPerson ReadPersonFrom(XmlReader reader, SyndicationItem item)
|
||
|
{
|
||
|
SyndicationPerson result = CreatePerson(item);
|
||
|
ReadPersonFrom(reader, result);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void ReadPersonFrom(XmlReader reader, SyndicationPerson result)
|
||
|
{
|
||
|
bool isEmpty = reader.IsEmptyElement;
|
||
|
if (reader.HasAttributes)
|
||
|
{
|
||
|
while (reader.MoveToNextAttribute())
|
||
|
{
|
||
|
string ns = reader.NamespaceURI;
|
||
|
string name = reader.LocalName;
|
||
|
if (FeedUtils.IsXmlns(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
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
reader.ReadStartElement();
|
||
|
if (!isEmpty)
|
||
|
{
|
||
|
XmlBuffer buffer = null;
|
||
|
XmlDictionaryWriter extWriter = null;
|
||
|
try
|
||
|
{
|
||
|
while (reader.IsStartElement())
|
||
|
{
|
||
|
if (reader.IsStartElement(Atom10Constants.NameTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Name = reader.ReadElementString();
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.UriTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Uri = reader.ReadElementString();
|
||
|
}
|
||
|
else if (reader.IsStartElement(Atom10Constants.EmailTag, Atom10Constants.Atom10Namespace))
|
||
|
{
|
||
|
result.Email = reader.ReadElementString();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!TryParseElement(reader, result, this.Version))
|
||
|
{
|
||
|
if (this.preserveElementExtensions)
|
||
|
{
|
||
|
CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceSyndicationElementIgnoredOnRead(reader);
|
||
|
reader.Skip();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
LoadElementExtensions(buffer, extWriter, result);
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if (extWriter != null)
|
||
|
{
|
||
|
((IDisposable) extWriter).Dispose();
|
||
|
}
|
||
|
}
|
||
|
reader.ReadEndElement();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TextSyndicationContent ReadTextContentFrom(XmlReader reader, string context)
|
||
|
{
|
||
|
return ReadTextContentFrom(reader, context, this.PreserveAttributeExtensions);
|
||
|
}
|
||
|
|
||
|
void WriteCategoriesTo(XmlWriter writer, Collection<SyndicationCategory> categories)
|
||
|
{
|
||
|
for (int i = 0; i < categories.Count; ++i)
|
||
|
{
|
||
|
WriteCategory(writer, categories[i], this.Version);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WriteFeed(XmlWriter writer)
|
||
|
{
|
||
|
if (this.Feed == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FeedFormatterDoesNotHaveFeed)));
|
||
|
}
|
||
|
WriteFeedTo(writer, this.Feed, false); // isSourceFeed
|
||
|
}
|
||
|
|
||
|
void WriteFeedTo(XmlWriter writer, SyndicationFeed feed, bool isSourceFeed)
|
||
|
{
|
||
|
if (!isSourceFeed)
|
||
|
{
|
||
|
if (!string.IsNullOrEmpty(feed.Language))
|
||
|
{
|
||
|
writer.WriteAttributeString("xml", "lang", XmlNs, feed.Language);
|
||
|
}
|
||
|
if (feed.BaseUri != null)
|
||
|
{
|
||
|
writer.WriteAttributeString("xml", "base", XmlNs, FeedUtils.GetUriString(feed.BaseUri));
|
||
|
}
|
||
|
WriteAttributeExtensions(writer, feed, this.Version);
|
||
|
}
|
||
|
bool isElementRequired = !isSourceFeed;
|
||
|
TextSyndicationContent title = feed.Title;
|
||
|
if (isElementRequired)
|
||
|
{
|
||
|
title = title ?? new TextSyndicationContent(string.Empty);
|
||
|
}
|
||
|
WriteContentTo(writer, Atom10Constants.TitleTag, title);
|
||
|
WriteContentTo(writer, Atom10Constants.SubtitleTag, feed.Description);
|
||
|
string id = feed.Id;
|
||
|
if (isElementRequired)
|
||
|
{
|
||
|
id = id ?? idGenerator.Next();
|
||
|
}
|
||
|
WriteElement(writer, Atom10Constants.IdTag, id);
|
||
|
WriteContentTo(writer, Atom10Constants.RightsTag, feed.Copyright);
|
||
|
WriteFeedLastUpdatedTimeTo(writer, feed.LastUpdatedTime, isElementRequired);
|
||
|
WriteCategoriesTo(writer, feed.Categories);
|
||
|
if (feed.ImageUrl != null)
|
||
|
{
|
||
|
WriteElement(writer, Atom10Constants.LogoTag, feed.ImageUrl.ToString());
|
||
|
}
|
||
|
WriteFeedAuthorsTo(writer, feed.Authors);
|
||
|
WriteFeedContributorsTo(writer, feed.Contributors);
|
||
|
WriteElement(writer, Atom10Constants.GeneratorTag, feed.Generator);
|
||
|
|
||
|
for (int i = 0; i < feed.Links.Count; ++i)
|
||
|
{
|
||
|
WriteLink(writer, feed.Links[i], feed.BaseUri);
|
||
|
}
|
||
|
|
||
|
WriteElementExtensions(writer, feed, this.Version);
|
||
|
|
||
|
if (!isSourceFeed)
|
||
|
{
|
||
|
WriteItems(writer, feed.Items, feed.BaseUri);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WriteItemContents(XmlWriter dictWriter, SyndicationItem item, Uri feedBaseUri)
|
||
|
{
|
||
|
Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(feedBaseUri, item.BaseUri);
|
||
|
if (baseUriToWrite != null)
|
||
|
{
|
||
|
dictWriter.WriteAttributeString("xml", "base", XmlNs, FeedUtils.GetUriString(baseUriToWrite));
|
||
|
}
|
||
|
WriteAttributeExtensions(dictWriter, item, this.Version);
|
||
|
|
||
|
string id = item.Id ?? idGenerator.Next();
|
||
|
WriteElement(dictWriter, Atom10Constants.IdTag, id);
|
||
|
|
||
|
TextSyndicationContent title = item.Title ?? new TextSyndicationContent(string.Empty);
|
||
|
WriteContentTo(dictWriter, Atom10Constants.TitleTag, title);
|
||
|
WriteContentTo(dictWriter, Atom10Constants.SummaryTag, item.Summary);
|
||
|
if (item.PublishDate != DateTimeOffset.MinValue)
|
||
|
{
|
||
|
dictWriter.WriteElementString(Atom10Constants.PublishedTag,
|
||
|
Atom10Constants.Atom10Namespace,
|
||
|
AsString(item.PublishDate));
|
||
|
}
|
||
|
WriteItemLastUpdatedTimeTo(dictWriter, item.LastUpdatedTime);
|
||
|
WriteItemAuthorsTo(dictWriter, item.Authors);
|
||
|
WriteItemContributorsTo(dictWriter, item.Contributors);
|
||
|
for (int i = 0; i < item.Links.Count; ++i)
|
||
|
{
|
||
|
WriteLink(dictWriter, item.Links[i], item.BaseUri);
|
||
|
}
|
||
|
WriteCategoriesTo(dictWriter, item.Categories);
|
||
|
WriteContentTo(dictWriter, Atom10Constants.ContentTag, item.Content);
|
||
|
WriteContentTo(dictWriter, Atom10Constants.RightsTag, item.Copyright);
|
||
|
if (item.SourceFeed != null)
|
||
|
{
|
||
|
dictWriter.WriteStartElement(Atom10Constants.SourceFeedTag, Atom10Constants.Atom10Namespace);
|
||
|
WriteFeedTo(dictWriter, item.SourceFeed, true); // isSourceFeed
|
||
|
dictWriter.WriteEndElement();
|
||
|
}
|
||
|
WriteElementExtensions(dictWriter, item, this.Version);
|
||
|
}
|
||
|
|
||
|
void WritePersonTo(XmlWriter writer, SyndicationPerson p, string elementName)
|
||
|
{
|
||
|
writer.WriteStartElement(elementName, Atom10Constants.Atom10Namespace);
|
||
|
WriteAttributeExtensions(writer, p, this.Version);
|
||
|
WriteElement(writer, Atom10Constants.NameTag, p.Name);
|
||
|
if (!string.IsNullOrEmpty(p.Uri))
|
||
|
{
|
||
|
writer.WriteElementString(Atom10Constants.UriTag, Atom10Constants.Atom10Namespace, p.Uri);
|
||
|
}
|
||
|
if (!string.IsNullOrEmpty(p.Email))
|
||
|
{
|
||
|
writer.WriteElementString(Atom10Constants.EmailTag, Atom10Constants.Atom10Namespace, p.Email);
|
||
|
}
|
||
|
WriteElementExtensions(writer, p, this.Version);
|
||
|
writer.WriteEndElement();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
|
||
|
[XmlRoot(ElementName = Atom10Constants.FeedTag, Namespace = Atom10Constants.Atom10Namespace)]
|
||
|
public class Atom10FeedFormatter<TSyndicationFeed> : Atom10FeedFormatter
|
||
|
where TSyndicationFeed : SyndicationFeed, new ()
|
||
|
{
|
||
|
// constructors
|
||
|
public Atom10FeedFormatter()
|
||
|
: base(typeof(TSyndicationFeed))
|
||
|
{
|
||
|
}
|
||
|
public Atom10FeedFormatter(TSyndicationFeed feedToWrite)
|
||
|
: base(feedToWrite)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
protected override SyndicationFeed CreateFeedInstance()
|
||
|
{
|
||
|
return new TSyndicationFeed();
|
||
|
}
|
||
|
}
|
||
|
}
|