2016-08-03 10:59:49 +00:00
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634 , 1691
namespace System.ServiceModel.Syndication
{
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Diagnostics.CodeAnalysis ;
using System.Globalization ;
using System.Runtime ;
using System.ServiceModel.Diagnostics ;
using System.Text ;
using System.Xml ;
using System.Xml.Schema ;
using System.Xml.Serialization ;
using DiagnosticUtility = System . ServiceModel . DiagnosticUtility ;
using System.Runtime.CompilerServices ;
[TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
[XmlRoot(ElementName = Rss20Constants.RssTag, Namespace = Rss20Constants.Rss20Namespace)]
public class Rss20FeedFormatter : SyndicationFeedFormatter , IXmlSerializable
{
static readonly XmlQualifiedName Rss20Domain = new XmlQualifiedName ( Rss20Constants . DomainTag , string . Empty ) ;
static readonly XmlQualifiedName Rss20Length = new XmlQualifiedName ( Rss20Constants . LengthTag , string . Empty ) ;
static readonly XmlQualifiedName Rss20Type = new XmlQualifiedName ( Rss20Constants . TypeTag , string . Empty ) ;
static readonly XmlQualifiedName Rss20Url = new XmlQualifiedName ( Rss20Constants . UrlTag , string . Empty ) ;
const string Rfc822OutputLocalDateTimeFormat = "ddd, dd MMM yyyy HH:mm:ss zzz" ;
const string Rfc822OutputUtcDateTimeFormat = "ddd, dd MMM yyyy HH:mm:ss Z" ;
Atom10FeedFormatter atomSerializer ;
Type feedType ;
int maxExtensionSize ;
bool preserveAttributeExtensions ;
bool preserveElementExtensions ;
bool serializeExtensionsAsAtom ;
public Rss20FeedFormatter ( )
: this ( typeof ( SyndicationFeed ) )
{
}
public Rss20FeedFormatter ( 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 . serializeExtensionsAsAtom = true ;
this . maxExtensionSize = int . MaxValue ;
this . preserveElementExtensions = true ;
this . preserveAttributeExtensions = true ;
this . atomSerializer = new Atom10FeedFormatter ( feedTypeToCreate ) ;
this . feedType = feedTypeToCreate ;
}
public Rss20FeedFormatter ( SyndicationFeed feedToWrite )
: this ( feedToWrite , true )
{
}
public Rss20FeedFormatter ( SyndicationFeed feedToWrite , bool serializeExtensionsAsAtom )
: base ( feedToWrite )
{
// No need to check that the parameter passed is valid - it is checked by the c'tor of the base class
this . serializeExtensionsAsAtom = serializeExtensionsAsAtom ;
this . maxExtensionSize = int . MaxValue ;
this . preserveElementExtensions = true ;
this . preserveAttributeExtensions = true ;
this . atomSerializer = new Atom10FeedFormatter ( this . Feed ) ;
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 bool SerializeExtensionsAsAtom
{
get { return this . serializeExtensionsAsAtom ; }
set { this . serializeExtensionsAsAtom = value ; }
}
public override string Version
{
get { return SyndicationVersions . Rss20 ; }
}
protected Type FeedType
{
get
{
return this . feedType ;
}
}
public override bool CanRead ( XmlReader reader )
{
if ( reader = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "reader" ) ;
}
return reader . IsStartElement ( Rss20Constants . RssTag , Rss20Constants . Rss20Namespace ) ;
}
[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 ( Rss20Constants . RssTag , Rss20Constants . Rss20Namespace ) ;
WriteFeed ( writer ) ;
writer . WriteEndElement ( ) ;
TraceFeedWriteEnd ( ) ;
}
protected internal override void SetFeed ( SyndicationFeed feed )
{
base . SetFeed ( feed ) ;
this . atomSerializer . SetFeed ( this . Feed ) ;
}
internal static void TraceExtensionsIgnoredOnWrite ( string message )
{
if ( DiagnosticUtility . ShouldTraceInformation )
{
TraceUtility . TraceEvent ( TraceEventType . Information , TraceCode . SyndicationProtocolElementIgnoredOnWrite , SR . GetString ( message ) ) ;
}
}
internal void ReadItemFrom ( XmlReader reader , SyndicationItem result )
{
ReadItemFrom ( reader , result , null ) ;
}
internal void WriteItemContents ( XmlWriter writer , SyndicationItem item )
{
WriteItemContents ( writer , item , null ) ;
}
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 ( Rss20Constants . ItemTag , Rss20Constants . Rss20Namespace ) )
{
items . Add ( ReadItem ( reader , feed ) ) ;
}
areAllItemsRead = true ;
return items ;
}
protected virtual void WriteItem ( XmlWriter writer , SyndicationItem item , Uri feedBaseUri )
{
TraceItemWriteBegin ( ) ;
writer . WriteStartElement ( Rss20Constants . ItemTag , Rss20Constants . Rss20Namespace ) ;
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 DateTimeOffset DateFromString ( string dateTimeString , XmlReader reader )
{
StringBuilder dateTimeStringBuilder = new StringBuilder ( dateTimeString . Trim ( ) ) ;
if ( dateTimeStringBuilder . Length < 18 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new XmlException ( FeedUtils . AddLineInfo ( reader ,
SR . ErrorParsingDateTime ) ) ) ;
}
if ( dateTimeStringBuilder [ 3 ] = = ',' )
{
// There is a leading (e.g.) "Tue, ", strip it off
dateTimeStringBuilder . Remove ( 0 , 4 ) ;
// There's supposed to be a space here but some implementations dont have one
RemoveExtraWhiteSpaceAtStart ( dateTimeStringBuilder ) ;
}
ReplaceMultipleWhiteSpaceWithSingleWhiteSpace ( dateTimeStringBuilder ) ;
if ( char . IsDigit ( dateTimeStringBuilder [ 1 ] ) )
{
// two-digit day, we are good
}
else
{
dateTimeStringBuilder . Insert ( 0 , '0' ) ;
}
if ( dateTimeStringBuilder . Length < 19 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new XmlException ( FeedUtils . AddLineInfo ( reader ,
SR . ErrorParsingDateTime ) ) ) ;
}
bool thereAreSeconds = ( dateTimeStringBuilder [ 17 ] = = ':' ) ;
int timeZoneStartIndex ;
if ( thereAreSeconds )
{
timeZoneStartIndex = 21 ;
}
else
{
timeZoneStartIndex = 18 ;
}
string timeZoneSuffix = dateTimeStringBuilder . ToString ( ) . Substring ( timeZoneStartIndex ) ;
dateTimeStringBuilder . Remove ( timeZoneStartIndex , dateTimeStringBuilder . Length - timeZoneStartIndex ) ;
bool isUtc ;
dateTimeStringBuilder . Append ( NormalizeTimeZone ( timeZoneSuffix , out isUtc ) ) ;
string wellFormattedString = dateTimeStringBuilder . ToString ( ) ;
DateTimeOffset theTime ;
string parseFormat ;
if ( thereAreSeconds )
{
parseFormat = "dd MMM yyyy HH:mm:ss zzz" ;
}
else
{
parseFormat = "dd MMM yyyy HH:mm zzz" ;
}
if ( DateTimeOffset . TryParseExact ( wellFormattedString , parseFormat ,
CultureInfo . InvariantCulture . DateTimeFormat ,
( isUtc ? DateTimeStyles . AdjustToUniversal : DateTimeStyles . None ) , out theTime ) )
{
return theTime ;
}
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new XmlException ( FeedUtils . AddLineInfo ( reader ,
SR . ErrorParsingDateTime ) ) ) ;
}
static string NormalizeTimeZone ( string rfc822TimeZone , out bool isUtc )
{
isUtc = false ;
// return a string in "-08:00" format
if ( rfc822TimeZone [ 0 ] = = '+' | | rfc822TimeZone [ 0 ] = = '-' )
{
// the time zone is supposed to be 4 digits but some feeds omit the initial 0
StringBuilder result = new StringBuilder ( rfc822TimeZone ) ;
if ( result . Length = = 4 )
{
// the timezone is +/-HMM. Convert to +/-HHMM
result . Insert ( 1 , '0' ) ;
}
result . Insert ( 3 , ':' ) ;
return result . ToString ( ) ;
}
switch ( rfc822TimeZone )
{
case "UT" :
case "Z" :
isUtc = true ;
return "-00:00" ;
case "GMT" :
return "-00:00" ;
case "A" :
return "-01:00" ;
case "B" :
return "-02:00" ;
case "C" :
return "-03:00" ;
case "D" :
case "EDT" :
return "-04:00" ;
case "E" :
case "EST" :
case "CDT" :
return "-05:00" ;
case "F" :
case "CST" :
case "MDT" :
return "-06:00" ;
case "G" :
case "MST" :
case "PDT" :
return "-07:00" ;
case "H" :
case "PST" :
return "-08:00" ;
case "I" :
return "-09:00" ;
case "K" :
return "-10:00" ;
case "L" :
return "-11:00" ;
case "M" :
return "-12:00" ;
case "N" :
return "+01:00" ;
case "O" :
return "+02:00" ;
case "P" :
return "+03:00" ;
case "Q" :
return "+04:00" ;
case "R" :
return "+05:00" ;
case "S" :
return "+06:00" ;
case "T" :
return "+07:00" ;
case "U" :
return "+08:00" ;
case "V" :
return "+09:00" ;
case "W" :
return "+10:00" ;
case "X" :
return "+11:00" ;
case "Y" :
return "+12:00" ;
default :
return "" ;
}
}
static void RemoveExtraWhiteSpaceAtStart ( StringBuilder stringBuilder )
{
int i = 0 ;
while ( i < stringBuilder . Length )
{
if ( ! char . IsWhiteSpace ( stringBuilder [ i ] ) )
{
break ;
}
+ + i ;
}
if ( i > 0 )
{
stringBuilder . Remove ( 0 , i ) ;
}
}
static void ReplaceMultipleWhiteSpaceWithSingleWhiteSpace ( StringBuilder builder )
{
int index = 0 ;
int whiteSpaceStart = - 1 ;
while ( index < builder . Length )
{
if ( char . IsWhiteSpace ( builder [ index ] ) )
{
if ( whiteSpaceStart < 0 )
{
whiteSpaceStart = index ;
// normalize all white spaces to be ' ' so that the date time parsing works
builder [ index ] = ' ' ;
}
}
else if ( whiteSpaceStart > = 0 )
{
if ( index > whiteSpaceStart + 1 )
{
// there are at least 2 spaces... replace by 1
builder . Remove ( whiteSpaceStart , index - whiteSpaceStart - 1 ) ;
index = whiteSpaceStart + 1 ;
}
whiteSpaceStart = - 1 ;
}
+ + index ;
}
// we have already trimmed the start and end so there cannot be a trail of white spaces in the end
Fx . Assert ( builder . Length = = 0 | | builder [ builder . Length - 1 ] ! = ' ' , "The string builder doesnt end in a white space" ) ;
}
string AsString ( DateTimeOffset dateTime )
{
if ( dateTime . Offset = = Atom10FeedFormatter . zeroOffset )
{
return dateTime . ToUniversalTime ( ) . ToString ( Rfc822OutputUtcDateTimeFormat , CultureInfo . InvariantCulture ) ;
}
else
{
StringBuilder sb = new StringBuilder ( dateTime . ToString ( Rfc822OutputLocalDateTimeFormat , CultureInfo . InvariantCulture ) ) ;
// the zzz in Rfc822OutputLocalDateTimeFormat makes the timezone e.g. "-08:00" but we require e.g. "-0800" without the ':'
sb . Remove ( sb . Length - 3 , 1 ) ;
return sb . ToString ( ) ;
}
}
SyndicationLink ReadAlternateLink ( XmlReader reader , Uri baseUri )
{
SyndicationLink link = new SyndicationLink ( ) ;
link . BaseUri = baseUri ;
link . RelationshipType = Atom10Constants . AlternateTag ;
if ( reader . HasAttributes )
{
while ( reader . MoveToNextAttribute ( ) )
{
if ( reader . LocalName = = "base" & & reader . NamespaceURI = = Atom10FeedFormatter . XmlNs )
{
link . BaseUri = FeedUtils . CombineXmlBase ( link . BaseUri , 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 ) ;
}
}
}
}
string uri = reader . ReadElementString ( ) ;
link . Uri = new Uri ( uri , UriKind . RelativeOrAbsolute ) ;
return link ;
}
SyndicationCategory ReadCategory ( XmlReader reader , SyndicationFeed feed )
{
SyndicationCategory result = CreateCategory ( feed ) ;
ReadCategory ( reader , result ) ;
return result ;
}
SyndicationCategory ReadCategory ( XmlReader reader , SyndicationItem item )
{
SyndicationCategory result = CreateCategory ( item ) ;
ReadCategory ( reader , result ) ;
return result ;
}
void ReadCategory ( XmlReader reader , SyndicationCategory category )
{
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 ( name = = Rss20Constants . DomainTag & & ns = = Rss20Constants . Rss20Namespace )
{
category . Scheme = val ;
}
else if ( ! TryParseAttribute ( name , ns , val , category , this . Version ) )
{
if ( this . preserveAttributeExtensions )
{
category . AttributeExtensions . Add ( new XmlQualifiedName ( name , ns ) , val ) ;
}
else
{
TraceSyndicationElementIgnoredOnRead ( reader ) ;
}
}
}
}
reader . ReadStartElement ( Rss20Constants . CategoryTag , Rss20Constants . Rss20Namespace ) ;
if ( ! isEmpty )
{
category . Name = reader . ReadString ( ) ;
reader . ReadEndElement ( ) ;
}
}
void ReadFeed ( XmlReader reader )
{
SetFeed ( CreateFeedInstance ( ) ) ;
ReadXml ( reader , this . Feed ) ;
}
void ReadItemFrom ( XmlReader reader , SyndicationItem result , Uri feedBaseUri )
{
try
{
result . BaseUri = feedBaseUri ;
reader . MoveToContent ( ) ;
bool isEmpty = reader . IsEmptyElement ;
if ( reader . HasAttributes )
{
while ( reader . MoveToNextAttribute ( ) )
{
string ns = reader . NamespaceURI ;
string name = reader . LocalName ;
if ( name = = "base" & & ns = = Atom10FeedFormatter . 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 ( name , ns ) , val ) ;
}
else
{
TraceSyndicationElementIgnoredOnRead ( reader ) ;
}
}
}
}
reader . ReadStartElement ( ) ;
if ( ! isEmpty )
{
string fallbackAlternateLink = null ;
XmlDictionaryWriter extWriter = null ;
bool readAlternateLink = false ;
try
{
XmlBuffer buffer = null ;
while ( reader . IsStartElement ( ) )
{
if ( reader . IsStartElement ( Rss20Constants . TitleTag , Rss20Constants . Rss20Namespace ) )
{
result . Title = new TextSyndicationContent ( reader . ReadElementString ( ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . LinkTag , Rss20Constants . Rss20Namespace ) )
{
result . Links . Add ( ReadAlternateLink ( reader , result . BaseUri ) ) ;
readAlternateLink = true ;
}
else if ( reader . IsStartElement ( Rss20Constants . DescriptionTag , Rss20Constants . Rss20Namespace ) )
{
result . Summary = new TextSyndicationContent ( reader . ReadElementString ( ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . AuthorTag , Rss20Constants . Rss20Namespace ) )
{
result . Authors . Add ( ReadPerson ( reader , result ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . CategoryTag , Rss20Constants . Rss20Namespace ) )
{
result . Categories . Add ( ReadCategory ( reader , result ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . EnclosureTag , Rss20Constants . Rss20Namespace ) )
{
result . Links . Add ( ReadMediaEnclosure ( reader , result . BaseUri ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . GuidTag , Rss20Constants . Rss20Namespace ) )
{
bool isPermalink = true ;
string permalinkString = reader . GetAttribute ( Rss20Constants . IsPermaLinkTag , Rss20Constants . Rss20Namespace ) ;
if ( ( permalinkString ! = null ) & & ( permalinkString . ToUpperInvariant ( ) = = "FALSE" ) )
{
isPermalink = false ;
}
result . Id = reader . ReadElementString ( ) ;
if ( isPermalink )
{
fallbackAlternateLink = result . Id ;
}
}
else if ( reader . IsStartElement ( Rss20Constants . PubDateTag , Rss20Constants . Rss20Namespace ) )
{
bool canReadContent = ! reader . IsEmptyElement ;
reader . ReadStartElement ( ) ;
if ( canReadContent )
{
string str = reader . ReadString ( ) ;
if ( ! string . IsNullOrEmpty ( str ) )
{
result . PublishDate = DateFromString ( str , reader ) ;
}
reader . ReadEndElement ( ) ;
}
}
else if ( reader . IsStartElement ( Rss20Constants . SourceTag , Rss20Constants . Rss20Namespace ) )
{
SyndicationFeed feed = new SyndicationFeed ( ) ;
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 ( name = = Rss20Constants . UrlTag & & ns = = Rss20Constants . Rss20Namespace )
{
feed . Links . Add ( SyndicationLink . CreateSelfLink ( new Uri ( val , UriKind . RelativeOrAbsolute ) ) ) ;
}
else if ( ! FeedUtils . IsXmlns ( name , ns ) )
{
if ( this . preserveAttributeExtensions )
{
feed . AttributeExtensions . Add ( new XmlQualifiedName ( name , ns ) , val ) ;
}
else
{
TraceSyndicationElementIgnoredOnRead ( reader ) ;
}
}
}
}
string feedTitle = reader . ReadElementString ( ) ;
feed . Title = new TextSyndicationContent ( feedTitle ) ;
result . SourceFeed = feed ;
}
else
{
bool parsedExtension = this . serializeExtensionsAsAtom & & this . atomSerializer . TryParseItemElementFrom ( reader , result ) ;
if ( ! parsedExtension )
{
parsedExtension = TryParseElement ( reader , result , this . Version ) ;
}
if ( ! parsedExtension )
{
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
if ( ! readAlternateLink & & fallbackAlternateLink ! = null )
{
result . Links . Add ( SyndicationLink . CreateAlternateLink ( new Uri ( fallbackAlternateLink , UriKind . RelativeOrAbsolute ) ) ) ;
readAlternateLink = true ;
}
// if there's no content and no alternate link set the summary as the item content
if ( result . Content = = null & & ! readAlternateLink )
{
result . Content = result . Summary ;
result . Summary = null ;
}
}
}
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 ) ) ;
}
}
SyndicationLink ReadMediaEnclosure ( XmlReader reader , Uri baseUri )
{
SyndicationLink link = new SyndicationLink ( ) ;
link . BaseUri = baseUri ;
link . RelationshipType = Rss20Constants . EnclosureTag ;
bool isEmptyElement = reader . IsEmptyElement ;
if ( reader . HasAttributes )
{
while ( reader . MoveToNextAttribute ( ) )
{
string ns = reader . NamespaceURI ;
string name = reader . LocalName ;
if ( name = = "base" & & ns = = Atom10FeedFormatter . XmlNs )
{
link . BaseUri = FeedUtils . CombineXmlBase ( link . BaseUri , reader . Value ) ;
continue ;
}
if ( FeedUtils . IsXmlns ( name , ns ) )
{
continue ;
}
string val = reader . Value ;
if ( name = = Rss20Constants . UrlTag & & ns = = Rss20Constants . Rss20Namespace )
{
link . Uri = new Uri ( val , UriKind . RelativeOrAbsolute ) ;
}
else if ( name = = Rss20Constants . TypeTag & & ns = = Rss20Constants . Rss20Namespace )
{
link . MediaType = val ;
}
else if ( name = = Rss20Constants . LengthTag & & ns = = Rss20Constants . Rss20Namespace )
{
link . Length = ! string . IsNullOrEmpty ( val ) ? Convert . ToInt64 ( val , CultureInfo . InvariantCulture . NumberFormat ) : 0 ;
}
else if ( ! FeedUtils . IsXmlns ( name , ns ) )
{
if ( this . preserveAttributeExtensions )
{
link . AttributeExtensions . Add ( new XmlQualifiedName ( name , ns ) , val ) ;
}
else
{
TraceSyndicationElementIgnoredOnRead ( reader ) ;
}
}
}
}
reader . ReadStartElement ( Rss20Constants . EnclosureTag , Rss20Constants . Rss20Namespace ) ;
if ( ! isEmptyElement )
{
reader . ReadEndElement ( ) ;
}
return link ;
}
SyndicationPerson ReadPerson ( XmlReader reader , SyndicationFeed feed )
{
SyndicationPerson result = CreatePerson ( feed ) ;
ReadPerson ( reader , result ) ;
return result ;
}
SyndicationPerson ReadPerson ( XmlReader reader , SyndicationItem item )
{
SyndicationPerson result = CreatePerson ( item ) ;
ReadPerson ( reader , result ) ;
return result ;
}
void ReadPerson ( XmlReader reader , SyndicationPerson person )
{
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 , person , this . Version ) )
{
if ( this . preserveAttributeExtensions )
{
person . AttributeExtensions . Add ( new XmlQualifiedName ( name , ns ) , val ) ;
}
else
{
TraceSyndicationElementIgnoredOnRead ( reader ) ;
}
}
}
}
reader . ReadStartElement ( ) ;
if ( ! isEmpty )
{
string email = reader . ReadString ( ) ;
reader . ReadEndElement ( ) ;
person . Email = email ;
}
}
void ReadXml ( XmlReader reader , SyndicationFeed result )
{
try
{
string baseUri = null ;
reader . MoveToContent ( ) ;
string version = reader . GetAttribute ( Rss20Constants . VersionTag , Rss20Constants . Rss20Namespace ) ;
if ( version ! = Rss20Constants . Version )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new NotSupportedException ( FeedUtils . AddLineInfo ( reader , ( SR . GetString ( SR . UnsupportedRssVersion , version ) ) ) ) ) ;
}
if ( reader . AttributeCount > 1 )
{
string tmp = reader . GetAttribute ( "base" , Atom10FeedFormatter . XmlNs ) ;
if ( ! string . IsNullOrEmpty ( tmp ) )
{
baseUri = tmp ;
}
}
reader . ReadStartElement ( ) ;
reader . MoveToContent ( ) ;
if ( reader . HasAttributes )
{
while ( reader . MoveToNextAttribute ( ) )
{
string ns = reader . NamespaceURI ;
string name = reader . LocalName ;
if ( name = = "base" & & ns = = Atom10FeedFormatter . XmlNs )
{
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 ( name , ns ) , val ) ;
}
else
{
TraceSyndicationElementIgnoredOnRead ( reader ) ;
}
}
}
}
if ( ! string . IsNullOrEmpty ( baseUri ) )
{
result . BaseUri = new Uri ( baseUri , UriKind . RelativeOrAbsolute ) ;
}
bool areAllItemsRead = true ;
bool readItemsAtLeastOnce = false ;
reader . ReadStartElement ( Rss20Constants . ChannelTag , Rss20Constants . Rss20Namespace ) ;
XmlBuffer buffer = null ;
XmlDictionaryWriter extWriter = null ;
try
{
while ( reader . IsStartElement ( ) )
{
if ( reader . IsStartElement ( Rss20Constants . TitleTag , Rss20Constants . Rss20Namespace ) )
{
result . Title = new TextSyndicationContent ( reader . ReadElementString ( ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . LinkTag , Rss20Constants . Rss20Namespace ) )
{
result . Links . Add ( ReadAlternateLink ( reader , result . BaseUri ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . DescriptionTag , Rss20Constants . Rss20Namespace ) )
{
result . Description = new TextSyndicationContent ( reader . ReadElementString ( ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . LanguageTag , Rss20Constants . Rss20Namespace ) )
{
result . Language = reader . ReadElementString ( ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . CopyrightTag , Rss20Constants . Rss20Namespace ) )
{
result . Copyright = new TextSyndicationContent ( reader . ReadElementString ( ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . ManagingEditorTag , Rss20Constants . Rss20Namespace ) )
{
result . Authors . Add ( ReadPerson ( reader , result ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . LastBuildDateTag , Rss20Constants . Rss20Namespace ) )
{
bool canReadContent = ! reader . IsEmptyElement ;
reader . ReadStartElement ( ) ;
if ( canReadContent )
{
string str = reader . ReadString ( ) ;
if ( ! string . IsNullOrEmpty ( str ) )
{
result . LastUpdatedTime = DateFromString ( str , reader ) ;
}
reader . ReadEndElement ( ) ;
}
}
else if ( reader . IsStartElement ( Rss20Constants . CategoryTag , Rss20Constants . Rss20Namespace ) )
{
result . Categories . Add ( ReadCategory ( reader , result ) ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . GeneratorTag , Rss20Constants . Rss20Namespace ) )
{
result . Generator = reader . ReadElementString ( ) ;
}
else if ( reader . IsStartElement ( Rss20Constants . ImageTag , Rss20Constants . Rss20Namespace ) )
{
reader . ReadStartElement ( ) ;
while ( reader . IsStartElement ( ) )
{
if ( reader . IsStartElement ( Rss20Constants . UrlTag , Rss20Constants . Rss20Namespace ) )
{
result . ImageUrl = new Uri ( reader . ReadElementString ( ) , UriKind . RelativeOrAbsolute ) ;
}
else
{
// ignore other content
TraceSyndicationElementIgnoredOnRead ( reader ) ;
reader . Skip ( ) ;
}
}
reader . ReadEndElement ( ) ; // image
}
else if ( reader . IsStartElement ( Rss20Constants . ItemTag , Rss20Constants . Rss20Namespace ) )
{
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
{
bool parsedExtension = this . serializeExtensionsAsAtom & & this . atomSerializer . TryParseFeedElementFrom ( reader , result ) ;
if ( ! parsedExtension )
{
parsedExtension = TryParseElement ( reader , result , this . Version ) ;
}
if ( ! parsedExtension )
{
if ( 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 ( areAllItemsRead )
{
reader . ReadEndElement ( ) ; // channel
reader . ReadEndElement ( ) ; // rss
}
}
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 ) ) ;
}
}
void WriteAlternateLink ( XmlWriter writer , SyndicationLink link , Uri baseUri )
{
writer . WriteStartElement ( Rss20Constants . LinkTag , Rss20Constants . Rss20Namespace ) ;
Uri baseUriToWrite = FeedUtils . GetBaseUriToWrite ( baseUri , link . BaseUri ) ;
if ( baseUriToWrite ! = null )
{
writer . WriteAttributeString ( "xml" , "base" , Atom10FeedFormatter . XmlNs , FeedUtils . GetUriString ( baseUriToWrite ) ) ;
}
link . WriteAttributeExtensions ( writer , SyndicationVersions . Rss20 ) ;
writer . WriteString ( FeedUtils . GetUriString ( link . Uri ) ) ;
writer . WriteEndElement ( ) ;
}
void WriteCategory ( XmlWriter writer , SyndicationCategory category )
{
if ( category = = null )
{
return ;
}
writer . WriteStartElement ( Rss20Constants . CategoryTag , Rss20Constants . Rss20Namespace ) ;
WriteAttributeExtensions ( writer , category , this . Version ) ;
if ( ! string . IsNullOrEmpty ( category . Scheme ) & & ! category . AttributeExtensions . ContainsKey ( Rss20Domain ) )
{
writer . WriteAttributeString ( Rss20Constants . DomainTag , Rss20Constants . Rss20Namespace , category . Scheme ) ;
}
writer . WriteString ( category . Name ) ;
writer . WriteEndElement ( ) ;
}
void WriteFeed ( XmlWriter writer )
{
if ( this . Feed = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . FeedFormatterDoesNotHaveFeed ) ) ) ;
}
if ( this . serializeExtensionsAsAtom )
{
writer . WriteAttributeString ( "xmlns" , Atom10Constants . Atom10Prefix , null , Atom10Constants . Atom10Namespace ) ;
}
writer . WriteAttributeString ( Rss20Constants . VersionTag , Rss20Constants . Version ) ;
writer . WriteStartElement ( Rss20Constants . ChannelTag , Rss20Constants . Rss20Namespace ) ;
if ( this . Feed . BaseUri ! = null )
{
writer . WriteAttributeString ( "xml" , "base" , Atom10FeedFormatter . XmlNs , FeedUtils . GetUriString ( this . Feed . BaseUri ) ) ;
}
WriteAttributeExtensions ( writer , this . Feed , this . Version ) ;
string title = this . Feed . Title ! = null ? this . Feed . Title . Text : string . Empty ;
writer . WriteElementString ( Rss20Constants . TitleTag , Rss20Constants . Rss20Namespace , title ) ;
SyndicationLink alternateLink = null ;
for ( int i = 0 ; i < this . Feed . Links . Count ; + + i )
{
if ( this . Feed . Links [ i ] . RelationshipType = = Atom10Constants . AlternateTag )
{
alternateLink = this . Feed . Links [ i ] ;
WriteAlternateLink ( writer , alternateLink , this . Feed . BaseUri ) ;
break ;
}
}
string description = this . Feed . Description ! = null ? this . Feed . Description . Text : string . Empty ;
writer . WriteElementString ( Rss20Constants . DescriptionTag , Rss20Constants . Rss20Namespace , description ) ;
if ( this . Feed . Language ! = null )
{
writer . WriteElementString ( Rss20Constants . LanguageTag , this . Feed . Language ) ;
}
if ( this . Feed . Copyright ! = null )
{
writer . WriteElementString ( Rss20Constants . CopyrightTag , Rss20Constants . Rss20Namespace , this . Feed . Copyright . Text ) ;
}
// if there's a single author with an email address, then serialize as the managingEditor
// else serialize the authors as Atom extensions
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft: this.Feed.Authors is never null
2016-08-03 10:59:49 +00:00
if ( ( this . Feed . Authors . Count = = 1 ) & & ( this . Feed . Authors [ 0 ] . Email ! = null ) )
#pragma warning restore 56506
{
WritePerson ( writer , Rss20Constants . ManagingEditorTag , this . Feed . Authors [ 0 ] ) ;
}
else
{
if ( serializeExtensionsAsAtom )
{
this . atomSerializer . WriteFeedAuthorsTo ( writer , this . Feed . Authors ) ;
}
else
{
TraceExtensionsIgnoredOnWrite ( SR . FeedAuthorsIgnoredOnWrite ) ;
}
}
if ( this . Feed . LastUpdatedTime > DateTimeOffset . MinValue )
{
writer . WriteStartElement ( Rss20Constants . LastBuildDateTag ) ;
writer . WriteString ( AsString ( this . Feed . LastUpdatedTime ) ) ;
writer . WriteEndElement ( ) ;
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft: this.Feed.Categories is never null
2016-08-03 10:59:49 +00:00
for ( int i = 0 ; i < this . Feed . Categories . Count ; + + i )
#pragma warning restore 56506
{
WriteCategory ( writer , this . Feed . Categories [ i ] ) ;
}
if ( ! string . IsNullOrEmpty ( this . Feed . Generator ) )
{
writer . WriteElementString ( Rss20Constants . GeneratorTag , this . Feed . Generator ) ;
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft: this.Feed.Contributors is never null
2016-08-03 10:59:49 +00:00
if ( this . Feed . Contributors . Count > 0 )
#pragma warning restore 56506
{
if ( serializeExtensionsAsAtom )
{
this . atomSerializer . WriteFeedContributorsTo ( writer , this . Feed . Contributors ) ;
}
else
{
TraceExtensionsIgnoredOnWrite ( SR . FeedContributorsIgnoredOnWrite ) ;
}
}
if ( this . Feed . ImageUrl ! = null )
{
writer . WriteStartElement ( Rss20Constants . ImageTag ) ;
writer . WriteElementString ( Rss20Constants . UrlTag , FeedUtils . GetUriString ( this . Feed . ImageUrl ) ) ;
writer . WriteElementString ( Rss20Constants . TitleTag , Rss20Constants . Rss20Namespace , title ) ;
string imgAlternateLink = ( alternateLink ! = null ) ? FeedUtils . GetUriString ( alternateLink . Uri ) : string . Empty ;
writer . WriteElementString ( Rss20Constants . LinkTag , Rss20Constants . Rss20Namespace , imgAlternateLink ) ;
writer . WriteEndElement ( ) ; // image
}
if ( serializeExtensionsAsAtom )
{
this . atomSerializer . WriteElement ( writer , Atom10Constants . IdTag , this . Feed . Id ) ;
// dont write out the 1st alternate link since that would have been written out anyway
bool isFirstAlternateLink = true ;
for ( int i = 0 ; i < this . Feed . Links . Count ; + + i )
{
if ( this . Feed . Links [ i ] . RelationshipType = = Atom10Constants . AlternateTag & & isFirstAlternateLink )
{
isFirstAlternateLink = false ;
continue ;
}
this . atomSerializer . WriteLink ( writer , this . Feed . Links [ i ] , this . Feed . BaseUri ) ;
}
}
else
{
if ( this . Feed . Id ! = null )
{
TraceExtensionsIgnoredOnWrite ( SR . FeedIdIgnoredOnWrite ) ;
}
if ( this . Feed . Links . Count > 1 )
{
TraceExtensionsIgnoredOnWrite ( SR . FeedLinksIgnoredOnWrite ) ;
}
}
WriteElementExtensions ( writer , this . Feed , this . Version ) ;
WriteItems ( writer , this . Feed . Items , this . Feed . BaseUri ) ;
writer . WriteEndElement ( ) ; // channel
}
void WriteItemContents ( XmlWriter writer , SyndicationItem item , Uri feedBaseUri )
{
Uri baseUriToWrite = FeedUtils . GetBaseUriToWrite ( feedBaseUri , item . BaseUri ) ;
if ( baseUriToWrite ! = null )
{
writer . WriteAttributeString ( "xml" , "base" , Atom10FeedFormatter . XmlNs , FeedUtils . GetUriString ( baseUriToWrite ) ) ;
}
WriteAttributeExtensions ( writer , item , this . Version ) ;
string guid = item . Id ? ? string . Empty ;
bool isPermalink = false ;
SyndicationLink firstAlternateLink = null ;
for ( int i = 0 ; i < item . Links . Count ; + + i )
{
if ( item . Links [ i ] . RelationshipType = = Atom10Constants . AlternateTag )
{
if ( firstAlternateLink = = null )
{
firstAlternateLink = item . Links [ i ] ;
}
if ( guid = = FeedUtils . GetUriString ( item . Links [ i ] . Uri ) )
{
isPermalink = true ;
break ;
}
}
}
if ( ! string . IsNullOrEmpty ( guid ) )
{
writer . WriteStartElement ( Rss20Constants . GuidTag ) ;
if ( isPermalink )
{
writer . WriteAttributeString ( Rss20Constants . IsPermaLinkTag , "true" ) ;
}
else
{
writer . WriteAttributeString ( Rss20Constants . IsPermaLinkTag , "false" ) ;
}
writer . WriteString ( guid ) ;
writer . WriteEndElement ( ) ;
}
if ( firstAlternateLink ! = null )
{
WriteAlternateLink ( writer , firstAlternateLink , ( item . BaseUri ! = null ? item . BaseUri : feedBaseUri ) ) ;
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, item.Authors is never null
2016-08-03 10:59:49 +00:00
if ( item . Authors . Count = = 1 & & ! string . IsNullOrEmpty ( item . Authors [ 0 ] . Email ) )
#pragma warning restore 56506
{
WritePerson ( writer , Rss20Constants . AuthorTag , item . Authors [ 0 ] ) ;
}
else
{
if ( serializeExtensionsAsAtom )
{
this . atomSerializer . WriteItemAuthorsTo ( writer , item . Authors ) ;
}
else
{
TraceExtensionsIgnoredOnWrite ( SR . ItemAuthorsIgnoredOnWrite ) ;
}
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, item.Categories is never null
2016-08-03 10:59:49 +00:00
for ( int i = 0 ; i < item . Categories . Count ; + + i )
#pragma warning restore 56506
{
WriteCategory ( writer , item . Categories [ i ] ) ;
}
bool serializedTitle = false ;
if ( item . Title ! = null )
{
writer . WriteElementString ( Rss20Constants . TitleTag , item . Title . Text ) ;
serializedTitle = true ;
}
bool serializedContentAsDescription = false ;
TextSyndicationContent summary = item . Summary ;
if ( summary = = null )
{
summary = ( item . Content as TextSyndicationContent ) ;
serializedContentAsDescription = ( summary ! = null ) ;
}
// the spec requires the wire to have a title or a description
if ( ! serializedTitle & & summary = = null )
{
summary = new TextSyndicationContent ( string . Empty ) ;
}
if ( summary ! = null )
{
writer . WriteElementString ( Rss20Constants . DescriptionTag , Rss20Constants . Rss20Namespace , summary . Text ) ;
}
if ( item . SourceFeed ! = null )
{
writer . WriteStartElement ( Rss20Constants . SourceTag , Rss20Constants . Rss20Namespace ) ;
WriteAttributeExtensions ( writer , item . SourceFeed , this . Version ) ;
SyndicationLink selfLink = null ;
for ( int i = 0 ; i < item . SourceFeed . Links . Count ; + + i )
{
if ( item . SourceFeed . Links [ i ] . RelationshipType = = Atom10Constants . SelfTag )
{
selfLink = item . SourceFeed . Links [ i ] ;
break ;
}
}
if ( selfLink ! = null & & ! item . SourceFeed . AttributeExtensions . ContainsKey ( Rss20Url ) )
{
writer . WriteAttributeString ( Rss20Constants . UrlTag , Rss20Constants . Rss20Namespace , FeedUtils . GetUriString ( selfLink . Uri ) ) ;
}
string title = ( item . SourceFeed . Title ! = null ) ? item . SourceFeed . Title . Text : string . Empty ;
writer . WriteString ( title ) ;
writer . WriteEndElement ( ) ;
}
if ( item . PublishDate > DateTimeOffset . MinValue )
{
writer . WriteElementString ( Rss20Constants . PubDateTag , Rss20Constants . Rss20Namespace , AsString ( item . PublishDate ) ) ;
}
// serialize the enclosures
SyndicationLink firstEnclosureLink = null ;
bool passedFirstAlternateLink = false ;
bool isLinkIgnored = false ;
for ( int i = 0 ; i < item . Links . Count ; + + i )
{
if ( item . Links [ i ] . RelationshipType = = Rss20Constants . EnclosureTag )
{
if ( firstEnclosureLink = = null )
{
firstEnclosureLink = item . Links [ i ] ;
WriteMediaEnclosure ( writer , item . Links [ i ] , item . BaseUri ) ;
continue ;
}
}
else if ( item . Links [ i ] . RelationshipType = = Atom10Constants . AlternateTag )
{
if ( ! passedFirstAlternateLink )
{
passedFirstAlternateLink = true ;
continue ;
}
}
if ( this . serializeExtensionsAsAtom )
{
this . atomSerializer . WriteLink ( writer , item . Links [ i ] , item . BaseUri ) ;
}
else
{
isLinkIgnored = true ;
}
}
if ( isLinkIgnored )
{
TraceExtensionsIgnoredOnWrite ( SR . ItemLinksIgnoredOnWrite ) ;
}
if ( item . LastUpdatedTime > DateTimeOffset . MinValue )
{
if ( this . serializeExtensionsAsAtom )
{
this . atomSerializer . WriteItemLastUpdatedTimeTo ( writer , item . LastUpdatedTime ) ;
}
else
{
TraceExtensionsIgnoredOnWrite ( SR . ItemLastUpdatedTimeIgnoredOnWrite ) ;
}
}
if ( serializeExtensionsAsAtom )
{
this . atomSerializer . WriteContentTo ( writer , Atom10Constants . RightsTag , item . Copyright ) ;
}
else
{
TraceExtensionsIgnoredOnWrite ( SR . ItemCopyrightIgnoredOnWrite ) ;
}
if ( ! serializedContentAsDescription )
{
if ( serializeExtensionsAsAtom )
{
this . atomSerializer . WriteContentTo ( writer , Atom10Constants . ContentTag , item . Content ) ;
}
else
{
TraceExtensionsIgnoredOnWrite ( SR . ItemContentIgnoredOnWrite ) ;
}
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, item.COntributors is never null
2016-08-03 10:59:49 +00:00
if ( item . Contributors . Count > 0 )
#pragma warning restore 56506
{
if ( serializeExtensionsAsAtom )
{
this . atomSerializer . WriteItemContributorsTo ( writer , item . Contributors ) ;
}
else
{
TraceExtensionsIgnoredOnWrite ( SR . ItemContributorsIgnoredOnWrite ) ;
}
}
WriteElementExtensions ( writer , item , this . Version ) ;
}
void WriteMediaEnclosure ( XmlWriter writer , SyndicationLink link , Uri baseUri )
{
writer . WriteStartElement ( Rss20Constants . EnclosureTag , Rss20Constants . Rss20Namespace ) ;
Uri baseUriToWrite = FeedUtils . GetBaseUriToWrite ( baseUri , link . BaseUri ) ;
if ( baseUriToWrite ! = null )
{
writer . WriteAttributeString ( "xml" , "base" , Atom10FeedFormatter . XmlNs , FeedUtils . GetUriString ( baseUriToWrite ) ) ;
}
link . WriteAttributeExtensions ( writer , SyndicationVersions . Rss20 ) ;
if ( ! link . AttributeExtensions . ContainsKey ( Rss20Url ) )
{
writer . WriteAttributeString ( Rss20Constants . UrlTag , Rss20Constants . Rss20Namespace , FeedUtils . GetUriString ( link . Uri ) ) ;
}
if ( link . MediaType ! = null & & ! link . AttributeExtensions . ContainsKey ( Rss20Type ) )
{
writer . WriteAttributeString ( Rss20Constants . TypeTag , Rss20Constants . Rss20Namespace , link . MediaType ) ;
}
if ( link . Length ! = 0 & & ! link . AttributeExtensions . ContainsKey ( Rss20Length ) )
{
writer . WriteAttributeString ( Rss20Constants . LengthTag , Rss20Constants . Rss20Namespace , Convert . ToString ( link . Length , CultureInfo . InvariantCulture ) ) ;
}
writer . WriteEndElement ( ) ;
}
void WritePerson ( XmlWriter writer , string elementTag , SyndicationPerson person )
{
writer . WriteStartElement ( elementTag , Rss20Constants . Rss20Namespace ) ;
WriteAttributeExtensions ( writer , person , this . Version ) ;
writer . WriteString ( person . Email ) ;
writer . WriteEndElement ( ) ;
}
}
[TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
[XmlRoot(ElementName = Rss20Constants.RssTag, Namespace = Rss20Constants.Rss20Namespace)]
public class Rss20FeedFormatter < TSyndicationFeed > : Rss20FeedFormatter
where TSyndicationFeed : SyndicationFeed , new ( )
{
// constructors
public Rss20FeedFormatter ( )
: base ( typeof ( TSyndicationFeed ) )
{
}
public Rss20FeedFormatter ( TSyndicationFeed feedToWrite )
: base ( feedToWrite )
{
}
public Rss20FeedFormatter ( TSyndicationFeed feedToWrite , bool serializeExtensionsAsAtom )
: base ( feedToWrite , serializeExtensionsAsAtom )
{
}
protected override SyndicationFeed CreateFeedInstance ( )
{
return new TSyndicationFeed ( ) ;
}
}
}