RssHelper.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Text.RegularExpressions;
  7. using System.Xml.Linq;
  8. namespace FormulaOneApp.Rss.Helpers
  9. {
  10. public static class RssHelper
  11. {
  12. private const string Imgpattern =
  13. @"<(?<Tag_Name>(a)|img)\b[^>]*?\b(?<URL_Type>(?(1)href|src))\s*=\s*(?:""(?<URL>(?:\\""|[^""])*)""|'(?<URL>(?:\\'|[^'])*)')";
  14. private const string Urlpattern = @"(www.+|http.+)([\s]|$)";
  15. private static readonly Dictionary<string, string[]> TimeZones = new Dictionary<string, string[]>
  16. {
  17. {"ACDT", new[] {"-1030", "Australian Central Daylight"}},
  18. {"ACST", new[] {"-0930", "Australian Central Standard"}},
  19. {"ADT", new[] {"+0300", "(US) Atlantic Daylight"}},
  20. {"AEDT", new[] {"-1100", "Australian East Daylight"}},
  21. {"AEST", new[] {"-1000", "Australian East Standard"}},
  22. {"AHDT", new[] {"+0900", ""}},
  23. {"AHST", new[] {"+1000", ""}},
  24. {"AST", new[] {"+0400", "(US) Atlantic Standard"}},
  25. {"AT", new[] {"+0200", "Azores"}},
  26. {"AWDT", new[] {"-0900", "Australian West Daylight"}},
  27. {"AWST", new[] {"-0800", "Australian West Standard"}},
  28. {"BAT", new[] {"-0300", "Bhagdad"}},
  29. {"BDST", new[] {"-0200", "British Double Summer"}},
  30. {"BET", new[] {"+1100", "Bering Standard"}},
  31. {"BST", new[] {"+0300", "Brazil Standard"}},
  32. {"BT", new[] {"-0300", "Baghdad"}},
  33. {"BZT2", new[] {"+0300", "Brazil Zone 2"}},
  34. {"CADT", new[] {"-1030", "Central Australian Daylight"}},
  35. {"CAST", new[] {"-0930", "Central Australian Standard"}},
  36. {"CAT", new[] {"+1000", "Central Alaska"}},
  37. {"CCT", new[] {"-0800", "China Coast"}},
  38. {"CDT", new[] {"+0500", "(US) Central Daylight"}},
  39. {"CED", new[] {"-0200", "Central European Daylight"}},
  40. {"CET", new[] {"-0100", "Central European"}},
  41. {"CST", new[] {"+0600", "(US) Central Standard"}},
  42. {"EAST", new[] {"-1000", "Eastern Australian Standard"}},
  43. {"EDT", new[] {"+0400", "(US) Eastern Daylight"}},
  44. {"EED", new[] {"-0300", "Eastern European Daylight"}},
  45. {"EET", new[] {"-0200", "Eastern Europe"}},
  46. {"EEST", new[] {"-0300", "Eastern Europe Summer"}},
  47. {"EST", new[] {"+0500", "(US) Eastern Standard"}},
  48. {"FST", new[] {"-0200", "French Summer"}},
  49. {"FWT", new[] {"-0100", "French Winter"}},
  50. {"GMT", new[] {"+0000", "Greenwich Mean"}},
  51. {"GST", new[] {"-1000", "Guam Standard"}},
  52. {"HDT", new[] {"+0900", "Hawaii Daylight"}},
  53. {"HST", new[] {"+1000", "Hawaii Standard"}},
  54. {"IDLE", new[] {"-1200", "Internation Date Line East"}},
  55. {"IDLW", new[] {"+1200", "Internation Date Line West"}},
  56. {"IST", new[] {"-0530", "Indian Standard"}},
  57. {"IT", new[] {"-0330", "Iran"}},
  58. {"JST", new[] {"-0900", "Japan Standard"}},
  59. {"JT", new[] {"-0700", "Java"}},
  60. {"MDT", new[] {"+0600", "(US) Mountain Daylight"}},
  61. {"MED", new[] {"-0200", "Middle European Daylight"}},
  62. {"MET", new[] {"-0100", "Middle European"}},
  63. {"MEST", new[] {"-0200", "Middle European Summer"}},
  64. {"MEWT", new[] {"-0100", "Middle European Winter"}},
  65. {"MST", new[] {"+0700", "(US) Mountain Standard"}},
  66. {"MT", new[] {"-0800", "Moluccas"}},
  67. {"NDT", new[] {"+0230", "Newfoundland Daylight"}},
  68. {"NFT", new[] {"+0330", "Newfoundland"}},
  69. {"NT", new[] {"+1100", "Nome"}},
  70. {"NST", new[] {"-0630", "North Sumatra"}},
  71. {"NZ", new[] {"-1100", "New Zealand "}},
  72. {"NZST", new[] {"-1200", "New Zealand Standard"}},
  73. {"NZDT", new[] {"-1300", "New Zealand Daylight"}},
  74. {"NZT", new[] {"-1200", "New Zealand"}},
  75. {"PDT", new[] {"+0700", "(US) Pacific Daylight"}},
  76. {"PST", new[] {"+0800", "(US) Pacific Standard"}},
  77. {"ROK", new[] {"-0900", "Republic of Korea"}},
  78. {"SAD", new[] {"-1000", "South Australia Daylight"}},
  79. {"SAST", new[] {"-0900", "South Australia Standard"}},
  80. {"SAT", new[] {"-0900", "South Australia Standard"}},
  81. {"SDT", new[] {"-1000", "South Australia Daylight"}},
  82. {"SST", new[] {"-0200", "Swedish Summer"}},
  83. {"SWT", new[] {"-0100", "Swedish Winter"}},
  84. {"USZ3", new[] {"-0400", "USSR Zone 3"}},
  85. {"USZ4", new[] {"-0500", "USSR Zone 4"}},
  86. {"USZ5", new[] {"-0600", "USSR Zone 5"}},
  87. {"USZ6", new[] {"-0700", "USSR Zone 6"}},
  88. {"UT", new[] {"+0000", "Universal Coordinated"}},
  89. {"UTC", new[] {"+0000", "Universal Coordinated"}},
  90. {"UZ10", new[] {"-1100", "USSR Zone 10"}},
  91. {"WAT", new[] {"+0100", "West Africa"}},
  92. {"WET", new[] {"+0000", "West European"}},
  93. {"WST", new[] {"-0800", "West Australian Standard"}},
  94. {"YDT", new[] {"+0800", "Yukon Daylight"}},
  95. {"YST", new[] {"+0900", "Yukon Standard"}},
  96. {"ZP4", new[] {"-0400", "USSR Zone 3"}},
  97. {"ZP5", new[] {"-0500", "USSR Zone 4"}},
  98. {"ZP6", new[] {"-0600", "USSR Zone 5"}}
  99. };
  100. /// <summary>
  101. /// Get the specified element's value as datetime
  102. /// </summary>
  103. /// <param name="item"></param>
  104. /// <param name="elementName"></param>
  105. /// <returns></returns>
  106. public static DateTime? GetSafeElementDate(this XElement item, string elementName)
  107. {
  108. return GetSafeElementDate(item, elementName, item.GetDefaultNamespace());
  109. }
  110. /// <summary>
  111. /// Get the specified element's value as datetime
  112. /// </summary>
  113. /// <param name="item"></param>
  114. /// <param name="elementName"></param>
  115. /// <param name="xNamespace"></param>
  116. /// <returns></returns>
  117. public static DateTime? GetSafeElementDate(this XElement item, string elementName, XNamespace xNamespace)
  118. {
  119. DateTime date;
  120. XElement element = item.Element(xNamespace + elementName);
  121. if (element == null)
  122. return null;
  123. if (TryParseDateTime(element.Value, out date))
  124. return date;
  125. return null;
  126. }
  127. /// <summary>
  128. /// Get the specified element's value as string
  129. /// </summary>
  130. /// <param name="item"></param>
  131. /// <param name="elementName"></param>
  132. /// <returns></returns>
  133. public static string GetSafeElementString(this XElement item, string elementName)
  134. {
  135. if (item == null) return String.Empty;
  136. return GetSafeElementString(item, elementName, item.GetDefaultNamespace());
  137. }
  138. /// <summary>
  139. /// Get the specified element's value as string
  140. /// </summary>
  141. /// <param name="item"></param>
  142. /// <param name="elementName"></param>
  143. /// <param name="xNamespace"></param>
  144. /// <returns></returns>
  145. public static string GetSafeElementString(this XElement item, string elementName, XNamespace xNamespace)
  146. {
  147. if (item == null) return String.Empty;
  148. XElement value = item.Element(xNamespace + elementName);
  149. if (value != null)
  150. return value.Value;
  151. return String.Empty;
  152. }
  153. /// <summary>
  154. /// Get the link element's value as string
  155. /// </summary>
  156. /// <param name="item"></param>
  157. /// <param name="rel"></param>
  158. /// <returns></returns>
  159. public static string GetLink(this XElement item, string rel)
  160. {
  161. IEnumerable<XElement> links = item.Elements(item.GetDefaultNamespace() + "link");
  162. var xElements = links as XElement[] ?? links.ToArray();
  163. IEnumerable<string> link = from l in xElements
  164. let xAttribute = l.Attribute("rel")
  165. where xAttribute != null && xAttribute.Value == rel
  166. let attribute = l.Attribute("href")
  167. where attribute != null
  168. select attribute.Value;
  169. var linkData = link as string[] ?? link.ToArray();
  170. if (!linkData.Any() && xElements.Any())
  171. {
  172. var firstOrDefault = xElements.FirstOrDefault();
  173. if (firstOrDefault != null) return firstOrDefault.Attributes().First().Value;
  174. }
  175. return linkData.FirstOrDefault();
  176. }
  177. /// <summary>
  178. /// Get the item's image
  179. /// </summary>
  180. /// <param name="item"></param>
  181. /// <returns></returns>
  182. public static string GetImage(this XElement item)
  183. {
  184. string feedDataImage = null;
  185. try
  186. {
  187. if (item == null) return String.Empty;
  188. feedDataImage = GetImageFromTag(item);
  189. if (string.IsNullOrEmpty(feedDataImage))
  190. {
  191. feedDataImage = GetImageFromEnclosure(item);
  192. }
  193. if (string.IsNullOrEmpty(feedDataImage))
  194. {
  195. feedDataImage = GetImagesInHtmlString(item.Value).FirstOrDefault();
  196. }
  197. if (string.IsNullOrEmpty(feedDataImage))
  198. {
  199. feedDataImage = GetImageFromMedia(item);
  200. }
  201. }
  202. catch (Exception ex)
  203. {
  204. Debug.WriteLine(ex);
  205. }
  206. return feedDataImage;
  207. }
  208. private static string GetImageFromTag(XElement item)
  209. {
  210. string image = string.Empty;
  211. XElement imageElement = item.Element(item.GetDefaultNamespace() + "image");
  212. if (imageElement != null)
  213. {
  214. if (imageElement.HasElements)
  215. {
  216. XElement urlElement = imageElement.Element(item.GetDefaultNamespace() + "url");
  217. if (urlElement != null)
  218. {
  219. image = urlElement.Value;
  220. }
  221. }
  222. else
  223. {
  224. image = imageElement.Value;
  225. }
  226. }
  227. return image;
  228. }
  229. private static string GetImageFromMedia(XElement item)
  230. {
  231. XNamespace media = "http://search.yahoo.com/mrss/";
  232. var content = item.Descendants(media + "content"); //this part doesn't work as expected
  233. var xElements = content as XElement[] ?? content.ToArray();
  234. if (xElements.Last() != null)
  235. {
  236. var xAttribute = xElements.Last().Attribute("url");
  237. return xAttribute != null ? xAttribute.Value : string.Empty;
  238. }
  239. return string.Empty;
  240. }
  241. // http://www.w3schools.com/rss/rss_tag_enclosure.asp
  242. private static string GetImageFromEnclosure(this XElement item)
  243. {
  244. string feedDataImage = null;
  245. try
  246. {
  247. XElement element = item.Element(item.GetDefaultNamespace() + "enclosure");
  248. if (element == null)
  249. return null;
  250. XAttribute typeAttribute = element.Attribute("type");
  251. if (typeAttribute != null &&
  252. !string.IsNullOrEmpty(typeAttribute.Value) &&
  253. typeAttribute.Value.StartsWith("image"))
  254. {
  255. XAttribute urlAttribute = element.Attribute("url");
  256. feedDataImage = (urlAttribute != null && !string.IsNullOrEmpty(urlAttribute.Value))
  257. ? urlAttribute.Value
  258. : string.Empty;
  259. }
  260. }
  261. catch (Exception ex)
  262. {
  263. Debug.WriteLine(ex);
  264. }
  265. return feedDataImage;
  266. }
  267. private static IEnumerable<string> GetImagesInHtmlString(string htmlString)
  268. {
  269. var images = new List<string>();
  270. const string pattern = Imgpattern;
  271. var rgx = new Regex(pattern, RegexOptions.IgnoreCase);
  272. MatchCollection matches = rgx.Matches(htmlString);
  273. for (int i = 0, l = matches.Count; i < l; i++)
  274. {
  275. if (matches[i].Value.Contains(".jpg") || matches[i].Value.Contains(".png"))
  276. {
  277. MatchCollection ms = Regex.Matches(matches[i].Value, Urlpattern);
  278. if (!string.IsNullOrEmpty(ms[0].Value))
  279. images.Add(ms[0].Value.Replace("\"", string.Empty));
  280. }
  281. }
  282. return images;
  283. }
  284. private static bool TryParseDateTime(string datetime, out DateTime result)
  285. {
  286. try
  287. {
  288. result = DateTime.Parse(datetime,
  289. DateTimeFormatInfo.InvariantInfo,
  290. DateTimeStyles.AllowWhiteSpaces);
  291. return true;
  292. }
  293. catch (FormatException)
  294. {
  295. int tzIndex = datetime.LastIndexOf(" ", StringComparison.Ordinal);
  296. if (tzIndex >= 0)
  297. {
  298. string tz = datetime.Substring(tzIndex, datetime.Length - tzIndex);
  299. string offset = TimeZoneToOffset(tz);
  300. if (offset != null)
  301. {
  302. string offsetDate = string.Format("{0} {1}", datetime.Substring(0, tzIndex), offset);
  303. return TryParseDateTime(offsetDate, out result);
  304. }
  305. }
  306. result = default(DateTime);
  307. return false;
  308. }
  309. }
  310. private static string TimeZoneToOffset(string tz)
  311. {
  312. if (tz == null)
  313. return null;
  314. tz = tz.ToUpper().Trim();
  315. if (TimeZones.ContainsKey(tz))
  316. {
  317. return TimeZones[tz][0];
  318. }
  319. return null;
  320. }
  321. }
  322. }