/// <summary>standard empty constructor</summary> public AtomFeedParser() : base() { Tracing.TraceCall("constructing AtomFeedParser"); this.nameTable = new AtomParserNameTable(); this.nameTable.InitAtomParserNameTable(); }
/// <summary>nifty loop to check for base attributes for an object</summary> /// <param name="reader">correctly positioned xmlreader</param> /// <param name="baseObject">the base object to set the property on</param> protected void ParseBasicAttributes(XmlReader reader, AtomBase baseObject) { Tracing.TraceCall(); Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } Tracing.Assert(baseObject != null, "baseObject should not be null"); if (baseObject == null) { throw new ArgumentNullException("baseObject"); } if (reader.NodeType == XmlNodeType.Element && reader.HasAttributes) { while (reader.MoveToNextAttribute()) { ParseBaseAttributes(reader, baseObject); } // position back to the element reader.MoveToElement(); } }
/// <summary>parses extension elements, needs to happen when known attributes are done</summary> /// <param name="reader">correctly positioned xmlreader</param> /// <param name="baseObject">the base object to set the property on</param> protected void ParseExtensionElements(XmlReader reader, AtomBase baseObject) { Tracing.TraceCall(); if (reader == null) { throw new System.ArgumentNullException("reader", "No XmlReader supplied"); } if (baseObject == null) { throw new System.ArgumentNullException("baseObject", "No baseObject supplied"); } if (IsCurrentNameSpace(reader, BaseNameTable.NSAtom)) { Tracing.TraceInfo("Found an unknown ATOM element = this might be a bug, either in the code or the document"); Tracing.TraceInfo("element: " + reader.LocalName + " position: " + reader.NodeType.ToString()); // maybe we should throw here, but I rather not - makes parsing more flexible } else { // everything NOT in Atom, call it Tracing.TraceInfo("Found an unknown element"); this.OnNewExtensionElement(reader, baseObject); // position back to the element reader.MoveToElement(); } }
/// <summary>initializes the name table for use with atom parsing. This is the /// only place where strings are defined for parsing</summary> public virtual void InitAtomParserNameTable() { // create the nametable object Tracing.TraceCall("Initializing basenametable support"); this.atomNameTable = new NameTable(); // <summary>add the keywords for the Feed this.totalResults = this.atomNameTable.Add("totalResults"); this.startIndex = this.atomNameTable.Add("startIndex"); this.itemsPerPage = this.atomNameTable.Add("itemsPerPage"); this.baseUri = this.atomNameTable.Add("base"); this.language = this.atomNameTable.Add("lang"); // batch keywords this.batchId = this.atomNameTable.Add(BaseNameTable.XmlElementBatchId); this.batchOperation = this.atomNameTable.Add(BaseNameTable.XmlElementBatchOperation); this.batchStatus = this.atomNameTable.Add(BaseNameTable.XmlElementBatchStatus); this.batchInterrupt = this.atomNameTable.Add(BaseNameTable.XmlElementBatchInterrupt); this.batchContentType = this.atomNameTable.Add(BaseNameTable.XmlAttributeBatchContentType); this.batchStatusCode = this.atomNameTable.Add(BaseNameTable.XmlAttributeBatchStatusCode); this.batchReason = this.atomNameTable.Add(BaseNameTable.XmlAttributeBatchReason); this.batchErrors = this.atomNameTable.Add(BaseNameTable.XmlElementBatchErrors); this.batchError = this.atomNameTable.Add(BaseNameTable.XmlElementBatchError); this.batchSuccessCount = this.atomNameTable.Add(BaseNameTable.XmlAttributeBatchSuccess); this.batchFailureCount = this.batchError; this.batchParsedCount = this.atomNameTable.Add(BaseNameTable.XmlAttributeBatchParsed); this.batchField = this.atomNameTable.Add(BaseNameTable.XmlAttributeBatchField); this.batchUnprocessed = this.atomNameTable.Add(BaseNameTable.XmlAttributeBatchUnprocessed); this.type = this.atomNameTable.Add(BaseNameTable.XmlAttributeType); this.value = this.atomNameTable.Add(BaseNameTable.XmlValue); this.name = this.atomNameTable.Add(BaseNameTable.XmlName); this.eTagAttribute = this.atomNameTable.Add(BaseNameTable.XmlEtagAttribute); }
/// <summary>Creates the complete URI query string based on all set properties.</summary> /// <returns> string => the query part of the URI</returns> protected virtual string CalculateQuery(string basePath) { Tracing.TraceCall("creating target Uri"); StringBuilder newPath = new StringBuilder(basePath, 2048); char paramInsertion = InsertionParameter(basePath); paramInsertion = CreateCategoryString(newPath, paramInsertion); if (this.FeedFormat != AlternativeFormat.Atom) { newPath.Append(paramInsertion); newPath.AppendFormat(CultureInfo.InvariantCulture, "alt={0}", FormatToString(this.FeedFormat)); paramInsertion = '&'; } paramInsertion = AppendQueryPart(this.Query, "q", paramInsertion, newPath); paramInsertion = AppendQueryPart(this.Author, "author", paramInsertion, newPath); paramInsertion = AppendQueryPart(this.StartDate, "updated-min", paramInsertion, newPath); paramInsertion = AppendQueryPart(this.EndDate, "updated-max", paramInsertion, newPath); paramInsertion = AppendQueryPart(this.MinPublication, "published-min", paramInsertion, newPath); paramInsertion = AppendQueryPart(this.MaxPublication, "published-max", paramInsertion, newPath); paramInsertion = AppendQueryPart(this.StartIndex, 0, "start-index", paramInsertion, newPath); paramInsertion = AppendQueryPart(this.NumberToRetrieve, 0, "max-results", paramInsertion, newPath); paramInsertion = AppendQueryPart(this.OAuthRequestorId, "xoauth_requestor_id", paramInsertion, newPath); if (Utilities.IsPersistable(this.ExtraParameters)) { newPath.Append(paramInsertion); newPath.Append(ExtraParameters); } return(newPath.ToString()); }
/// <summary>standard constructor</summary> public AtomFeedParser(IVersionAware v) : base() { Tracing.TraceCall("constructing AtomFeedParser"); this.nameTable = new AtomParserNameTable(); this.nameTable.InitAtomParserNameTable(); this.versionInfo = new VersionInformation(v); }
///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// /// <summary>default constructor</summary> /// <param name="uriBase">the location the feed was loaded from</param> /// <param name="service">the service used to create this feed</param> ////////////////////////////////////////////////////////////////////// public AtomFeed(Uri uriBase, IService service) : base() { Tracing.TraceCall("Constructing AtomFeed"); if (uriBase != null) { this.ImpliedBase = new AtomUri(uriBase.AbsoluteUri); } this.Service = service; NewExtensionElement += new ExtensionElementEventHandler(this.OnNewExtensionsElement); }
/// <summary>parses an xml stream to create an AtomCategory object</summary> /// <param name="reader">correctly positioned xmlreader</param> /// <param name="owner">the object containing the person</param> /// <returns> the created AtomCategory object</returns> protected AtomCategory ParseCategory(XmlReader reader, AtomBase owner) { Tracing.TraceCall(); Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } if (owner == null) { throw new ArgumentNullException("owner"); } AtomCategory category = owner.CreateAtomSubElement(reader, this) as AtomCategory; if (category != null) { bool noChildren = reader.IsEmptyElement; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { object localname = reader.LocalName; if (localname.Equals(this.nameTable.Term)) { category.Term = Utilities.DecodedValue(reader.Value); } else if (localname.Equals(this.nameTable.Scheme)) { category.Scheme = new AtomUri(reader.Value); } else if (localname.Equals(this.nameTable.Label)) { category.Label = Utilities.DecodedValue(reader.Value); } else { ParseBaseAttributes(reader, category); } } } if (!noChildren) { reader.MoveToElement(); int lvl = -1; while (NextChildElement(reader, ref lvl)) { ParseExtensionElements(reader, category); } } } return(category); }
/// <summary>Parses the base attributes and puts the rest in extensions. /// This needs to happen AFTER known attributes are parsed.</summary> /// <param name="reader">correctly positioned xmlreader</param> /// <param name="baseObject">the base object to set the property on</param> /// <returns> true if an unknown attribute was found</returns> protected bool ParseBaseAttributes(XmlReader reader, AtomBase baseObject) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } Tracing.Assert(baseObject != null, "baseObject should not be null"); if (baseObject == null) { throw new ArgumentNullException("baseObject"); } bool fRet = false; fRet = true; object localName = reader.LocalName; Tracing.TraceCall(); if (IsCurrentNameSpace(reader, BaseNameTable.NSXml)) { if (localName.Equals(this.nameTable.Base)) { baseObject.Base = new AtomUri(reader.Value); fRet = false; } else if (localName.Equals(this.nameTable.Language)) { baseObject.Language = Utilities.DecodedValue(reader.Value); fRet = false; } } else if (IsCurrentNameSpace(reader, BaseNameTable.gNamespace)) { ISupportsEtag se = baseObject as ISupportsEtag; if (se != null) { if (localName.Equals(this.nameTable.ETag)) { se.Etag = reader.Value; fRet = false; } } } if (fRet == true) { Tracing.TraceInfo("Found an unknown attribute"); this.OnNewExtensionElement(reader, baseObject); } return(fRet); }
/// <summary>parses an AtomTextConstruct</summary> /// <param name="reader">the xmlreader correctly positioned at the construct </param> /// <param name="owner">the container element</param> /// <returns>the new text construct </returns> protected AtomTextConstruct ParseTextConstruct(XmlReader reader, AtomBase owner) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } if (owner == null) { throw new System.ArgumentNullException("owner"); } Tracing.TraceCall("Parsing atomTextConstruct"); AtomTextConstruct construct = owner.CreateAtomSubElement(reader, this) as AtomTextConstruct; if (reader.NodeType == XmlNodeType.Element) { if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { object attributeName = reader.LocalName; if (attributeName.Equals(this.nameTable.Type)) { construct.Type = (AtomTextConstructType)Enum.Parse( typeof(AtomTextConstructType), Utilities.DecodedValue(reader.Value), true); } else { ParseBaseAttributes(reader, construct); } } } reader.MoveToElement(); switch (construct.Type) { case AtomTextConstructType.html: case AtomTextConstructType.text: construct.Text = Utilities.DecodedValue(reader.ReadString()); break; case AtomTextConstructType.xhtml: default: construct.Text = reader.ReadInnerXml(); break; } } return(construct); }
/// <summary>the basic interface. Take a URI and just get it</summary> /// <param name="queryUri">the URI to execute</param> /// <param name="ifModifiedSince">used to set a precondition date that /// indicates the feed should be returned only if it has been modified /// after the specified date. A value of DateTime.MinValue indicates no /// precondition.</param> /// <param name="etag">used to set a precondition etag that /// indicates the feed should be returned only if it has been modified </param> /// <param name="contentLength">returns the content length of the response</param> /// <returns> a webresponse object</returns> private Stream Query(Uri queryUri, DateTime ifModifiedSince, string etag, out long contentLength) { Tracing.TraceCall("Enter"); if (queryUri == null) { throw new System.ArgumentNullException("queryUri"); } contentLength = -1; IGDataRequest request = this.RequestFactory.CreateRequest(GDataRequestType.Query, queryUri); request.Credentials = this.Credentials; request.IfModifiedSince = ifModifiedSince; if (etag != null) { ISupportsEtag ise = request as ISupportsEtag; if (ise != null) { ise.Etag = etag; } } try { request.Execute(); } catch (Exception) { // Prevent connection leaks if (request.GetResponseStream() != null) { request.GetResponseStream().Close(); } throw; } // return the response GDataGAuthRequest gr = request as GDataGAuthRequest; if (gr != null) { contentLength = gr.ContentLength; } Tracing.TraceCall("Exit"); return(new GDataReturnStream(request)); }
/// <summary>parses an author/person object</summary> /// <param name="reader"> an XmlReader positioned at the start of the author</param> /// <param name="owner">the object containing the person</param> /// <returns> the created author object</returns> protected AtomPerson ParsePerson(XmlReader reader, AtomBase owner) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } Tracing.Assert(owner != null, "owner should not be null"); if (owner == null) { throw new ArgumentNullException("owner"); } Tracing.TraceCall(); object localname = null; AtomPerson author = owner.CreateAtomSubElement(reader, this) as AtomPerson; ParseBasicAttributes(reader, author); int lvl = -1; while (NextChildElement(reader, ref lvl)) { localname = reader.LocalName; if (localname.Equals(this.nameTable.Name)) { // author.Name = Utilities.DecodeString(Utilities.DecodedValue(reader.ReadString())); author.Name = Utilities.DecodedValue(reader.ReadString()); reader.Read(); } else if (localname.Equals(this.nameTable.Uri)) { author.Uri = new AtomUri(Utilities.DecodedValue(reader.ReadString())); reader.Read(); } else if (localname.Equals(this.nameTable.Email)) { author.Email = Utilities.DecodedValue(reader.ReadString()); reader.Read(); } else { // default extension parsing. ParseExtensionElements(reader, author); } } return(author); }
///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// /// <summary>Event chaining. We catch this by the baseFeedParsers, which /// would not do anything with the gathered data. We pass the event up /// to the user; if the user doesn't discard it, we add the entry to our /// collection</summary> /// <param name="sender"> the object which send the event</param> /// <param name="e">FeedParserEventArguments, holds the feed entry</param> /// <returns> </returns> ////////////////////////////////////////////////////////////////////// protected void OnNewExtensionElement(object sender, ExtensionElementEventArgs e) { // by default, if our event chain is not hooked, the underlying parser will add it Tracing.TraceCall("received new extension element notification"); Tracing.Assert(e != null, "e should not be null"); if (e == null) { throw new ArgumentNullException("e"); } if (this.NewExtensionElement != null) { Tracing.TraceMsg("\t calling event dispatcher"); this.NewExtensionElement(sender, e); } }
static public void TraceCall(string msg) { // puts out the callstack and the msg StackTrace trace = new StackTrace(); if (trace != null && trace.FrameCount > 1) { StackFrame frame = trace.GetFrame(1); Tracing.TraceCall(msg, frame, trace.FrameCount); } else { Tracing.TraceCall(msg, null, 0); } }
/// <summary>starts the parsing process</summary> /// <param name="streamInput">input stream to parse </param> /// <param name="feed">the basefeed object that should be set</param> public override void Parse(Stream streamInput, AtomFeed feed) { Tracing.TraceCall("feedparser starts parsing"); try { XmlReader reader = new XmlTextReader(streamInput, this.nameTable.Nametable); MoveToStartElement(reader); ParseFeed(reader, feed); } catch (Exception e) { throw new ClientFeedException("Parsing failed", e); } }
///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// /// <summary>Event chaining. We catch this by the baseFeedParsers, which /// would not do anything with the gathered data. We pass the event up /// to the user; if the user doesn't discard it, we add the entry to our /// collection</summary> /// <param name="sender"> the object which send the event</param> /// <param name="e">FeedParserEventArguments, holds the feed entry</param> /// <returns> </returns> ////////////////////////////////////////////////////////////////////// protected void OnParsedNewEntry(object sender, FeedParserEventArgs e) { // by default, if our event chain is not hooked, add it to the collection Tracing.TraceCall("received new item notification"); Tracing.Assert(e != null, "e should not be null"); if (e == null) { throw new ArgumentNullException("e"); } if (this.NewAtomEntry != null) { Tracing.TraceMsg("\t calling event dispatcher"); this.NewAtomEntry(this, e); } // now check the return if (!e.DiscardEntry) { if (!e.CreatingEntry) { if (e.Entry != null) { // add it to the collection Tracing.TraceMsg("\t new AtomEntry found, adding to collection"); e.Entry.Service = this.Service; this.Entries.Add(e.Entry); } else if (e.Feed != null) { // parsed a feed, set ourselves to it... Tracing.TraceMsg("\t Feed parsed found, parsing is done..."); } } else { IVersionAware v = e.Entry as IVersionAware; if (v != null) { v.ProtocolMajor = this.ProtocolMajor; v.ProtocolMinor = this.ProtocolMinor; } } } if (e.DoneParsing) { this.BaseUriChanged(this.ImpliedBase); } }
///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// /// <summary>default constructor</summary> /// <param name="originalFeed">if you want to create a copy feed, for batch use, e.g</param> ////////////////////////////////////////////////////////////////////// public AtomFeed(AtomFeed originalFeed) : base() { if (originalFeed == null) { throw new ArgumentNullException("originalFeed"); } Tracing.TraceCall("Constructing AtomFeed"); this.Batch = originalFeed.Batch; this.Post = originalFeed.Post; this.Self = originalFeed.Self; this.Feed = originalFeed.Feed; this.Service = originalFeed.Service; this.ImpliedBase = originalFeed.ImpliedBase; }
/// <summary>executes the query and returns an AtomFeed object tree</summary> /// <param name="feedQuery">the query parameters as a FeedQuery object </param> /// <returns>AtomFeed object tree</returns> public AtomFeed Query(FeedQuery feedQuery) { AtomFeed feed = null; Tracing.TraceCall("Enter"); if (feedQuery == null) { throw new System.ArgumentNullException("feedQuery", "The query argument MUST not be null"); } // Create a new request to the Uri in the query object... Uri targetUri = null; try { targetUri = feedQuery.Uri; } catch (System.UriFormatException) { throw new System.ArgumentException("The query argument MUST contain a valid Uri", "feedQuery"); } Tracing.TraceInfo("Service:Query - about to query"); Stream responseStream = null; if (feedQuery.Etag != null) { responseStream = Query(targetUri, feedQuery.Etag); } else { responseStream = Query(targetUri, feedQuery.ModifiedSince); } Tracing.TraceInfo("Service:Query - query done"); if (responseStream != null) { feed = CreateAndParseFeed(responseStream, feedQuery.Uri); } Tracing.TraceCall("Exit"); return(feed); }
/// <summary>parses an AtomGenerator</summary> /// <param name="reader">the xmlreader correctly positioned at the generator </param> /// <param name="owner">the container element</param> /// <returns> </returns> protected AtomGenerator ParseGenerator(XmlReader reader, AtomBase owner) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } if (owner == null) { throw new ArgumentNullException("owner"); } Tracing.TraceCall(); AtomGenerator generator = owner.CreateAtomSubElement(reader, this) as AtomGenerator; if (generator != null) { generator.Text = Utilities.DecodedValue(reader.ReadString()); if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { object attributeName = reader.LocalName; if (attributeName.Equals(this.nameTable.Uri)) { generator.Uri = new AtomUri(reader.Value); } else if (attributeName.Equals(this.nameTable.Version)) { generator.Version = Utilities.DecodedValue(reader.Value); } else { ParseBaseAttributes(reader, generator); } } } } return(generator); }
/// <summary>tries to parse a category collection document</summary> /// <param name="reader"> xmlReader positioned at the start element</param> /// <param name="owner">the base object that the collection belongs to</param> /// <returns></returns> public AtomCategoryCollection ParseCategories(XmlReader reader, AtomBase owner) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } AtomCategoryCollection ret = new AtomCategoryCollection(); MoveToStartElement(reader); Tracing.TraceCall("entering Categories Parser"); object localname = reader.LocalName; Tracing.TraceInfo("localname is: " + reader.LocalName); if (IsCurrentNameSpace(reader, BaseNameTable.AppPublishingNamespace(owner)) && localname.Equals(this.nameTable.Categories)) { Tracing.TraceInfo("Found categories document"); int depth = -1; while (NextChildElement(reader, ref depth)) { localname = reader.LocalName; if (IsCurrentNameSpace(reader, BaseNameTable.NSAtom)) { if (localname.Equals(this.nameTable.Category)) { AtomCategory category = ParseCategory(reader, owner); ret.Add(category); } } } } else { Tracing.TraceInfo("ParseCategories called and nothing was parsed" + localname); throw new ClientFeedException("An invalid Atom Document was passed to the parser. This was not an app:categories document: " + localname); } return(ret); }
/// <summary>parses a baselink object, like AtomId, AtomLogo, or AtomIcon</summary> /// <param name="reader"> correctly positioned xmlreader</param> /// <param name="baseLink">the base object to set the property on</param> /// <returns> </returns> protected void ParseBaseLink(XmlReader reader, AtomBaseLink baseLink) { Tracing.TraceCall(); Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } Tracing.Assert(baseLink != null, "baseLink should not be null"); if (baseLink == null) { throw new ArgumentNullException("baseLink"); } ParseBasicAttributes(reader, baseLink); if (reader.NodeType == XmlNodeType.Element) { // read the element content baseLink.Uri = new AtomUri(Utilities.DecodedValue(reader.ReadString())); } }
/// <summary>reads in the feed properties, updates the feed object, then starts /// working on the entries...</summary> /// <param name="reader"> xmlReader positioned at the Feed element</param> /// <param name="feed">the basefeed object that should be set</param> /// <returns> notifies user using event mechanism</returns> protected void ParseFeed(XmlReader reader, AtomFeed feed) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } Tracing.Assert(feed != null, "feed should not be null"); if (feed == null) { throw new ArgumentNullException("feed"); } Tracing.TraceCall("entering AtomFeed Parser"); object localname = reader.LocalName; Tracing.TraceInfo("localname is: " + reader.LocalName); if (localname.Equals(this.nameTable.Feed)) { Tracing.TraceInfo("Found standard feed document"); // found the feed...... // now parse the source base of this element ParseSource(reader, feed); // feed parsing complete, send notfication this.OnNewAtomEntry(feed); } else if (localname.Equals(this.nameTable.Entry)) { Tracing.TraceInfo("Found entry document"); ParseEntry(reader); } else { Tracing.TraceInfo("ParseFeed called and nothing was parsed" + localname.ToString()); // throw new ClientFeedException("An invalid Atom Document was passed to the parser. Neither Feed nor Entry started the document"); } OnParsingDone(); feed.MarkElementDirty(false); }
////////////////////////////////////////////////////////////////////// /// <summary>initializes the name table for use with atom parsing. This is the /// only place where strings are defined for parsing</summary> ////////////////////////////////////////////////////////////////////// public override void InitAtomParserNameTable() { // create the nametable object by calling the base base.InitAtomParserNameTable(); Tracing.TraceCall("Initializing atom nametable support"); // <summary>add the keywords for the Feed</summary> this.feed = this.Nametable.Add(AtomParserNameTable.XmlFeedElement); this.version = this.Nametable.Add(AtomParserNameTable.XmlAttributeVersion); this.source = this.Nametable.Add(AtomParserNameTable.XmlSourceElement); this.entry = this.Nametable.Add(AtomParserNameTable.XmlAtomEntryElement); this.title = this.Nametable.Add(AtomParserNameTable.XmlTitleElement); this.link = this.Nametable.Add(AtomParserNameTable.XmlLinkElement); this.id = this.Nametable.Add(AtomParserNameTable.XmlIdElement); this.href = this.Nametable.Add(AtomParserNameTable.XmlAttributeHRef); this.rel = this.Nametable.Add(AtomParserNameTable.XmlAttributeRel); this.hreflang = this.Nametable.Add(AtomParserNameTable.XmlAttributeHRefLang); this.length = this.Nametable.Add(AtomParserNameTable.XmlAttributeLength); this.updated = this.Nametable.Add(AtomParserNameTable.XmlUpdatedElement); this.published = this.Nametable.Add(AtomParserNameTable.XmlPublishedElement); this.author = this.Nametable.Add(AtomParserNameTable.XmlAuthorElement); this.contributor = this.Nametable.Add(AtomParserNameTable.XmlContributorElement); this.rights = this.Nametable.Add(AtomParserNameTable.XmlRightsElement); this.category = this.Nametable.Add(AtomParserNameTable.XmlCategoryElement); this.term = this.Nametable.Add(AtomParserNameTable.XmlAttributeTerm); this.scheme = this.Nametable.Add(AtomParserNameTable.XmlAttributeScheme); this.label = this.Nametable.Add(AtomParserNameTable.XmlAttributeLabel); this.summary = this.Nametable.Add(AtomParserNameTable.XmlSummaryElement); this.content = this.Nametable.Add(AtomParserNameTable.XmlContentElement); this.src = this.Nametable.Add(AtomParserNameTable.XmlAttributeSrc); this.uri = this.Nametable.Add(AtomParserNameTable.XmlUriElement); this.generator = this.Nametable.Add(AtomParserNameTable.XmlGeneratorElement); this.email = this.Nametable.Add(AtomParserNameTable.XmlEmailElement); this.icon = this.Nametable.Add(AtomParserNameTable.XmlIconElement); this.logo = this.Nametable.Add(AtomParserNameTable.XmlLogoElement); this.subTitle = this.Nametable.Add(AtomParserNameTable.XmlSubtitleElement); this.categories = this.Nametable.Add(AtomParserNameTable.XmlCategoriesElement); }
///////////////////////////////////////////////////////////////////////////// #endregion ////////////////////////////////////////////////////////////////////// /// <summary>given a stream, parses it to construct the Feed object out of it</summary> /// <param name="stream"> a stream representing hopefully valid XML</param> /// <param name="format"> indicates if the stream is Atom or Rss</param> ////////////////////////////////////////////////////////////////////// public void Parse(Stream stream, AlternativeFormat format) { Tracing.TraceCall("parsing stream -> Start:" + format.ToString()); BaseFeedParser feedParser = null; // make sure we reset our collections this.Authors.Clear(); this.Contributors.Clear(); this.Links.Clear(); this.Categories.Clear(); feedParser = new AtomFeedParser(this); // create a new delegate for the parser feedParser.NewAtomEntry += new FeedParserEventHandler(this.OnParsedNewEntry); feedParser.NewExtensionElement += new ExtensionElementEventHandler(this.OnNewExtensionElement); feedParser.Parse(stream, this); Tracing.TraceInfo("Parsing stream -> Done"); // done parsing }
/// <summary>creates an AtomContent object by parsing an xml stream</summary> /// <param name="reader">a XMLReader positioned correctly </param> /// <param name="owner">the container element</param> /// <returns> null or an AtomContent object</returns> protected AtomContent ParseContent(XmlReader reader, AtomBase owner) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } if (owner == null) { throw new ArgumentNullException("owner"); } AtomContent content = owner.CreateAtomSubElement(reader, this) as AtomContent; Tracing.TraceCall(); if (content != null) { if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { object localname = reader.LocalName; if (localname.Equals(this.nameTable.Type)) { content.Type = Utilities.DecodedValue(reader.Value); } else if (localname.Equals(this.nameTable.Src)) { content.Src = new AtomUri(reader.Value); } else { ParseBaseAttributes(reader, content); } } } if (MoveToStartElement(reader)) { if (content.Type.Equals("text") || content.Type.Equals("html") || content.Type.StartsWith("text/")) { // if it's text it get's just the string treatment. No // subelements are allowed here content.Content = Utilities.DecodedValue(reader.ReadString()); } else if (content.Type.Equals("xhtml") || content.Type.Contains("/xml") || content.Type.Contains("+xml")) { // do not get childlists if the element is empty. That would skip to the next element if (!reader.IsEmptyElement) { // everything else will be nodes in the extension element list // different media type. Create extension elements int lvl = -1; while (NextChildElement(reader, ref lvl)) { ParseExtensionElements(reader, content); } } } else { // everything else SHOULD be base 64 encoded, so one big string // i know the if statement could be combined with the text handling // but i consider it clearer to make a 3 cases statement than combine them content.Content = Utilities.DecodedValue(reader.ReadString()); } } } return(content); }
/// <summary>creates an atomlink object</summary> /// <param name="reader">correctly positioned xmlreader</param> /// <param name="owner">the object containing the person</param> /// <returns> the created AtomLink object</returns> protected AtomLink ParseLink(XmlReader reader, AtomBase owner) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } if (owner == null) { throw new ArgumentNullException("owner"); } bool noChildren = reader.IsEmptyElement; Tracing.TraceCall(); AtomLink link = owner.CreateAtomSubElement(reader, this) as AtomLink; object localname = null; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { localname = reader.LocalName; if (localname.Equals(this.nameTable.HRef)) { link.HRef = new AtomUri(reader.Value); } else if (localname.Equals(this.nameTable.Rel)) { link.Rel = Utilities.DecodedValue(reader.Value); } else if (localname.Equals(this.nameTable.Type)) { link.Type = Utilities.DecodedValue(reader.Value); } else if (localname.Equals(this.nameTable.HRefLang)) { link.HRefLang = Utilities.DecodedValue(reader.Value); } else if (localname.Equals(this.nameTable.Title)) { link.Title = Utilities.DecodedValue(reader.Value); } else if (localname.Equals(this.nameTable.Length)) { link.Length = int.Parse(Utilities.DecodedValue(reader.Value), CultureInfo.InvariantCulture); } else { ParseBaseAttributes(reader, link); } } } if (!noChildren) { reader.MoveToElement(); int lvl = -1; while (NextChildElement(reader, ref lvl)) { ParseExtensionElements(reader, link); } } return(link); }
/// <summary>reads one of the feed entries at a time</summary> /// <param name="reader"> XmlReader positioned at the entry element</param> /// <returns> notifies user using event mechanism</returns> public void ParseEntry(XmlReader reader) { Tracing.Assert(reader != null, "reader should not be null"); if (reader == null) { throw new ArgumentNullException("reader"); } object localname = reader.LocalName; Tracing.TraceCall("Parsing atom entry"); if (localname.Equals(this.nameTable.Entry) == false) { throw new ClientFeedException("trying to parse an atom entry, but reader is not at the right spot"); } AtomEntry entry = OnCreateNewEntry(); ParseBasicAttributes(reader, entry); // remember the depth of entry int depth = -1; while (NextChildElement(reader, ref depth)) { localname = reader.LocalName; if (IsCurrentNameSpace(reader, BaseNameTable.NSAtom)) { if (localname.Equals(this.nameTable.Id)) { entry.Id = entry.CreateAtomSubElement(reader, this) as AtomId; ParseBaseLink(reader, entry.Id); } else if (localname.Equals(this.nameTable.Link)) { entry.Links.Add(ParseLink(reader, entry)); } else if (localname.Equals(this.nameTable.Updated)) { entry.Updated = DateTime.Parse(Utilities.DecodedValue(reader.ReadString()), CultureInfo.InvariantCulture); } else if (localname.Equals(this.nameTable.Published)) { entry.Published = DateTime.Parse(Utilities.DecodedValue(reader.ReadString()), CultureInfo.InvariantCulture); } else if (localname.Equals(this.nameTable.Author)) { entry.Authors.Add(ParsePerson(reader, entry)); } else if (localname.Equals(this.nameTable.Contributor)) { entry.Contributors.Add(ParsePerson(reader, entry)); } else if (localname.Equals(this.nameTable.Rights)) { entry.Rights = ParseTextConstruct(reader, entry); } else if (localname.Equals(this.nameTable.Category)) { AtomCategory category = ParseCategory(reader, entry); entry.Categories.Add(category); } else if (localname.Equals(this.nameTable.Summary)) { entry.Summary = ParseTextConstruct(reader, entry); } else if (localname.Equals(this.nameTable.Content)) { entry.Content = ParseContent(reader, entry); } else if (localname.Equals(this.nameTable.Source)) { entry.Source = entry.CreateAtomSubElement(reader, this) as AtomSource; ParseSource(reader, entry.Source); } else if (localname.Equals(this.nameTable.Title)) { entry.Title = ParseTextConstruct(reader, entry); } // all parse methods should leave the reader at the end of their element reader.Read(); } else if (IsCurrentNameSpace(reader, BaseNameTable.gBatchNamespace)) { // parse the google batch extensions if they are there ParseBatch(reader, entry); } else { // default extension parsing ParseExtensionElements(reader, entry); } } OnNewAtomEntry(entry); return; }
////////////////////////////////////////////////////////////////////// /// <summary>Parses an xml node to create an instance of this object.</summary> /// <param name="node">the xml parses node, can be NULL</param> /// <param name="parser">the xml parser to use if we need to dive deeper</param> /// <returns>the created IExtensionElement object</returns> ////////////////////////////////////////////////////////////////////// public virtual IExtensionElementFactory CreateInstance(XmlNode node, AtomFeedParser parser) { Tracing.TraceCall(); return(new XmlExtension(node)); }
/// <summary>Executes the request and prepares the response stream. Also /// does error checking</summary> public virtual void Execute() { try { EnsureWebRequest(); // if we ever handed out a stream, we want to close it before doing the real excecution if (this.requestStream != null) { this.requestStream.Close(); } Tracing.TraceCall("calling the real execution over the webresponse"); LogRequest(this.webRequest); this.webResponse = this.webRequest.GetResponse(); } catch (WebException e) { Tracing.TraceCall("GDataRequest::Execute failed: " + this.targetUri.ToString()); GDataRequestException gde = new GDataRequestException("Execution of request failed: " + this.targetUri.ToString(), e); throw gde; } if (this.webResponse != null) { this.responseStream = this.webResponse.GetResponseStream(); } LogResponse(this.webResponse); if (this.webResponse is HttpWebResponse) { HttpWebResponse response = this.webResponse as HttpWebResponse; HttpWebRequest request = this.webRequest as HttpWebRequest; this.useGZip = (string.Compare(response.ContentEncoding, "gzip", true, CultureInfo.InvariantCulture) == 0); if (this.useGZip) { this.responseStream = new GZipStream(this.responseStream, CompressionMode.Decompress); } Tracing.Assert(response != null, "The response should not be NULL"); Tracing.Assert(request != null, "The request should not be NULL"); int code = (int)response.StatusCode; Tracing.TraceMsg("Returned ContentType is: " + (response.ContentType == null ? "None" : response.ContentType) + " from URI : " + request.RequestUri.ToString());; Tracing.TraceMsg("Returned StatusCode is: " + response.StatusCode + code); if (response.StatusCode == HttpStatusCode.Forbidden) { // that could imply that we need to reauthenticate Tracing.TraceMsg("need to reauthenticate"); throw new GDataForbiddenException("Execution of request returned HttpStatusCode.Forbidden: " + this.targetUri.ToString() + response.StatusCode.ToString(), this.webResponse); } if (response.StatusCode == HttpStatusCode.Conflict) { // a put went bad due to a version conflict throw new GDataVersionConflictException("Execution of request returned HttpStatusCode.Conflict: " + this.targetUri.ToString() + response.StatusCode.ToString(), this.webResponse); } if ((this.IfModifiedSince != DateTime.MinValue || this.Etag != null) && response.StatusCode == HttpStatusCode.NotModified) { // Throw an exception for conditional GET throw new GDataNotModifiedException("Content not modified: " + this.targetUri.ToString(), this.webResponse); } if (response.StatusCode == HttpStatusCode.Redirect || response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.RedirectKeepVerb) { Tracing.TraceMsg("throwing for redirect"); throw new GDataRedirectException("Execution resulted in a redirect from " + this.targetUri.ToString(), this.webResponse); } if (code > 299) { // treat everything else over 300 as errors throw new GDataRequestException("Execution of request returned unexpected result: " + this.targetUri.ToString() + response.StatusCode.ToString(), this.webResponse); } this.contentLength = response.ContentLength; // if we got an etag back, remember it this.eTag = response.Headers[GDataRequestFactory.EtagHeader]; response = null; request = null; } }
/// <summary>Executes the request and prepares the response stream. Also /// does error checking</summary> /// <param name="retryCounter">indicates the n-th time this is run</param> protected void Execute(int retryCounter) { Tracing.TraceCall("GoogleAuth: Execution called"); try { CopyRequestData(); base.Execute(); if (this.Response is HttpWebResponse) { HttpWebResponse response = this.Response as HttpWebResponse; this.responseVersion = new VersionInformation(response.Headers[GDataGAuthRequestFactory.GDataVersion]); } } catch (GDataForbiddenException) { Tracing.TraceMsg("need to reauthenticate, got a forbidden back"); // do it again, once, reset AuthToken first and streams first Reset(); this.factory.GAuthToken = null; CopyRequestData(); base.Execute(); } catch (GDataRedirectException re) { // we got a redirect. Tracing.TraceMsg("Got a redirect to: " + re.Location); // only reset the base, the auth cookie is still valid // and cookies are stored in the factory if (this.factory.StrictRedirect) { HttpWebRequest http = this.Request as HttpWebRequest; if (http != null) { // only redirect for GET, else throw if (http.Method != HttpMethods.Get) { throw; } } } // verify that there is a non empty location string if (re.Location.Trim().Length == 0) { throw; } Reset(); this.TargetUri = new Uri(re.Location); CopyRequestData(); base.Execute(); } catch (GDataRequestException re) { HttpWebResponse webResponse = re.Response as HttpWebResponse; if (webResponse != null && webResponse.StatusCode != HttpStatusCode.InternalServerError) { Tracing.TraceMsg("Not a server error. Possibly a Bad request or forbidden resource."); Tracing.TraceMsg("We don't want to retry non 500 errors."); throw; } if (retryCounter > this.factory.NumberOfRetries) { Tracing.TraceMsg("Number of retries exceeded"); throw; } Tracing.TraceMsg("Let's retry this"); // only reset the base, the auth cookie is still valid // and cookies are stored in the factory Reset(); this.Execute(retryCounter + 1); } catch (Exception e) { Tracing.TraceCall("*** EXCEPTION " + e.GetType().Name + " CAUGHT ***"); throw; } finally { if (this.requestCopy != null) { this.requestCopy.Close(); this.requestCopy = null; } } }