/// <summary> /// Merges the current node wiki with the given node wiki. /// </summary> /// <param name="wiki">Wiki to merge with.</param> /// <param name="mergeDescription">Value indicating whether to merge description.</param> /// <returns>Merged wiki.</returns> public RockClimbingComWiki MergeWikiWith(RockClimbingComWiki wiki, bool mergeDescription) { RockClimbingComWiki ret = this.Info; if (ret != null && wiki != null) { // Assigning location, if missing if (ret.Location == null && wiki.Location != null) ret.Location = wiki.Location; // Assigning climbing type, if missing if (ret.Climbing == Models.ClimbingTypes.NotSpecified && wiki.Climbing != Models.ClimbingTypes.NotSpecified) ret.Climbing = wiki.Climbing; // Assigning climbing season, if missing if (ret.Season == Models.Seasons.NotSpecified && wiki.Season != Models.Seasons.NotSpecified) ret.Season = wiki.Season; if (mergeDescription) { // Overriding description if the name changes if (string.IsNullOrWhiteSpace(ret.Name) && !string.IsNullOrWhiteSpace(wiki.Name)) { ret.Name = wiki.Name; ret.Description = wiki.Description; } else if (ret.Description.Length * 3 < wiki.Description.Length) { // Candidate wiki has substantially more rich description - overriding ret.Description = wiki.Description; } } } return ret; }
/// <summary> /// Parses page from the given content. /// </summary> /// <param name="content">Content.</param> /// <returns>Page.</returns> public static RockClimbingComWiki Parse(string content) { Match m = null; double parsed = -1; string[] seasons = null; string[] climbingTypes = null; RockClimbingComWiki ret = null; bool hasGeneralDescription = false; StringBuilder description = new StringBuilder(); Models.Seasons season = Models.Seasons.NotSpecified; Models.ClimbingTypes climbing = Models.ClimbingTypes.NotSpecified; Func<string, string> getFieldValue = (name) => { string result = string.Empty; m = Regex.Match(content, string.Format("{0}:\\s*</strong>\\s*</td>\\s*<td[^>]+>([^<]+)</td>", name), RegexOptions.IgnoreCase | RegexOptions.Singleline); if (m != null && m.Success) result = FixPunctiation(m.Groups[1].Value.Trim()); return result; }; Action<string> appendToDescription = (name) => { string nearest = string.Empty; string v = getFieldValue(name); string approachTime = string.Empty; if (string.Compare(name, "Directions", StringComparison.InvariantCultureIgnoreCase) == 0) { nearest = getFieldValue("Nearest town or city"); if (!string.IsNullOrEmpty(nearest)) v = string.Concat(string.Format("The nearest town or city is {0}. ", nearest.Trim().TrimEnd('.')), v); } else if (string.Compare(name, "Approach", StringComparison.InvariantCultureIgnoreCase) == 0) { approachTime = getFieldValue("Approach Time"); if (!string.IsNullOrEmpty(approachTime)) { approachTime = Regex.Replace(Regex.Replace(approachTime, @"([0-9]+)", " $1 ", RegexOptions.IgnoreCase).Trim(), @"\s+", " ").Trim(); if (Regex.IsMatch(approachTime, "[a-zA-Z]+", RegexOptions.IgnoreCase)) v = string.Concat(string.Format("The approach time is {0}. ", approachTime.Trim().TrimEnd('.').Trim()), v); } } if (!string.IsNullOrEmpty(v)) { v = v.Trim(); if (description.Length > 0) description.AppendLine(); if (hasGeneralDescription) description.AppendLine(string.Format("### {0}", name)); description.Append(v); hasGeneralDescription = v.Length > 0; } }; m = Regex.Match(content, "<h2>([^>]+)</h2>", RegexOptions.IgnoreCase); if (m != null && m.Success) { ret = new RockClimbingComWiki(); ret.Name = NormalizeName(m.Groups[1].Value.Trim(), true); if (!string.IsNullOrEmpty(ret.Name)) { m = Regex.Match(content, "<td[^>]+>\\s*<!--[^>]+Description[^>]+-->([^<]+)</td>", RegexOptions.IgnoreCase | RegexOptions.Singleline); if (m != null && m.Success) { description.Append(FixPunctiation(m.Groups[1].Value.Trim())); hasGeneralDescription = description.Length > 0; } appendToDescription("Directions"); appendToDescription("Approach"); appendToDescription("Access issues"); ret.Description = description.ToString(); m = Regex.Match(content, "<td[^>]+>(\\-?\\d+(\\.\\d+)?),\\s*(\\-?\\d+(\\.\\d+)?)</td>", RegexOptions.IgnoreCase); if (m != null && m.Success) { ret.Location = new Models.Location(); if (double.TryParse(m.Groups[1].Value, NumberStyles.AllowLeadingSign, LocationCulture, out parsed) || double.TryParse(m.Groups[1].Value, NumberStyles.Any, LocationCulture, out parsed)) { ret.Location.Latitude = parsed; } if (double.TryParse(m.Groups[3].Value, NumberStyles.AllowLeadingSign, LocationCulture, out parsed) || double.TryParse(m.Groups[3].Value, NumberStyles.Any, LocationCulture, out parsed)) { ret.Location.Longitude = parsed; } if (ret.Location.Latitude < -90 || ret.Location.Latitude > 90) ret.Location = null; } seasons = getFieldValue("When to Climb").Split(new char[] { ' ', '\n', '/' }, StringSplitOptions.RemoveEmptyEntries).Select(v => v.Trim()).ToArray(); if (seasons != null && seasons.Any()) { foreach (string s in seasons) { if (Enum.TryParse<Models.Seasons>(s.Trim().Trim(',', '.', ';').Trim(), true, out season)) { if (ret.Season == Models.Seasons.NotSpecified) ret.Season = season; else ret.Season |= season; } } } climbingTypes = getFieldValue("Type of Climbing").Split(new char[] { ' ', '\n', '/' }, StringSplitOptions.RemoveEmptyEntries).Select(v => v.Trim()).ToArray(); if (climbingTypes != null && climbingTypes.Any()) { foreach (string c in climbingTypes) { if (Enum.TryParse<Models.ClimbingTypes>(c.Trim().Trim(',', '.', ';').Trim(), true, out climbing)) { if (ret.Climbing == Models.ClimbingTypes.NotSpecified) ret.Climbing = climbing; else ret.Climbing |= climbing; } } } if (ret.Climbing == Models.ClimbingTypes.NotSpecified) ret.Climbing = Models.ClimbingTypes.Sport; } else ret = null; } return ret; }