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); }
GetTwitterSearchNetworkConfiguration ( out String searchTerm, out TwitterSearchNetworkAnalyzer.WhatToInclude whatToInclude, out Int32 maximumPeoplePerRequest, out String networkFileFolderPath, out NetworkFileFormats networkFileFormats, out Boolean automateNodeXLWorkbook ) { AssertValid(); Debug.Assert(m_oNetworkConfigurationXmlDocument != null); Debug.Assert(GetNetworkType() == NetworkType.TwitterSearch); XmlNode oTwitterSearchNetworkConfigurationNode = XmlUtil2.SelectRequiredSingleNode( m_oNetworkConfigurationXmlDocument, "/NetworkConfiguration/TwitterSearchNetworkConfiguration", null); searchTerm = XmlUtil2.SelectRequiredSingleNodeAsString( oTwitterSearchNetworkConfigurationNode, "SearchTerm/text()", null); whatToInclude = GetRequiredEnumValue <TwitterSearchNetworkAnalyzer.WhatToInclude>( oTwitterSearchNetworkConfigurationNode, "WhatToInclude/text()", "WhatToInclude"); GetTwitterCommonConfiguration(oTwitterSearchNetworkConfigurationNode, out maximumPeoplePerRequest, out networkFileFolderPath, out networkFileFormats, out automateNodeXLWorkbook); }
GetGraphDirectedness ( XmlNode oGraphXmlNode ) { Debug.Assert(oGraphXmlNode != null); AssertValid(); String sEdgeDefault = XmlUtil2.SelectRequiredSingleNodeAsString( oGraphXmlNode, "@edgedefault", null); switch (sEdgeDefault) { case "directed": return(GraphDirectedness.Directed); case "undirected": return(GraphDirectedness.Undirected); default: throw new XmlException( "The \"edgedefault\" attribute on the \"graph\" XML node" + " must be either \"directed\" or \"undirected\"." ); } }
GetVertexCount ( XmlDocument oGraphMLXmlDocument ) { Debug.Assert(oGraphMLXmlDocument != null); AssertValid(); Int32 iVertexCount = 0; XmlNode oXmlNode; XmlNamespaceManager oXmlNamespaceManager = GraphMLXmlDocument.CreateXmlNamespaceManager( oGraphMLXmlDocument, "g"); if (XmlUtil2.TrySelectSingleNode(oGraphMLXmlDocument, "g:graphml/g:graph/g:node", oXmlNamespaceManager, out oXmlNode)) { while (oXmlNode != null) { if (oXmlNode.Name == "node") { iVertexCount++; } oXmlNode = oXmlNode.NextSibling; } } return(iVertexCount); }
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); }
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); }
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); } } } }
ParseEdges ( IGraph oGraph, XmlNode oGraphXmlNode, XmlNamespaceManager oXmlNamespaceManager, Dictionary <String, IVertex> oVertexDictionary, Dictionary <String, GraphMLAttribute> oGraphMLAttributeDictionary ) { Debug.Assert(oGraph != null); Debug.Assert(oGraphXmlNode != null); Debug.Assert(oXmlNamespaceManager != null); Debug.Assert(oVertexDictionary != null); Debug.Assert(oGraphMLAttributeDictionary != null); AssertValid(); IEdgeCollection oEdges = oGraph.Edges; Boolean bGraphIsDirected = (oGraph.Directedness == GraphDirectedness.Directed); foreach (XmlNode oEdgeXmlNode in oGraphXmlNode.SelectNodes( GraphMLPrefix + ":edge", oXmlNamespaceManager)) { IVertex oVertex1, oVertex2; if ( !TryGraphMLNodeIDToVertex(oEdgeXmlNode, "source", oVertexDictionary, out oVertex1) || !TryGraphMLNodeIDToVertex(oEdgeXmlNode, "target", oVertexDictionary, out oVertex2) ) { // From the GraphML Primer: // // For applications which can not handle nested graphs the // fall-back behaviour is to ignore nodes which are not // contained in the top-level graph and to ignore edges which // have do not have both endpoints in the top-level graph. continue; } IEdge oEdge = oEdges.Add(oVertex1, oVertex2, bGraphIsDirected); String sID; if (XmlUtil2.TrySelectSingleNodeAsString(oEdgeXmlNode, "@id", null, out sID)) { oEdge.Name = sID; } ParseGraphMLAttributeValues(oEdgeXmlNode, oXmlNamespaceManager, oEdge, false, oGraphMLAttributeDictionary); } }
YouTubeErrorResponseToMessage ( HttpWebResponse oHttpWebResponse ) { Debug.Assert(oHttpWebResponse != null); AssertValid(); // YouTube provides error information as an XmlDocument. String sMessage = null; XmlDocument oXmlDocument = new XmlDocument(); Stream oStream = null; try { oStream = oHttpWebResponse.GetResponseStream(); oXmlDocument.Load(oStream); } catch (XmlException) { return (null); } finally { if (oStream != null) { oStream.Close(); } } XmlNamespaceManager oXmlNamespaceManager = YouTubeUserNetworkAnalyzer.CreateXmlNamespaceManager(oXmlDocument); // Although the document may contain multiple error nodes, just look at // the first one for now. if ( XmlUtil2.TrySelectSingleNodeAsString(oXmlDocument, "gd:errors/gd:error/gd:code/text()", oXmlNamespaceManager, out sMessage) ) { if (sMessage.IndexOf("too_many_recent_calls") >= 0) { sMessage = "You have made too many YouTube network requests recently." + " Wait a few minutes and try again." ; } } else { sMessage = null; } return (sMessage); }
GetScreenNameFromVertexXmlNode ( XmlNode oVertexXmlNode ) { Debug.Assert(oVertexXmlNode != null); AssertValid(); return(XmlUtil2.SelectRequiredSingleNodeAsString(oVertexXmlNode, "@id", null)); }
GetCommonConfiguration ( XmlNode oParentNode, out String sNetworkFileFolderPath ) { Debug.Assert(oParentNode != null); AssertValid(); sNetworkFileFolderPath = XmlUtil2.SelectRequiredSingleNodeAsString( oParentNode, "NetworkFileFolder/text()", null); }
GetRequiredEnumValue <T> ( XmlNode oNode, String sXPath, String[] asEnumValuesToIgnore, String sValueToUseIfEmpty, String sTagName ) { Debug.Assert(oNode != null); Debug.Assert(!String.IsNullOrEmpty(sXPath)); Debug.Assert(sValueToUseIfEmpty != null); Debug.Assert(!String.IsNullOrEmpty(sTagName)); AssertValid(); Exception oException; try { String sEnumAsString = XmlUtil2.SelectRequiredSingleNodeAsString( oNode, sXPath, null); if (asEnumValuesToIgnore != null) { sEnumAsString = RemoveEnumValues( sEnumAsString, asEnumValuesToIgnore); if (sEnumAsString.Length == 0) { sEnumAsString = sValueToUseIfEmpty; } } return((T)Enum.Parse(typeof(T), sEnumAsString)); } catch (XmlException oXmlException) { oException = oXmlException; } catch (ArgumentException oArgumentException) { oException = oArgumentException; } String sErrorMessage = String.Format( "The {0} value is missing or invalid." , sTagName ); throw new XmlException(sErrorMessage, oException); }
GetXmlDocument ( String sUrl, RequestStatistics oRequestStatistics ) { Debug.Assert(!String.IsNullOrEmpty(sUrl)); Debug.Assert(oRequestStatistics != null); AssertValid(); XmlDocument oXmlDocument = GetXmlDocumentWithRetries(sUrl, HttpStatusCodesToFailImmediately, oRequestStatistics); String sStatus; if ( XmlUtil2.TrySelectSingleNodeAsString(oXmlDocument, "rsp/@stat", null, out sStatus) && sStatus == "ok" ) { return(oXmlDocument); } // Flickr indicates errors by returning an XML document containing an // rsp/err node. The following code turns such an error document into // a custom FlickrException. String sErrorMessage; if (XmlUtil2.TrySelectSingleNodeAsString(oXmlDocument, "rsp/err/@msg", null, out sErrorMessage)) { if (sErrorMessage.ToLower().IndexOf("user not found") >= 0) { sErrorMessage = "The user wasn't found. Either there is no such user, or" + " she has hidden herself from public searches." ; } } else { sErrorMessage = "Flickr provided information in an unrecognized format."; } throw new FlickrException(sErrorMessage); }
ParseVertices ( IGraph oGraph, XmlNode oGraphXmlNode, XmlNamespaceManager oXmlNamespaceManager, Dictionary <String, GraphMLAttribute> oGraphMLAttributeDictionary ) { Debug.Assert(oGraph != null); Debug.Assert(oGraphXmlNode != null); Debug.Assert(oXmlNamespaceManager != null); Debug.Assert(oGraphMLAttributeDictionary != null); AssertValid(); IVertexCollection oVertices = oGraph.Vertices; // The key is the id attribute of the "node" XML node, and the value is // the corresponding IVertex. Dictionary <String, IVertex> oVertexDictionary = new Dictionary <String, IVertex>(); foreach (XmlNode oNodeXmlNode in oGraphXmlNode.SelectNodes( GraphMLPrefix + ":node", oXmlNamespaceManager)) { String sID = XmlUtil2.SelectRequiredSingleNodeAsString( oNodeXmlNode, "@id", null); IVertex oVertex = oVertices.Add(); oVertex.Name = sID; try { oVertexDictionary.Add(sID, oVertex); } catch (ArgumentException) { throw new XmlException( "The id \"" + sID + "\" exists for two \"node\" XML nodes." + " Node id values must be unique." ); } ParseGraphMLAttributeValues(oNodeXmlNode, oXmlNamespaceManager, oVertex, true, oGraphMLAttributeDictionary); } return(oVertexDictionary); }
OnNetworkObtained ( XmlDocument oGraphMLXmlDocument, RequestStatistics oRequestStatistics, String sNetworkDescription, String sNetworkTitle, String sPartialFileName ) { Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oRequestStatistics != null); Debug.Assert(!String.IsNullOrEmpty(sNetworkDescription)); Debug.Assert(!String.IsNullOrEmpty(sNetworkTitle)); Debug.Assert(!String.IsNullOrEmpty(sPartialFileName)); AssertValid(); XmlNode oGraphXmlNode = XmlUtil2.SelectRequiredSingleNode( oGraphMLXmlDocument, "g:graphml/g:graph", GraphMLXmlDocument.CreateXmlNamespaceManager( oGraphMLXmlDocument, "g") ); XmlUtil2.SetAttributes(oGraphXmlNode, "description", sNetworkDescription); XmlUtil2.SetAttributes(oGraphXmlNode, "suggestedTitle", sNetworkTitle); String sSuggestedFileNameNoExtension = String.Format( "{0} NodeXL {1}" , DateTimeUtil2.ToCultureInvariantFileName( oRequestStatistics.StartTimeUtc), sPartialFileName ); XmlUtil2.SetAttributes(oGraphXmlNode, "suggestedFileNameNoExtension", sSuggestedFileNameNoExtension); if (oRequestStatistics.UnexpectedExceptions > 0) { // The network is partial. throw new PartialNetworkException(oGraphMLXmlDocument, oRequestStatistics); } }
LoadGraphCore ( Stream stream ) { Debug.Assert(stream != null); AssertValid(); XmlDocument oXmlDocument = new XmlDocument(); oXmlDocument.Load(stream); XmlNamespaceManager oXmlNamespaceManager = new XmlNamespaceManager( oXmlDocument.NameTable); oXmlNamespaceManager.AddNamespace(GraphMLPrefix, GraphMLUri); XmlNode oGraphMLXmlNode = oXmlDocument.DocumentElement; XmlNode oGraphXmlNode = XmlUtil2.SelectRequiredSingleNode( oGraphMLXmlNode, GraphMLPrefix + ":graph", oXmlNamespaceManager); // Parse the vertex and edge attribute definitions. // // The key is the id attribute of a "key" XML node, and the value is // the corresponding GraphMLAttribute object. Dictionary <String, GraphMLAttribute> oGraphMLAttributeDictionary = ParseGraphMLAttributeDefinitions(oGraphMLXmlNode, oXmlNamespaceManager); GraphDirectedness eGraphDirectedness = GetGraphDirectedness(oGraphXmlNode); IGraph oGraph = new Graph(eGraphDirectedness); // The key is the id attribute of the "node" XML node, and the value is // the corresponding IVertex. Dictionary <String, IVertex> oVertexDictionary = ParseVertices(oGraph, oGraphXmlNode, oXmlNamespaceManager, oGraphMLAttributeDictionary); ParseEdges(oGraph, oGraphXmlNode, oXmlNamespaceManager, oVertexDictionary, oGraphMLAttributeDictionary); SaveGraphMLAttributeNames(oGraph, oGraphMLAttributeDictionary); return(oGraph); }
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); }
GetTwitterCommonConfiguration ( XmlNode oParentNode, out Int32 iMaximumPeoplePerRequest, out String sNetworkFileFolderPath, out NetworkFileFormats eNetworkFileFormats, out Boolean bAutomateNodeXLWorkbook ) { Debug.Assert(oParentNode != null); AssertValid(); String sMaximumPeoplePerRequest; iMaximumPeoplePerRequest = Int32.MaxValue; if (XmlUtil2.TrySelectSingleNodeAsString(oParentNode, "MaximumPeoplePerRequest/text()", null, out sMaximumPeoplePerRequest)) { if (!Int32.TryParse(sMaximumPeoplePerRequest, out iMaximumPeoplePerRequest)) { throw new XmlException( "The MaximumPeoplePerRequest value is not valid." ); } } sNetworkFileFolderPath = XmlUtil2.SelectRequiredSingleNodeAsString( oParentNode, "NetworkFileFolder/text()", null); eNetworkFileFormats = GetRequiredEnumValue <NetworkFileFormats>( oParentNode, "NetworkFileFormats/text()", "NetworkFileFormats"); // The AutomateNodeXLWorkbook node was added in a later version of the // program, so it is not required. if (!XmlUtil2.TrySelectSingleNodeAsBoolean( oParentNode, "AutomateNodeXLWorkbook/text()", null, out bAutomateNodeXLWorkbook)) { bAutomateNodeXLWorkbook = false; } }
TryGraphMLNodeIDToVertex ( XmlNode oEdgeXmlNode, String sSourceOrTarget, Dictionary <String, IVertex> oVertexDictionary, out IVertex oVertex ) { Debug.Assert(oEdgeXmlNode != null); Debug.Assert(!String.IsNullOrEmpty(sSourceOrTarget)); Debug.Assert(oVertexDictionary != null); AssertValid(); String sID = XmlUtil2.SelectRequiredSingleNodeAsString(oEdgeXmlNode, "@" + sSourceOrTarget, null); return(oVertexDictionary.TryGetValue(sID, out oVertex)); }
ParseGraphAttribute ( IGraph oGraph, XmlNode oGraphXmlNode, String sXmlAttributeName, String sKey ) { Debug.Assert(oGraph != null); Debug.Assert(oGraphXmlNode != null); Debug.Assert(!String.IsNullOrEmpty(sXmlAttributeName)); Debug.Assert(!String.IsNullOrEmpty(sKey)); AssertValid(); String sValue; if (XmlUtil2.TrySelectSingleNodeAsString(oGraphXmlNode, "@" + sXmlAttributeName, null, out sValue)) { oGraph.SetValue(sKey, sValue); } }
TryGetEdgeGraphMLAttributeValue ( XmlNode oEdgeXmlNode, String sAttributeID, XmlNamespaceManager oXmlNamespaceManager, out String sAttributeValue ) { Debug.Assert(oEdgeXmlNode != null); Debug.Assert(!String.IsNullOrEmpty(sAttributeID)); Debug.Assert(oXmlNamespaceManager != null); String sXPath = String.Format( "g:data[@key=\"{0}\"]/text()" , sAttributeID ); return(XmlUtil2.TrySelectSingleNodeAsString( oEdgeXmlNode, sXPath, oXmlNamespaceManager, out sAttributeValue)); }
GetRequiredEnumValue <T> ( XmlNode oNode, String sXPath, String sTagName ) { Debug.Assert(oNode != null); Debug.Assert(!String.IsNullOrEmpty(sXPath)); Debug.Assert(!String.IsNullOrEmpty(sTagName)); AssertValid(); Exception oException; try { String sText = XmlUtil2.SelectRequiredSingleNodeAsString(oNode, sXPath, null); return((T)Enum.Parse(typeof(T), sText)); } catch (XmlException oXmlException) { oException = oXmlException; } catch (ArgumentException oArgumentException) { oException = oArgumentException; } String sErrorMessage = String.Format( "The {0} value is missing or invalid." , sTagName ); throw new XmlException(sErrorMessage, oException); }
GetAttributeValue ( XmlNode dataXmlNode ) { Debug.Assert(dataXmlNode != null); Debug.Assert(dataXmlNode.Name == "data"); AssertValid(); String sKey = XmlUtil2.SelectRequiredSingleNodeAsString(dataXmlNode, "@key", null); Debug.Assert(sKey == m_sID); String sAttributeValue; if (!XmlUtil2.TrySelectSingleNodeAsString(dataXmlNode, "text()", null, out sAttributeValue)) { // Allow missing inner text for GraphML-attributes of type string. // This was found in a GraphML file created by the yED program. sAttributeValue = String.Empty; } try { return(ConvertAttributeValue(sAttributeValue)); } catch (FormatException) { throw new XmlException( "The GraphML-attribute value specified for a \"data\" XML node" + " with the key \"" + sKey + "\" is not of the specified" + " type." ); } }
ParseGraphMLAttributeValues ( XmlNode oNodeOrEdgeXmlNode, XmlNamespaceManager oXmlNamespaceManager, IMetadataProvider oEdgeOrVertex, Boolean bIsVertex, Dictionary <String, GraphMLAttribute> oGraphMLAttributeDictionary ) { Debug.Assert(oNodeOrEdgeXmlNode != null); Debug.Assert(oXmlNamespaceManager != null); Debug.Assert(oEdgeOrVertex != null); Debug.Assert(oGraphMLAttributeDictionary != null); AssertValid(); // For each GraphML-attribute that has a default value, set a metadata // value on the edge or vertex. This value may may get overwritten // later. foreach (GraphMLAttribute oGraphMLAttribute in oGraphMLAttributeDictionary.Values) { if (oGraphMLAttribute.IsForVertex == bIsVertex) { Object oDefaultAttributeValue; if (oGraphMLAttribute.TryGetDefaultAttributeValue( out oDefaultAttributeValue)) { oEdgeOrVertex.SetValue(oGraphMLAttribute.Name, oDefaultAttributeValue); } } } // For each "data" XML node specified for this edge or vertex, set // a metadata value on the edge or vertex. This may overwrite a // previously-written default value. foreach (XmlNode oDataXmlNode in oNodeOrEdgeXmlNode.SelectNodes( GraphMLPrefix + ":data", oXmlNamespaceManager)) { String sGraphMLAttributeID = XmlUtil2.SelectRequiredSingleNodeAsString(oDataXmlNode, "@key", null); GraphMLAttribute oGraphMLAttribute; if (!oGraphMLAttributeDictionary.TryGetValue(sGraphMLAttributeID, out oGraphMLAttribute)) { throw new XmlException( "A \"data\" XML node has the key \"" + sGraphMLAttributeID + "\", for which there is no corresponding \"key\" XML" + " node." ); } oEdgeOrVertex.SetValue(oGraphMLAttribute.Name, oGraphMLAttribute.GetAttributeValue(oDataXmlNode)); } }
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); } } }
AppendSharedResponderEdges ( GraphMLXmlDocument oGraphMLXmlDocument, HashSet <String> oVideoIDs, Int32 iMaximumResponses, String sUrlPattern, String sResponderTitle, String sKeyAttributeID, RequestStatistics oRequestStatistics ) { Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oVideoIDs != null); Debug.Assert(iMaximumResponses > 0); Debug.Assert(!String.IsNullOrEmpty(sUrlPattern)); Debug.Assert(sUrlPattern.IndexOf("{0}") >= 0); Debug.Assert(!String.IsNullOrEmpty(sResponderTitle)); Debug.Assert(!String.IsNullOrEmpty(sKeyAttributeID)); Debug.Assert(oRequestStatistics != null); AssertValid(); // The key is the name of an author and the value is a LinkedList of // the video IDs to which the author has responded. Dictionary <String, LinkedList <String> > oAuthorUserNameDictionary = new Dictionary <String, LinkedList <String> >(); foreach (String sVideoID in oVideoIDs) { ReportProgress(String.Format( "Getting {0}s for the video with the ID \"{1}\"." , sResponderTitle, sVideoID )); // This is to prevent self-loop edges that would result when the // same author responds to the same video more than once. HashSet <String> oAuthorUserNames = new HashSet <String>(); String sUrl = String.Format(sUrlPattern, sVideoID); // The document consists of an "entry" XML node for each response. foreach (XmlNode oEntryXmlNode in EnumerateXmlNodes(sUrl, "a:feed/a:entry", iMaximumResponses, true, oRequestStatistics)) { XmlNamespaceManager oXmlNamespaceManager = CreateXmlNamespaceManager(oEntryXmlNode.OwnerDocument); String sAuthorUserName; if ( XmlUtil2.TrySelectSingleNodeAsString(oEntryXmlNode, "a:author/a:name/text()", oXmlNamespaceManager, out sAuthorUserName) && !oAuthorUserNames.Contains(sAuthorUserName) ) { AddVideoIDToDictionary(sAuthorUserName, sVideoID, oAuthorUserNameDictionary); oAuthorUserNames.Add(sAuthorUserName); } } } ReportProgress("Adding edges for shared " + sResponderTitle + "s."); AppendEdgesFromDictionary(oAuthorUserNameDictionary, oGraphMLXmlDocument, "Shared " + sResponderTitle, sKeyAttributeID); }
ParseKeyXmlNode ( XmlNode oKeyXmlNode, XmlNamespaceManager oXmlNamespaceManager, String sGraphMLPrefix ) { Debug.Assert(oKeyXmlNode != null); Debug.Assert(oXmlNamespaceManager != null); Debug.Assert(!String.IsNullOrEmpty(sGraphMLPrefix)); m_sID = XmlUtil2.SelectRequiredSingleNodeAsString(oKeyXmlNode, "@id", null); String sFor = XmlUtil2.SelectRequiredSingleNodeAsString(oKeyXmlNode, "@for", null); // Note that the @attr.name and @attr.type attributes are optional. // Default to sensible values if they are missing. if (!XmlUtil2.TrySelectSingleNodeAsString(oKeyXmlNode, "@attr.name", null, out m_sName)) { m_sName = m_sID; } String sType; if (!XmlUtil2.TrySelectSingleNodeAsString(oKeyXmlNode, "@attr.type", null, out sType)) { sType = "string"; } switch (sFor) { case "node": m_bIsForVertex = true; break; case "edge": m_bIsForVertex = false; break; // NodeXL doesn't support the "graph" or "all" values allowed by // the GraphML specification. The caller should filter out such // "key" XML nodes before using this class. default: throw new XmlException( "The \"for\" attribute on the \"key\" XML node with the" + " id \"" + m_sID + "\" must be either \"node\" or" + " \"edge\"." ); } switch (sType) { case "boolean": m_eType = AttributeType.Boolean; break; case "int": m_eType = AttributeType.Int; break; case "long": m_eType = AttributeType.Long; break; case "float": m_eType = AttributeType.Float; break; case "double": m_eType = AttributeType.Double; break; case "string": m_eType = AttributeType.String; break; default: throw new XmlException( "The \"attr.type\" attribute on the \"key\" XML node with" + " id \"" + m_sID + "\" does not have a valid value." ); } m_oDefaultAttributeValue = null; String sDefaultAttributeValue; XmlNode oDefaultXmlNode = oKeyXmlNode.SelectSingleNode( sGraphMLPrefix + ":default", oXmlNamespaceManager); if ( oDefaultXmlNode != null && XmlUtil2.TrySelectSingleNodeAsString(oDefaultXmlNode, "text()", null, out sDefaultAttributeValue) ) { try { m_oDefaultAttributeValue = ConvertAttributeValue(sDefaultAttributeValue); } catch (FormatException) { throw new XmlException( "The default value specified for the \"key\" XML node with" + " the id \"" + m_sID + "\" is not of the specified type." ); } } AssertValid(); }
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); } } }
AppendAllStatisticGraphMLAttributeValues ( String sUserName, XmlNode oVertexXmlNode, GraphMLXmlDocument oGraphMLXmlDocument, RequestStatistics oRequestStatistics ) { Debug.Assert(!String.IsNullOrEmpty(sUserName)); Debug.Assert(oVertexXmlNode != null); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oRequestStatistics != null); AssertValid(); XmlDocument oXmlDocument; XmlNamespaceManager oXmlNamespaceManager; // Some of the statistics are available in the user's profile. String sUrl = "http://gdata.youtube.com/feeds/api/users/" + EncodeUrlParameter(sUserName); if (TryGetXmlDocument(sUrl, oRequestStatistics, out oXmlDocument, out oXmlNamespaceManager)) { AppendYouTubeDateGraphMLAttributeValue(oXmlDocument, "a:entry/a:published/text()", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, JoinedDateUtcID); AppendStringGraphMLAttributeValue(oXmlDocument, "a:entry/media:thumbnail/@url", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, NodeXLGraphMLUtil.VertexImageFileID); XmlNode oStatisticsXmlNode; if (XmlUtil2.TrySelectSingleNode(oXmlDocument, "a:entry/yt:statistics", oXmlNamespaceManager, out oStatisticsXmlNode)) { AppendInt32GraphMLAttributeValue(oStatisticsXmlNode, "@videoWatchCount", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, VideosWatchedID); AppendInt32GraphMLAttributeValue(oStatisticsXmlNode, "@subscriberCount", oXmlNamespaceManager, oGraphMLXmlDocument, oVertexXmlNode, SubscribersID); } } // The remaining statistics must be obtained from the totalResults // XML node within documents obtained from other URLs. const String TotalResultsXPath = "a:feed/openSearch:totalResults/text()"; sUrl = GetFriendsOrSubscriptionsUrl(sUserName, true) + "?max-results=1"; AppendInt32GraphMLAttributeValue(sUrl, TotalResultsXPath, oGraphMLXmlDocument, oRequestStatistics, oVertexXmlNode, FriendsID); sUrl = GetFriendsOrSubscriptionsUrl(sUserName, false) + "?max-results=1"; AppendInt32GraphMLAttributeValue(sUrl, TotalResultsXPath, oGraphMLXmlDocument, oRequestStatistics, oVertexXmlNode, SubscriptionsID); sUrl = "http://gdata.youtube.com/feeds/api/users/" + EncodeUrlParameter(sUserName) + "/uploads?max-results=1"; AppendInt32GraphMLAttributeValue(sUrl, TotalResultsXPath, oGraphMLXmlDocument, oRequestStatistics, oVertexXmlNode, VideosUploadedID); }
GetUserNetworkRecursive ( String sUserName, WhatToInclude eWhatToInclude, Boolean bIncludeFriendsThisCall, NetworkLevel eNetworkLevel, Int32 iMaximumPeoplePerRequest, Int32 iRecursionLevel, GraphMLXmlDocument oGraphMLXmlDocument, Dictionary <String, XmlNode> oUserNameDictionary, RequestStatistics oRequestStatistics ) { Debug.Assert(!String.IsNullOrEmpty(sUserName)); Debug.Assert(eNetworkLevel == NetworkLevel.One || eNetworkLevel == NetworkLevel.OnePointFive || eNetworkLevel == NetworkLevel.Two); Debug.Assert(iMaximumPeoplePerRequest > 0); Debug.Assert(iRecursionLevel == 1 || iRecursionLevel == 2); Debug.Assert(oGraphMLXmlDocument != null); Debug.Assert(oUserNameDictionary != 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); List <String> oUserNamesToRecurse = new List <String>(); ReportProgressForFriendsOrSubscriptions(sUserName, bIncludeFriendsThisCall); Boolean bThisUserAppended = false; // If the GraphMLXmlDocument already contains at least one vertex node, // then this is the second time that this method has been called, a // partial network has already been obtained, and most errors should // now be skipped. However, if none of the network has been obtained // yet, errors on page 1 should throw an immediate exception. Boolean bSkipMostPage1Errors = oGraphMLXmlDocument.HasVertexXmlNode; // The document consists of a single "feed" node with zero or more // "entry" child nodes. foreach (XmlNode oEntryXmlNode in EnumerateXmlNodes( GetFriendsOrSubscriptionsUrl(sUserName, bIncludeFriendsThisCall), "a:feed/a:entry", iMaximumPeoplePerRequest, bSkipMostPage1Errors, oRequestStatistics)) { XmlNamespaceManager oXmlNamespaceManager = CreateXmlNamespaceManager(oEntryXmlNode.OwnerDocument); String sOtherUserName; if (!XmlUtil2.TrySelectSingleNodeAsString(oEntryXmlNode, "yt:username/text()", oXmlNamespaceManager, out sOtherUserName)) { 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(sUserName, null, oGraphMLXmlDocument, oUserNameDictionary); bThisUserAppended = true; } Boolean bNeedToAppendVertices = GetNeedToAppendVertices( eNetworkLevel, iRecursionLevel); if (bNeedToAppendVertices) { if ( TryAppendVertexXmlNode(sOtherUserName, oEntryXmlNode, oGraphMLXmlDocument, oUserNameDictionary) && bNeedToRecurse ) { oUserNamesToRecurse.Add(sOtherUserName); } } if (bNeedToAppendVertices || oUserNameDictionary.ContainsKey(sOtherUserName)) { String sRelationship; if (bIncludeFriendsThisCall) { sRelationship = "Friend of"; } else { sRelationship = "Subscribes to"; String sSubscriptionType = null; if (XmlUtil2.TrySelectSingleNodeAsString(oEntryXmlNode, "a:category[@scheme='http://gdata.youtube.com/schemas/" + "2007/subscriptiontypes.cat']/@term", oXmlNamespaceManager, out sSubscriptionType)) { sRelationship += " " + sSubscriptionType; } } NodeXLGraphMLUtil.AppendEdgeXmlNode(oGraphMLXmlDocument, sUserName, sOtherUserName, sRelationship); } } if (bNeedToRecurse) { foreach (String sUserNameToRecurse in oUserNamesToRecurse) { GetUserNetworkRecursive(sUserNameToRecurse, eWhatToInclude, bIncludeFriendsThisCall, eNetworkLevel, iMaximumPeoplePerRequest, 2, oGraphMLXmlDocument, oUserNameDictionary, oRequestStatistics); } } }