AppendVertexXmlNode ( String sTag, GraphMLXmlDocument oGraphMLXmlDocument, Dictionary <String, XmlNode> oTagDictionary ) { Debug.Assert(!String.IsNullOrEmpty(sTag)); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oTagDictionary != null); if (!oTagDictionary.ContainsKey(sTag)) { XmlNode oVertexXmlNode = oGraphMLXmlDocument.AppendVertexXmlNode( sTag); oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, NodeXLGraphMLUtil.VertexLabelID, sTag); oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, NodeXLGraphMLUtil.VertexMenuTextID, "Open Flickr Page for This Tag"); oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, NodeXLGraphMLUtil.VertexMenuActionID, String.Format( "http://www.flickr.com/photos/tags/{0}/" , UrlUtil.EncodeUrlParameter(sTag) )); oTagDictionary.Add(sTag, oVertexXmlNode); } }
EncodeUrlParameter ( String urlParameter ) { Debug.Assert(urlParameter != null); // From the YouTube documentation: // // "To URL escape a string, convert each sequence of whitespace // characters to a single "+" (plus sign) and replace any other // nonalphanumeric characters with the hexadecimal encoding that // represents the value of that character." // Compress whitespace into a single space. urlParameter = Regex.Replace(urlParameter, "\\s+", " "); // Use .NET's URL encoding. urlParameter = UrlUtil.EncodeUrlParameter(urlParameter); // That converted each space to "%20". Convert that to the plus sign // YouTube expects. urlParameter = urlParameter.Replace("%20", "+"); return (urlParameter); }
FlickrScreenNameToUserID ( String sScreenNameAnyCase, String sApiKey, RequestStatistics oRequestStatistics, out String sUserID, out String sScreenNameCorrectCase ) { Debug.Assert(!String.IsNullOrEmpty(sScreenNameAnyCase)); Debug.Assert(!String.IsNullOrEmpty(sApiKey)); Debug.Assert(oRequestStatistics != null); AssertValid(); XmlDocument oXmlDocument = GetXmlDocument( GetFlickrMethodUrl("flickr.people.findByUsername", sApiKey, "&username="******"rsp/user/@nsid", null); sScreenNameCorrectCase = XmlUtil2.SelectRequiredSingleNodeAsString( oXmlDocument, "rsp/user/username/text()", null); }
GetCommentersEnumerator ( String sUserID, Int32 iMaximumPerRequest, Boolean bSkipMostPage1Errors, String sApiKey, RequestStatistics oRequestStatistics ) { Debug.Assert(!String.IsNullOrEmpty(sUserID)); Debug.Assert(iMaximumPerRequest > 0); Debug.Assert(!String.IsNullOrEmpty(sApiKey)); Debug.Assert(oRequestStatistics != null); AssertValid(); // Get the user's public photos, which are paged. String sUrl = GetFlickrMethodUrl("flickr.people.getPublicPhotos", sApiKey, GetUserIDUrlParameter(sUserID)); foreach (XmlNode oPhotoXmlNode in EnumerateXmlNodes(sUrl, "rsp/photos/photo", iMaximumPerRequest, bSkipMostPage1Errors, oRequestStatistics)) { String sPhotoID; if (!XmlUtil2.TrySelectSingleNodeAsString(oPhotoXmlNode, "@id", null, out sPhotoID)) { continue; } // Get the photo's comments, which are not paged. ReportProgress(String.Format( "Getting comments for the photo \"{0}\"." , sPhotoID )); sUrl = GetFlickrMethodUrl("flickr.photos.comments.getList", sApiKey, "&photo_id=" + UrlUtil.EncodeUrlParameter(sPhotoID) ); XmlDocument oXmlDocument; if (TryGetXmlDocument(sUrl, oRequestStatistics, out oXmlDocument)) { foreach (XmlNode oCommentXmlNode in oXmlDocument.SelectNodes( "rsp/comments/comment")) { yield return(oCommentXmlNode); } } } }
GetUserIDUrlParameter ( String sUserID ) { Debug.Assert(!String.IsNullOrEmpty(sUserID)); AssertValid(); return("&user_id=" + UrlUtil.EncodeUrlParameter(sUserID)); }
TryGetSampleImageUrl ( String sTag, String sApiKey, RequestStatistics oRequestStatistics, out String sSampleImageUrl ) { Debug.Assert(!String.IsNullOrEmpty(sTag)); Debug.Assert(!String.IsNullOrEmpty(sApiKey)); Debug.Assert(oRequestStatistics != null); AssertValid(); sSampleImageUrl = null; String sUrl = GetFlickrMethodUrl("flickr.tags.getClusterPhotos", sApiKey, "&tag=" + UrlUtil.EncodeUrlParameter(sTag)); XmlDocument oXmlDocument; String sPhotoID; if ( !TryGetXmlDocument(sUrl, oRequestStatistics, out oXmlDocument) || !XmlUtil2.TrySelectSingleNodeAsString(oXmlDocument, "rsp/photos/photo/@id", null, out sPhotoID) ) { return(false); } sUrl = GetFlickrMethodUrl("flickr.photos.getSizes", sApiKey, "&photo_id=" + UrlUtil.EncodeUrlParameter(sPhotoID)); if ( !TryGetXmlDocument(sUrl, oRequestStatistics, out oXmlDocument) || !XmlUtil2.TrySelectSingleNodeAsString(oXmlDocument, "rsp/sizes/size[@label='Thumbnail']/@source", null, out sSampleImageUrl) ) { return(false); } return(true); }
GetRelatedTagsRecursive ( String sTag, WhatToInclude eWhatToInclude, NetworkLevel eNetworkLevel, String sApiKey, Int32 iRecursionLevel, GraphMLXmlDocument oGraphMLXmlDocument, Dictionary <String, XmlNode> oTagDictionary, RequestStatistics oRequestStatistics ) { Debug.Assert(!String.IsNullOrEmpty(sTag)); Debug.Assert(eNetworkLevel == NetworkLevel.One || eNetworkLevel == NetworkLevel.OnePointFive || eNetworkLevel == NetworkLevel.Two); Debug.Assert(!String.IsNullOrEmpty(sApiKey)); Debug.Assert(iRecursionLevel == 1 || iRecursionLevel == 2); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oTagDictionary != null); Debug.Assert(oRequestStatistics != null); AssertValid(); /* * Here is what this method should do, based on the eNetworkLevel and * iRecursionLevel parameters. * * eNetworkLevel * |One | OnePointFive | Two * ---|------------------| ------------------| ----------------- * i 1 |Add all vertices. | Add all vertices. | Add all vertices. * R | | | * e |Add all edges. | Add all edges. | Add all edges. * c | | | * u |Do not recurse. | Recurse. | Recurse. * r | | | * s ---|------------------|-------------------|------------------ * i 2 |Impossible. | Do not add | Add all vertices. * o | | vertices. | * n | | | * L | | Add edges only if | Add all edges. * e | | vertices are | * v | | already included. | * e | | | * l | | Do not recurse. | Do not recurse. | | | | ---|------------------|-------------------|------------------ */ Boolean bNeedToRecurse = GetNeedToRecurse(eNetworkLevel, iRecursionLevel); Boolean bNeedToAppendVertices = GetNeedToAppendVertices( eNetworkLevel, iRecursionLevel); ReportProgress("Getting tags related to \"" + sTag + "\"."); String sUrl = GetFlickrMethodUrl("flickr.tags.getRelated", sApiKey, "&tag=" + UrlUtil.EncodeUrlParameter(sTag)); XmlDocument oXmlDocument; try { oXmlDocument = GetXmlDocument(sUrl, oRequestStatistics); } catch (Exception oException) { // If the exception is not a WebException or XmlException, or if // none of the network has been obtained yet, throw the exception. if (!HttpSocialNetworkUtil.ExceptionIsWebOrXml(oException) || !oGraphMLXmlDocument.HasVertexXmlNode) { throw oException; } return; } // The document consists of a single "tags" node with zero or more // "tag" child nodes. String sOtherTag = null; XmlNodeList oTagNodes = oXmlDocument.DocumentElement.SelectNodes( "tags/tag"); if (oTagNodes.Count > 0) { AppendVertexXmlNode(sTag, oGraphMLXmlDocument, oTagDictionary); } foreach (XmlNode oTagNode in oTagNodes) { sOtherTag = XmlUtil2.SelectRequiredSingleNodeAsString(oTagNode, "text()", null); if (bNeedToAppendVertices) { AppendVertexXmlNode(sOtherTag, oGraphMLXmlDocument, oTagDictionary); } if (bNeedToAppendVertices || oTagDictionary.ContainsKey(sOtherTag)) { oGraphMLXmlDocument.AppendEdgeXmlNode(sTag, sOtherTag); } } if (bNeedToRecurse) { foreach (XmlNode oTagNode in oTagNodes) { sOtherTag = XmlUtil2.SelectRequiredSingleNodeAsString(oTagNode, "text()", null); GetRelatedTagsRecursive(sOtherTag, eWhatToInclude, eNetworkLevel, sApiKey, 2, oGraphMLXmlDocument, oTagDictionary, oRequestStatistics); } } }
AppendVertexXmlNodes ( String sSearchTerm, WhatToInclude eWhatToInclude, Int32 iMaximumPeoplePerRequest, GraphMLXmlDocument oGraphMLXmlDocument, Dictionary <String, TwitterVertex> oScreenNameDictionary, RequestStatistics oRequestStatistics ) { Debug.Assert(!String.IsNullOrEmpty(sSearchTerm)); Debug.Assert(iMaximumPeoplePerRequest > 0); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oScreenNameDictionary != null); Debug.Assert(oRequestStatistics != null); AssertValid(); // Convert spaces in the search term to a plus sign. // // (Note: Don't try to use Twitter's "show_user" URL parameter in an // attempt to get a "user" XML node for each author. That's not what // the URL parameter does.) String sUrl = String.Format( "http://search.twitter.com/search.atom?q={0}&rpp=100" , UrlUtil.EncodeUrlParameter(sSearchTerm).Replace("%20", "+") ); ReportProgress("Getting a list of tweets."); Boolean bIncludeStatistics = WhatToIncludeFlagIsSet( eWhatToInclude, WhatToInclude.Statistics); Boolean bIncludeStatuses = WhatToIncludeFlagIsSet( eWhatToInclude, WhatToInclude.Statuses); // The document consists of an "entry" XML node for each tweet that // contains the search term. Multiple tweets may have the same author, // so we have to enumerate until the requested maximum number of unique // authors is reached. foreach (XmlNode oAuthorNameXmlNode in EnumerateXmlNodes( sUrl, "a:feed/a:entry/a:author/a:name", "a", AtomNamespaceUri, 15, Int32.MaxValue, true, false, oRequestStatistics)) { if (oScreenNameDictionary.Count == iMaximumPeoplePerRequest) { break; } // The author name is in this format: // // james_laker (James Laker) String sAuthorName; if (!XmlUtil2.TrySelectSingleNodeAsString(oAuthorNameXmlNode, "text()", null, out sAuthorName)) { continue; } Int32 iIndexOfSpace = sAuthorName.IndexOf(' '); String sScreenName = sAuthorName; if (iIndexOfSpace != -1) { sScreenName = sAuthorName.Substring(0, iIndexOfSpace); } sScreenName = sScreenName.ToLower(); TwitterVertex oTwitterVertex; if (!TryAppendVertexXmlNode(sScreenName, null, oGraphMLXmlDocument, oScreenNameDictionary, bIncludeStatistics, false, out oTwitterVertex)) { // A tweet for the author has already been found. continue; } XmlNode oVertexXmlNode = oTwitterVertex.VertexXmlNode; XmlNode oEntryXmlNode = oAuthorNameXmlNode.ParentNode.ParentNode; XmlNamespaceManager oXmlNamespaceManager = new XmlNamespaceManager( oEntryXmlNode.OwnerDocument.NameTable); oXmlNamespaceManager.AddNamespace("a", AtomNamespaceUri); // Get the image URL and status for the tweet's author. AppendStringGraphMLAttributeValue(oEntryXmlNode, "a:link[@rel='image']/@href", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, ImageFileID); String sStatus; if (XmlUtil2.TrySelectSingleNodeAsString(oEntryXmlNode, "a:title/text()", oXmlNamespaceManager, out sStatus)) { String sStatusDateUtc; if (XmlUtil2.TrySelectSingleNodeAsString(oEntryXmlNode, "a:published/text()", oXmlNamespaceManager, out sStatusDateUtc)) { sStatusDateUtc = TwitterDateParser.ParseTwitterDate( sStatusDateUtc); } oTwitterVertex.StatusForAnalysis = sStatus; oTwitterVertex.StatusForAnalysisDateUtc = sStatusDateUtc; if (bIncludeStatuses) { oGraphMLXmlDocument.AppendGraphMLAttributeValue( oVertexXmlNode, StatusID, sStatus); if (!String.IsNullOrEmpty(sStatusDateUtc)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue( oVertexXmlNode, StatusDateUtcID, sStatusDateUtc); } } } } }