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); } }
TryAppendVertexXmlNode ( String sUserName, XmlNode oEntryXmlNode, GraphMLXmlDocument oGraphMLXmlDocument, Dictionary <String, XmlNode> oUserNameDictionary ) { Debug.Assert(!String.IsNullOrEmpty(sUserName)); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oUserNameDictionary != null); XmlNode oVertexXmlNode; if (oUserNameDictionary.TryGetValue(sUserName, out oVertexXmlNode)) { return(false); } oVertexXmlNode = oGraphMLXmlDocument.AppendVertexXmlNode(sUserName); oUserNameDictionary.Add(sUserName, oVertexXmlNode); oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, NodeXLGraphMLUtil.VertexMenuTextID, "Open YouTube Page for This Person"); oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, NodeXLGraphMLUtil.VertexMenuActionID, String.Format(WebPageUrlPattern, sUserName)); return(true); }
AppendDoubleGraphMLAttributeValue ( XmlNode oXmlNodeToSelectFrom, String sXPath, XmlNamespaceManager oXmlNamespaceManager, GraphMLXmlDocument oGraphMLXmlDocument, XmlNode oEdgeOrVertexXmlNode, String sGraphMLAttributeID ) { Debug.Assert(oXmlNodeToSelectFrom != null); Debug.Assert(!String.IsNullOrEmpty(sXPath)); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oEdgeOrVertexXmlNode != null); Debug.Assert(!String.IsNullOrEmpty(sGraphMLAttributeID)); AssertValid(); Double dAttributeValue; if (XmlUtil2.TrySelectSingleNodeAsDouble(oXmlNodeToSelectFrom, sXPath, oXmlNamespaceManager, out dAttributeValue)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue( oEdgeOrVertexXmlNode, sGraphMLAttributeID, dAttributeValue); return(true); } return(false); }
AppendSampleThumbnails ( Dictionary <String, XmlNode> oTagDictionary, GraphMLXmlDocument oGraphMLXmlDocument, String sApiKey, RequestStatistics oRequestStatistics ) { Debug.Assert(oTagDictionary != null); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(!String.IsNullOrEmpty(sApiKey)); Debug.Assert(oRequestStatistics != null); AssertValid(); foreach (KeyValuePair <String, XmlNode> oKeyValuePair in oTagDictionary) { String sTag = oKeyValuePair.Key; ReportProgress("Getting sample image file for \"" + sTag + "\"."); String sSampleImageUrl; if (TryGetSampleImageUrl(sTag, sApiKey, oRequestStatistics, out sSampleImageUrl)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue( oKeyValuePair.Value, NodeXLGraphMLUtil.VertexImageFileID, sSampleImageUrl); } } }
AppendValueFromValueDictionary ( Dictionary <String, Object> valueDictionary, String name, GraphMLXmlDocument graphMLXmlDocument, XmlNode edgeOrVertexXmlNode, String graphMLAttributeID ) { Debug.Assert(valueDictionary != null); Debug.Assert(!String.IsNullOrEmpty(name)); Debug.Assert(graphMLXmlDocument != null); Debug.Assert(edgeOrVertexXmlNode != null); Debug.Assert(!String.IsNullOrEmpty(graphMLAttributeID)); String value; if (TwitterJsonUtil.TryGetJsonValueFromDictionary( valueDictionary, name, out value)) { graphMLXmlDocument.AppendGraphMLAttributeValue( edgeOrVertexXmlNode, graphMLAttributeID, value); return(true); } return(false); }
AppendYouTubeDateGraphMLAttributeValue ( XmlNode oXmlNodeToSelectFrom, String sXPath, XmlNamespaceManager oXmlNamespaceManager, GraphMLXmlDocument oGraphMLXmlDocument, XmlNode oVertexXmlNode, String sGraphMLAttributeID ) { Debug.Assert(oXmlNodeToSelectFrom != null); Debug.Assert( !String.IsNullOrEmpty(sXPath) ); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oVertexXmlNode != null); Debug.Assert( !String.IsNullOrEmpty(sGraphMLAttributeID) ); AssertValid(); String sYouTubeDate; if ( XmlUtil2.TrySelectSingleNodeAsString(oXmlNodeToSelectFrom, sXPath, oXmlNamespaceManager, out sYouTubeDate) ) { oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, sGraphMLAttributeID, FormatYouTubeDate(sYouTubeDate) ); return (true); } return (false); }
AppendGraphMLAttributeValues ( IMetadataProvider oEdgeOrVertex, GraphMLXmlDocument oGraphMLXmlDocument, XmlNode oEdgeOrVertexXmlNode, String [] asAttributeNames, String AttributeIDPrefix ) { Debug.Assert(oEdgeOrVertex != null); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oEdgeOrVertexXmlNode != null); Debug.Assert(asAttributeNames != null); Debug.Assert(!String.IsNullOrEmpty(AttributeIDPrefix)); AssertValid(); foreach (String sAttributeName in asAttributeNames) { Object oAttributeValue; // Note that the value type isn't checked. Whatever type it is, // it gets converted to a string. if (oEdgeOrVertex.TryGetValue(sAttributeName, out oAttributeValue) && oAttributeValue != null) { oGraphMLXmlDocument.AppendGraphMLAttributeValue( oEdgeOrVertexXmlNode, AttributeIDPrefix + sAttributeName, oAttributeValue.ToString()); } } }
AppendUserStatisticsFromValueDictionary ( Dictionary <String, Object> userValueDictionary, GraphMLXmlDocument graphMLXmlDocument, TwitterUser twitterUser ) { Debug.Assert(userValueDictionary != null); Debug.Assert(graphMLXmlDocument != null); Debug.Assert(twitterUser != null); XmlNode vertexXmlNode = twitterUser.VertexXmlNode; AppendValueFromValueDictionary(userValueDictionary, "friends_count", graphMLXmlDocument, vertexXmlNode, VertexFollowedID); AppendValueFromValueDictionary(userValueDictionary, "followers_count", graphMLXmlDocument, vertexXmlNode, VertexFollowersID); AppendValueFromValueDictionary(userValueDictionary, "statuses_count", graphMLXmlDocument, vertexXmlNode, VertexStatusesID); AppendValueFromValueDictionary(userValueDictionary, "favourites_count", graphMLXmlDocument, vertexXmlNode, VertexFavoritesID); AppendValueFromValueDictionary(userValueDictionary, "description", graphMLXmlDocument, vertexXmlNode, VertexDescriptionID); AppendValueFromValueDictionary(userValueDictionary, "location", graphMLXmlDocument, vertexXmlNode, VertexLocationID); AppendValueFromValueDictionary(userValueDictionary, "url", graphMLXmlDocument, vertexXmlNode, VertexUrlID); AppendValueFromValueDictionary(userValueDictionary, "time_zone", graphMLXmlDocument, vertexXmlNode, VertexTimeZoneID); AppendValueFromValueDictionary(userValueDictionary, "utc_offset", graphMLXmlDocument, vertexXmlNode, VertexUtcOffsetID); String joinedDateUtc; if (TwitterJsonUtil.TryGetJsonValueFromDictionary(userValueDictionary, "created_at", out joinedDateUtc)) { graphMLXmlDocument.AppendGraphMLAttributeValue( vertexXmlNode, VertexJoinedDateUtcID, TwitterDateParser.ParseTwitterDate(joinedDateUtc)); } }
AppendEdgesFromDictionary ( Dictionary <String, LinkedList <String> > oDictionary, GraphMLXmlDocument oGraphMLXmlDocument, String sRelationship, String sKeyAttributeID ) { Debug.Assert(oDictionary != null); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(!String.IsNullOrEmpty(sRelationship)); Debug.Assert(!String.IsNullOrEmpty(sKeyAttributeID)); AssertValid(); // For each key... foreach (KeyValuePair <String, LinkedList <String> > oKeyValuePair in oDictionary) { String sKey = oKeyValuePair.Key; // For each video ID that has the key... LinkedList <String> oVideoIDsWithThisKey = oKeyValuePair.Value; for ( LinkedListNode <String> oVideoIDWithThisKey = oVideoIDsWithThisKey.First; oVideoIDWithThisKey != null; oVideoIDWithThisKey = oVideoIDWithThisKey.Next ) { // For each of the subsequent video IDs in the LinkedList that // have the key... for ( LinkedListNode <String> oSubsequentVideoIDWithThisKey = oVideoIDWithThisKey.Next; oSubsequentVideoIDWithThisKey != null; oSubsequentVideoIDWithThisKey = oSubsequentVideoIDWithThisKey.Next ) { XmlNode oEdgeXmlNode = NodeXLGraphMLUtil.AppendEdgeXmlNode( oGraphMLXmlDocument, oVideoIDWithThisKey.Value, oSubsequentVideoIDWithThisKey.Value, sRelationship); oGraphMLXmlDocument.AppendGraphMLAttributeValue( oEdgeXmlNode, sKeyAttributeID, sKey); } } } }
TryAppendVertexXmlNode ( String screenName, String userID, GraphMLXmlDocument graphMLXmlDocument, Dictionary <String, TwitterUser> userIDDictionary, out TwitterUser twitterUser ) { Debug.Assert(!String.IsNullOrEmpty(screenName)); Debug.Assert(!String.IsNullOrEmpty(userID)); Debug.Assert(graphMLXmlDocument != null); Debug.Assert(userIDDictionary != null); twitterUser = null; if (userIDDictionary.TryGetValue(userID, out twitterUser)) { // A vertex XML node already exists. return(false); } XmlNode vertexXmlNode = graphMLXmlDocument.AppendVertexXmlNode( screenName); twitterUser = new TwitterUser(screenName, vertexXmlNode); userIDDictionary.Add(userID, twitterUser); graphMLXmlDocument.AppendGraphMLAttributeValue(vertexXmlNode, NodeXLGraphMLUtil.VertexMenuTextID, "Open Twitter Page for This Person"); graphMLXmlDocument.AppendGraphMLAttributeValue( vertexXmlNode, NodeXLGraphMLUtil.VertexMenuActionID, String.Format(TwitterApiUrls.UserWebPageUrlPattern, screenName) ); return(true); }
AppendLatitudeAndLongitudeGraphMLAttributeValues ( GraphMLXmlDocument graphMLXmlDocument, XmlNode edgeOrVertexXmlNode, String latitude, String longitude ) { Debug.Assert(graphMLXmlDocument != null); Debug.Assert(edgeOrVertexXmlNode != null); if (!String.IsNullOrEmpty(latitude)) { graphMLXmlDocument.AppendGraphMLAttributeValue( edgeOrVertexXmlNode, LatitudeID, latitude); } if (!String.IsNullOrEmpty(longitude)) { graphMLXmlDocument.AppendGraphMLAttributeValue( edgeOrVertexXmlNode, LongitudeID, longitude); } }
AppendTweetedSearchTermGraphMLAttributeValue ( GraphMLXmlDocument graphMLXmlDocument, TwitterUser twitterUser, Boolean userTweetedSearchTerm ) { Debug.Assert(graphMLXmlDocument != null); Debug.Assert(twitterUser != null); graphMLXmlDocument.AppendGraphMLAttributeValue( twitterUser.VertexXmlNode, VertexTweetedSearchTermID, userTweetedSearchTerm ? "Yes" : "No"); }
AppendStartTimeRelationshipDateUtcGraphMLAttributeValue ( GraphMLXmlDocument oGraphMLXmlDocument, XmlNode oEdgeXmlNode, RequestStatistics oRequestStatistics ) { Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oEdgeXmlNode != null); Debug.Assert(oRequestStatistics != null); AssertValid(); oGraphMLXmlDocument.AppendGraphMLAttributeValue(oEdgeXmlNode, TwitterGraphMLUtil.EdgeRelationshipDateUtcID, DateTimeUtil2.ToCultureInvariantString( oRequestStatistics.StartTimeUtc) ); }
AppendEdgeXmlNode ( GraphMLXmlDocument graphMLXmlDocument, String vertex1ID, String vertex2ID, String relationship ) { Debug.Assert(graphMLXmlDocument != null); Debug.Assert(!String.IsNullOrEmpty(vertex1ID)); Debug.Assert(!String.IsNullOrEmpty(vertex2ID)); Debug.Assert(!String.IsNullOrEmpty(relationship)); XmlNode edgeXmlNode = graphMLXmlDocument.AppendEdgeXmlNode( vertex1ID, vertex2ID); graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, EdgeRelationshipID, relationship); return(edgeXmlNode); }
AppendInReplyToStatusIDGraphMLAttributeValue ( GraphMLXmlDocument graphMLXmlDocument, XmlNode edgeOrVertexXmlNode, String inReplyToStatusID ) { Debug.Assert(graphMLXmlDocument != null); Debug.Assert(edgeOrVertexXmlNode != null); if (!String.IsNullOrEmpty(inReplyToStatusID)) { // Precede the ID with a single quote to force Excel to treat the // ID as text. Otherwise, it formats the ID, which is a large // number, in scientific notation. graphMLXmlDocument.AppendGraphMLAttributeValue( edgeOrVertexXmlNode, InReplyToStatusIDID, "'" + inReplyToStatusID); } }
AppendEdgeXmlNode ( GraphMLXmlDocument oGraphMLXmlDocument, String sVertex1ID, String sVertex2ID, String sRelationship ) { Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(!String.IsNullOrEmpty(sVertex1ID)); Debug.Assert(!String.IsNullOrEmpty(sVertex2ID)); Debug.Assert(!String.IsNullOrEmpty(sRelationship)); AssertValid(); XmlNode oEdgeXmlNode = oGraphMLXmlDocument.AppendEdgeXmlNode( sVertex1ID, sVertex2ID); oGraphMLXmlDocument.AppendGraphMLAttributeValue(oEdgeXmlNode, RelationshipID, sRelationship); return(oEdgeXmlNode); }
AppendVertexTooltipXmlNodes ( GraphMLXmlDocument graphMLXmlDocument, Dictionary <String, TwitterUser> userIDDictionary ) { Debug.Assert(graphMLXmlDocument != null); Debug.Assert(userIDDictionary != null); foreach (TwitterUser twitterUser in userIDDictionary.Values) { // The tooltip is the user's screen name followed by the first // tweet returned by Twitter. ICollection <TwitterStatus> statuses = twitterUser.Statuses; String firstStatus = statuses.Count > 0 ? statuses.First().Text : String.Empty; // The Excel template doesn't wrap long tooltip text. Break the // status into lines so the entire tooltip will show in the graph // pane. firstStatus = StringUtil.BreakIntoLines(firstStatus, 30); String toolTip = String.Format( "{0}\n\n{1}" , twitterUser.ScreenName, firstStatus ); graphMLXmlDocument.AppendGraphMLAttributeValue( twitterUser.VertexXmlNode, VertexToolTipID, toolTip); } }
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); } } } } }
AppendRepliesToAndMentionsEdgeXmlNode ( GraphMLXmlDocument graphMLXmlDocument, String screenName1, String screenName2, String relationship, TwitterStatus twitterStatus ) { Debug.Assert(graphMLXmlDocument != null); Debug.Assert(!String.IsNullOrEmpty(screenName1)); Debug.Assert(!String.IsNullOrEmpty(screenName2)); Debug.Assert(!String.IsNullOrEmpty(relationship)); Debug.Assert(twitterStatus != null); XmlNode edgeXmlNode = NodeXLGraphMLUtil.AppendEdgeXmlNode( graphMLXmlDocument, screenName1, screenName2, relationship); String statusDateUtc = twitterStatus.ParsedDateUtc; Boolean hasStatusDateUtc = !String.IsNullOrEmpty(statusDateUtc); if (hasStatusDateUtc) { // The status's date is the relationship date. graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, EdgeRelationshipDateUtcID, statusDateUtc); } String statusText = twitterStatus.Text; graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, EdgeStatusID, statusText); String urls = twitterStatus.Urls; if (!String.IsNullOrEmpty(urls)) { graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, EdgeStatusUrlsID, urls); graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, EdgeStatusDomainsID, UrlsToDomains(urls)); } if (!String.IsNullOrEmpty(twitterStatus.Hashtags)) { graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, EdgeStatusHashtagsID, twitterStatus.Hashtags); } if (hasStatusDateUtc) { graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, EdgeStatusDateUtcID, statusDateUtc); } graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, EdgeStatusWebPageUrlID, FormatStatusWebPageUrl(screenName1, twitterStatus) ); AppendLatitudeAndLongitudeGraphMLAttributeValues( graphMLXmlDocument, edgeXmlNode, twitterStatus.Latitude, twitterStatus.Longitude); // Precede the ID with a single quote to force Excel to treat the // ID as text. Otherwise, it formats the ID, which is a large // number, in scientific notation. graphMLXmlDocument.AppendGraphMLAttributeValue(edgeXmlNode, NodeXLGraphMLUtil.ImportedIDID, "'" + twitterStatus.ID); AppendInReplyToStatusIDGraphMLAttributeValue(graphMLXmlDocument, edgeXmlNode, twitterStatus.InReplyToStatusID); }
AppendLatestStatusInformationFromValueDictionary ( Dictionary <String, Object> oStatusValueDictionary, GraphMLXmlDocument oGraphMLXmlDocument, TwitterUser oTwitterUser, Boolean bIncludeLatestStatus, Boolean bExpandLatestStatusUrls ) { Debug.Assert(oStatusValueDictionary != null); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oTwitterUser != null); AssertValid(); TwitterStatus oTwitterStatus; if (!TwitterStatus.TryFromStatusValueDictionary( oStatusValueDictionary, bExpandLatestStatusUrls, out oTwitterStatus)) { return; } XmlNode oVertexXmlNode = oTwitterUser.VertexXmlNode; if (bIncludeLatestStatus) { // Add the status to the vertex XML node. oGraphMLXmlDocument.AppendGraphMLAttributeValue( oVertexXmlNode, TwitterGraphMLUtil.VertexLatestStatusID, oTwitterStatus.Text); String sLatestStatusUrls = oTwitterStatus.Urls; if (!String.IsNullOrEmpty(sLatestStatusUrls)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue( oVertexXmlNode, TwitterGraphMLUtil.VertexLatestStatusUrlsID, sLatestStatusUrls); oGraphMLXmlDocument.AppendGraphMLAttributeValue( oVertexXmlNode, TwitterGraphMLUtil.VertexLatestStatusDomainsID, TwitterGraphMLUtil.UrlsToDomains(sLatestStatusUrls)); } String sLatestStatusHashtags = oTwitterStatus.Hashtags; if (!String.IsNullOrEmpty(sLatestStatusHashtags)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue( oVertexXmlNode, TwitterGraphMLUtil.VertexLatestStatusHashtagsID, sLatestStatusHashtags); } if (!String.IsNullOrEmpty(oTwitterStatus.ParsedDateUtc)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue( oVertexXmlNode, TwitterGraphMLUtil.VertexLatestStatusDateUtcID, oTwitterStatus.ParsedDateUtc); } TwitterGraphMLUtil. AppendLatitudeAndLongitudeGraphMLAttributeValues( oGraphMLXmlDocument, oVertexXmlNode, oTwitterStatus.Latitude, oTwitterStatus.Longitude); TwitterGraphMLUtil.AppendInReplyToStatusIDGraphMLAttributeValue( oGraphMLXmlDocument, oVertexXmlNode, oTwitterStatus.InReplyToStatusID); } oTwitterUser.Statuses.Add(oTwitterStatus); }
AppendVertexXmlNodes ( String sSearchTerm, WhatToInclude eWhatToInclude, Int32 iMaximumVideos, GraphMLXmlDocument oGraphMLXmlDocument, RequestStatistics oRequestStatistics, out HashSet <String> oVideoIDs, out Dictionary <String, LinkedList <String> > oCategoryDictionary ) { Debug.Assert(!String.IsNullOrEmpty(sSearchTerm)); Debug.Assert(iMaximumVideos > 0); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oRequestStatistics != null); AssertValid(); ReportProgress("Getting a list of videos."); // This is used to skip duplicate videos in the results returned by // YouTube. (I'm not sure why YouTube sometimes returns duplicates, // but it does.) oVideoIDs = new HashSet <String>(); // If an edge should be included for each pair of videos that share the // same category, the key is a lower-case category and the value is a // LinkedList of the video IDs that have the category. if (WhatToIncludeFlagIsSet(eWhatToInclude, WhatToInclude.SharedCategoryEdges)) { oCategoryDictionary = new Dictionary <String, LinkedList <String> >(); } else { oCategoryDictionary = null; } String sUrl = String.Format( "http://gdata.youtube.com/feeds/api/videos?q={0}" , EncodeUrlParameter(sSearchTerm) ); // The document consists of an "entry" XML node for each video. foreach (XmlNode oEntryXmlNode in EnumerateXmlNodes(sUrl, "a:feed/a:entry", iMaximumVideos, false, oRequestStatistics)) { XmlNamespaceManager oXmlNamespaceManager = CreateXmlNamespaceManager(oEntryXmlNode.OwnerDocument); // Use the video ID as the GraphML vertex name. The video title // can't be used because it is not unique. String sVideoID; if ( !XmlUtil2.TrySelectSingleNodeAsString(oEntryXmlNode, "media:group/yt:videoid/text()", oXmlNamespaceManager, out sVideoID) || oVideoIDs.Contains(sVideoID) ) { continue; } oVideoIDs.Add(sVideoID); XmlNode oVertexXmlNode = oGraphMLXmlDocument.AppendVertexXmlNode( sVideoID); AppendStringGraphMLAttributeValue(oEntryXmlNode, "a:title/text()", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, TitleID); AppendStringGraphMLAttributeValue(oEntryXmlNode, "a:author/a:name/text()", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, AuthorID); AppendDoubleGraphMLAttributeValue(oEntryXmlNode, "gd:rating/@average", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, RatingID); AppendInt32GraphMLAttributeValue(oEntryXmlNode, "yt:statistics/@viewCount", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, ViewsID); AppendInt32GraphMLAttributeValue(oEntryXmlNode, "yt:statistics/@favoriteCount", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, FavoritedID); AppendInt32GraphMLAttributeValue(oEntryXmlNode, "gd:comments/gd:feedLink/@countHint", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, CommentsID); AppendYouTubeDateGraphMLAttributeValue(oEntryXmlNode, "a:published/text()", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, CreatedDateUtcID); AppendStringGraphMLAttributeValue(oEntryXmlNode, "media:group/media:thumbnail/@url", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, NodeXLGraphMLUtil.VertexImageFileID); if (AppendStringGraphMLAttributeValue(oEntryXmlNode, "media:group/media:player/@url", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, NodeXLGraphMLUtil.VertexMenuActionID)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, NodeXLGraphMLUtil.VertexMenuTextID, "Play Video in Browser"); } if (oCategoryDictionary != null) { CollectCategories(oEntryXmlNode, sVideoID, oXmlNamespaceManager, oCategoryDictionary); } } }
AppendUserInformationGraphMLAttributeValues ( String sUserID, XmlNode oVertexXmlNode, GraphMLXmlDocument oGraphMLXmlDocument, String sApiKey, RequestStatistics oRequestStatistics ) { Debug.Assert(!String.IsNullOrEmpty(sUserID)); Debug.Assert(oVertexXmlNode != null); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(!String.IsNullOrEmpty(sApiKey)); Debug.Assert(oRequestStatistics != null); AssertValid(); String sUrl = GetFlickrMethodUrl("flickr.people.getInfo", sApiKey, GetUserIDUrlParameter(sUserID)); XmlDocument oXmlDocument; if (!TryGetXmlDocument(sUrl, oRequestStatistics, out oXmlDocument)) { // Ignore errors. The user information isn't critical. return; } const String XPathRoot = "rsp/person/"; AppendStringGraphMLAttributeValue(oXmlDocument, XPathRoot + "realname/text()", null, oGraphMLXmlDocument, oVertexXmlNode, RealNameID); AppendInt32GraphMLAttributeValue(oXmlDocument, XPathRoot + "photos/count/text()", null, oGraphMLXmlDocument, oVertexXmlNode, TotalPhotosID); String sIsProfessional; if (XmlUtil2.TrySelectSingleNodeAsString(oXmlDocument, XPathRoot + "@ispro", null, out sIsProfessional)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, IsProfessionalID, (sIsProfessional == "0") ? "No" : "Yes" ); } // Get the URL to the user's buddy icon, which is explained here: // // http://www.flickr.com/services/api/misc.buddyicons.html Int32 iIconServer, iIconFarm; String sBuddyIconUrl; if ( XmlUtil2.TrySelectSingleNodeAsInt32(oXmlDocument, XPathRoot + "@iconserver", null, out iIconServer) && XmlUtil2.TrySelectSingleNodeAsInt32(oXmlDocument, XPathRoot + "@iconfarm", null, out iIconFarm) && iIconServer > 0 ) { sBuddyIconUrl = String.Format( "http://farm{0}.static.flickr.com/{1}/buddyicons/{2}.jpg" , iIconFarm, iIconServer, sUserID ); } else { sBuddyIconUrl = "http://www.flickr.com/images/buddyicon.jpg"; } oGraphMLXmlDocument.AppendGraphMLAttributeValue( oVertexXmlNode, ImageFileID, sBuddyIconUrl); if (AppendStringGraphMLAttributeValue(oXmlDocument, XPathRoot + "photosurl/text()", null, oGraphMLXmlDocument, oVertexXmlNode, MenuActionID)) { oGraphMLXmlDocument.AppendGraphMLAttributeValue(oVertexXmlNode, MenuTextID, "Open Flickr Page for This Person"); } }
GetUserNetworkRecursive ( String sUserID, String sScreenName, WhatToInclude eWhatToInclude, Boolean bIncludeContactsThisCall, NetworkLevel eNetworkLevel, Int32 iMaximumPerRequest, String sApiKey, Int32 iRecursionLevel, GraphMLXmlDocument oGraphMLXmlDocument, Dictionary <String, XmlNode> oUserIDDictionary, RequestStatistics oRequestStatistics ) { Debug.Assert(!String.IsNullOrEmpty(sUserID)); Debug.Assert(!String.IsNullOrEmpty(sScreenName)); Debug.Assert(eNetworkLevel == NetworkLevel.One || eNetworkLevel == NetworkLevel.OnePointFive || eNetworkLevel == NetworkLevel.Two); Debug.Assert(iMaximumPerRequest > 0); Debug.Assert(!String.IsNullOrEmpty(sApiKey)); Debug.Assert(iRecursionLevel == 1 || iRecursionLevel == 2); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oUserIDDictionary != 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); List <String> oUserIDsToRecurse = new List <String>(); ReportProgressForContactsOrCommenters(sScreenName, bIncludeContactsThisCall); Boolean bThisUserAppended = false; foreach (XmlNode oChildXmlNode in GetContactsOrCommentersEnumerator( sUserID, bIncludeContactsThisCall, iMaximumPerRequest, oGraphMLXmlDocument, sApiKey, oRequestStatistics)) { String sOtherScreenName, sOtherUserID; if ( !XmlUtil2.TrySelectSingleNodeAsString(oChildXmlNode, bIncludeContactsThisCall ? "@username" : "@authorname", null, out sOtherScreenName) || !XmlUtil2.TrySelectSingleNodeAsString(oChildXmlNode, bIncludeContactsThisCall ? "@nsid" : "@author", null, out sOtherUserID) ) { continue; } if (!bThisUserAppended) { // Append a vertex node for this request's user. // // This used to be done after the foreach loop, which avoided // the need for a "bThisUserAppended" flag. That caused the // following bug: If a YouTube error occurred within // EnumerateXmlNodes() after some edges had been added, and the // user decided to import the resulting partial network, the // GraphML might contain edges that referenced "this user" // without containing a vertex for "this user." That is an // illegal state for GraphML, which the ExcelTemplate project // caught and reported as an error. TryAppendVertexXmlNode(sUserID, sScreenName, oGraphMLXmlDocument, oUserIDDictionary); bThisUserAppended = true; } if (bNeedToAppendVertices) { if ( TryAppendVertexXmlNode(sOtherUserID, sOtherScreenName, oGraphMLXmlDocument, oUserIDDictionary) && bNeedToRecurse ) { oUserIDsToRecurse.Add(sOtherUserID); } } if (bNeedToAppendVertices || oUserIDDictionary.ContainsKey(sOtherUserID)) { // Append an edge node and optional attributes. XmlNode oEdgeXmlNode; if (bIncludeContactsThisCall) { oEdgeXmlNode = AppendEdgeXmlNode(oGraphMLXmlDocument, sScreenName, sOtherScreenName, "Contact"); } else { // (Note the swapping of screen names in the commenter // case.) oEdgeXmlNode = AppendEdgeXmlNode(oGraphMLXmlDocument, sOtherScreenName, sScreenName, "Commenter"); UInt32 uCommentDateUtc; if (XmlUtil2.TrySelectSingleNodeAsUInt32(oChildXmlNode, "@datecreate", null, out uCommentDateUtc)) { DateTime oCommentDateUtc = DateTimeUtil2.UnixTimestampToDateTimeUtc( uCommentDateUtc); oGraphMLXmlDocument.AppendGraphMLAttributeValue( oEdgeXmlNode, CommentDateUtcID, ExcelDateTimeUtil.DateTimeToStringLocale1033( oCommentDateUtc, ExcelColumnFormat.DateAndTime) ); } AppendStringGraphMLAttributeValue(oChildXmlNode, "@permalink", null, oGraphMLXmlDocument, oEdgeXmlNode, CommentUrlID); } } } if (bNeedToRecurse) { foreach (String sUserIDToRecurse in oUserIDsToRecurse) { XmlNode oVertexXmlNode = oUserIDDictionary[sUserIDToRecurse]; String sScreenNameToRecurse = GetScreenNameFromVertexXmlNode( oVertexXmlNode); GetUserNetworkRecursive(sUserIDToRecurse, sScreenNameToRecurse, eWhatToInclude, bIncludeContactsThisCall, eNetworkLevel, iMaximumPerRequest, sApiKey, 2, oGraphMLXmlDocument, oUserIDDictionary, oRequestStatistics); } } }