using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; namespace ReadSharp.Ports.NReadability { public class MetaExtractor { /// /// Gets or sets a value indicating whether [has value]. /// /// /// true if [has value]; otherwise, false. /// public bool HasValue { get; set; } /// /// Gets or sets the tags. /// /// /// The tags. /// public IEnumerable Tags { get; private set; } /// /// Initializes a new instance of the class. /// /// The document. public MetaExtractor(XDocument document) { var documentRoot = document.Root; if (documentRoot == null || documentRoot.Name == null || !"html".Equals(documentRoot.Name.LocalName, StringComparison.OrdinalIgnoreCase)) { HasValue = false; return; } var headElement = documentRoot.GetChildrenByTagName("head").FirstOrDefault(); if (headElement == null) { HasValue = false; return; } IEnumerable meta = headElement.GetChildrenByTagName("meta"); IEnumerable link = headElement.GetChildrenByTagName("link"); Tags = meta != null ? meta.Concat(link) : link; HasValue = Tags != null && Tags.Count() > 0; } /// /// Gets the meta description. /// /// public string GetMetaDescription() { return SearchCandidates(new Dictionary() { { "property|og:description", "content" }, { "name|description", "content" } }); } /// /// Gets the meta image. /// /// public string GetMetaImage() { return SearchCandidates(new Dictionary() { { "property|og:image", "content" }, { "rel|apple-touch-icon", "href" }, { "rel|apple-touch-icon-precomposed", "href"}, { "name|msapplication-square310x310logo", "content" }, { "name|msapplication-square150x150logo", "content" }, { "name|msapplication-square70x70logo", "content" }, { "name|msapplication-TileImage", "content" }, { "rel|image_src", "href" } }); } /// /// Gets the meta favicon. /// /// public string GetMetaFavicon() { return SearchCandidates(new Dictionary() { { "rel|icon", "href" }, { "rel|shortcut icon", "href" } }); } /// /// Gets the charset. /// /// public string GetCharset() { // find: string result = SearchCandidates(new Dictionary() { { "charset", "charset" } }, true); if (String.IsNullOrEmpty(result)) { // find: result = SearchCandidates(new Dictionary() { { "http-equiv|Content-Type", "content" } }); if (!String.IsNullOrEmpty(result)) { int charsetStart = result.IndexOf("charset="); if (charsetStart > 0) { charsetStart += 8; result = result.Substring(charsetStart, result.Length - charsetStart); } } } return String.IsNullOrEmpty(result) ? null : result.ToUpper(); } /// /// Searches the candidates. /// /// The candidates. /// private string SearchCandidates(Dictionary candidates, bool simple = false) { string result = null; foreach (var candidate in candidates) { XElement element; string[] type = candidate.Key.Split('|'); if (simple) { element = Tags .Where(item => item.GetAttributeValue(type[0], null) != null) .FirstOrDefault(); } else { element = Tags .Where(item => String.Equals(item.GetAttributeValue(type[0], null), type[1], StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); } if (element != null) { result = element.GetAttributeValue(candidate.Value, ""); } if (result != null && result.Length > 1) { break; } } return result; } } }