/// <summary> /// Will call the GSA using the specified Query object. All parameters of the query object will be used to construct the call. /// </summary> /// <param name="query">The <see cref="Query"/> object that encapsulates the query parameters </param> /// <param name="cookie">The optional authentication cookie to send with the request</param> /// <returns>The <see cref="ISearchResult"/></returns> public ISearchResult Search(IQuery query, HttpCookie cookie = null) { XDocument document; try { var url = query.ConstructQuery(); if (query.Access == SearchAccess.Secure || query.Access == SearchAccess.All) { //Secure search, we need to jump through some hoops var cookieCollection = new CookieCollection(); //Do we have an authentication cookie to send with the request? if (cookie != null) { var requestCookie = new Cookie(cookie.Name, cookie.Value, "/", query.GetDomain()); requestCookie.Expires = cookie.Expires; requestCookie.HttpOnly = cookie.HttpOnly; requestCookie.Secure = cookie.Secure; cookieCollection.Add(requestCookie); } var xml = CallUrl(url, null, cookieCollection); document = XDocument.Parse(xml); } else { document = XDocument.Load(url); } } catch (Exception ex) { return new SearchResult { Error = "Server error occured while loading XML" }; } if (document.Root == null) { return new SearchResult { Error = "The XML appears Malformed. No Root element found." }; } var result = new SearchResult(); var tm = document.Root.Element("TM"); if (tm != null) { result.ExecutionTime = tm.Value; } var rq = document.Root.Element("Q"); if (rq != null) { result.Query = rq.Value; } result.Version = document.Root.Attribute("VER").Value; result.Parameters = new List<ResultParameter>(); foreach (var param in document.Root.Elements("PARAM")) { var resultParameter = new ResultParameter(); resultParameter.Name = param.Attribute("name").Value; resultParameter.Value = param.Attribute("value").Value; resultParameter.OriginalValue = param.Attribute("original_value").Value; result.Parameters.Add(resultParameter); } result.SearchHits = new List<SearchHit>(); var res = document.Root.Element("RES"); if (res != null) { //The search gave results var matches = res.Element("M"); if (matches != null) { result.NumberOfHits = int.Parse(matches.Value); } var filter = res.Element("FI"); if (filter != null) { result.Filtering = filter.Value; } var nb = res.Element("NB"); if (nb != null) { var nexturl = nb.Element("NU"); if (nexturl != null) { result.NextUrl = nexturl.Value; } var prevurl = nb.Element("NP"); if (prevurl != null) { result.PreviousUrl = prevurl.Value; } } foreach (var hit in res.Elements("R")) { var searchHit = new SearchHit(); searchHit.Index = int.Parse(hit.Attribute("N").Value); var url = hit.Element("U"); if (url != null) { searchHit.Url = url.Value; } var encodedUrl = hit.Element("UE"); if (encodedUrl != null) { searchHit.EncodedUrl = encodedUrl.Value; } var title = hit.Element("T"); if (title != null) { searchHit.Title = title.Value; } var rating = hit.Element("RK"); if (rating != null) { searchHit.Rating = int.Parse(rating.Value); } var snippet = hit.Element("S"); if (snippet != null) { searchHit.Snippet = snippet.Value; } var mimeType = hit.Attribute("MIME"); if (mimeType != null) { searchHit.MimeType = mimeType.Value; } var has = hit.Element("HAS"); if (has != null) { var c = has.Element("C"); if (c != null) { var sz = c.Attribute("SZ"); if (sz != null) { searchHit.Size = sz.Value; } } } searchHit.MetaTags = new Dictionary<string, string>(); foreach (var mt in hit.Elements("MT")) { var n = mt.Attribute("N"); if (n != null) { var v = mt.Attribute("V"); if (v != null) { searchHit.MetaTags.Add(n.Value, v.Value); } } } result.SearchHits.Add(searchHit); } result.Facets = new List<Facet>(); var facets = res.Element("PARM"); if (facets != null) { //We have facets or "dynamic navigation" as it's called in google reference foreach (var pmt in facets.Elements("PMT")) { var facet = new Facet(); var nm = pmt.Attribute("NM"); if (nm != null) { facet.MetaName = nm.Value; } var dn = pmt.Attribute("DN"); if (dn != null) { facet.DisplayName = dn.Value; } var ir = pmt.Attribute("IR"); if (ir != null) { facet.IsRange = int.Parse(ir.Value) > 0; } var t = pmt.Attribute("T"); if (t != null) { facet.FacetType = (FacetType)int.Parse(t.Value); } facet.FacetItems = new List<FacetItem>(); foreach (var pv in pmt.Elements("PV")) { var facetItem = new FacetItem(); var v = pv.Attribute("V"); if (v != null) { facetItem.Value = v.Value; } var l = pv.Attribute("L"); if (l != null) { facetItem.LowRange = l.Value; } var h = pv.Attribute("H"); if (h != null) { facetItem.HighRange = h.Value; } var c = pv.Attribute("C"); if (c != null) { facetItem.Count = int.Parse(c.Value); } facetItem.MetaName = facet.MetaName; facet.FacetItems.Add(facetItem); } result.Facets.Add(facet); } } } result.KeyMatches = new List<KeyMatch>(); //We have keyMatches foreach (var gm in document.Root.Elements("GM")) { var keyMatch = new KeyMatch(); var gl = gm.Element("GL"); if (gl != null) { keyMatch.Url = gl.Value; } var gd = gm.Element("GD"); if (gd != null) { keyMatch.Description = gd.Value; } result.KeyMatches.Add(keyMatch); } result.SpellingSuggestions = new List<string>(); var spellings = document.Root.Element("Spelling"); if (spellings != null) { //We have spelling suggestions foreach (var suggestion in spellings.Elements("Suggestion")) { var q = suggestion.Attribute("q"); if (q != null) { result.SpellingSuggestions.Add(q.Value); } } } result.Synonyms = new List<string>(); var synonyms = document.Root.Element("Synonyms"); if (synonyms != null) { //We have synonyms to the submitted query foreach (var synonym in synonyms.Elements("OneSynonym")) { var q = synonym.Attribute("q"); if (q != null) { result.Synonyms.Add(q.Value); } } } return result; }