|
//------------------------------------------------------------
// 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();
}
}
}
|