Monday, January 10, 2011

Customizing SharePoint Search - overriding search results webpart



Customizing Sharepoint Search - overriding search results webpart


Some times ago, I developed custom search solution in SharePoint 2007 enviroment.
I implemented search using Search URL Syntax
I needed special custom search webpart with multiple additional search criteria related to custom properties. additionally I implemented custom result webpart

Introduction


In this article i describe, how to create additional filter to search results by overriding
"core search result" webpart.

Searching using URL syntax query has limited functionality (searching by scope or keyword).
It is not posibile to compare dates or number, (like greather then  01.01.2008 or less then 15).

why not just use full text search engine? Because using URL syntaxt query give more flexibilty! You can easly redirect  your search results to other pages/webparts!

Using aproach described in this article, it is posible to perfom compare operation on searched columns with date or number values.The way to do this, it is filtering already returned search results in search results webpart.


Implementation


1) Override CoreResultsWebPart webpart



namespace SearchWebParts
{
[
Guid("85DF3779-8E2C-49c9-8A83-828DC4FACE03")]
public class EasyAdvancedSearchResults : Microsoft.Office.Server.Search.WebControls.CoreResultsWebPart
{





2) where to modify search results???

Search results are stored in xmlResponseDoc member variable. Good place to modify it is in protected 
ModifyXsltArgumentList(Microsoft.SharePoint.WebPartPages.
ArgumentClassWrapper argList) method.


#region Overrides
protected override void ModifyXsltArgumentList(Microsoft.SharePoint.WebPartPages.ArgumentClassWrapper argList)
{
base.ModifyXsltArgumentList(argList);
//here starts custom filtering of the search results
FilterSearchResultsByCreateDate(); 
}
 #endregion Overrides
3) Get filter parameters

In this example i need to filter searched documents with creation date. 
User can select the scope of creation date with start date and end date parameters on the custom search webpart. This parameters are then send with url query. For example:

http://testdomain/sites/test/erweitertesuche.aspx?k=search&fromdate=06.04.2009+00%3a00%3a00&todate=30.04.2009+00%3a00%3a00&s=Alle+ERGO+Dokumente&start=1

Get this values from URL in our custom result webpart

System.Globalization.
CultureInfo provider = System.Globalization.CultureInfo.CurrentCulture; 
//filter when one of the date parameters is present 'fromdate' or 'todate'
if (this.Context.Request["todate"] != null || this.Context.Request["fromdate"] != null)
{
//try parse 'to date' parameter
if (this.Context.Request["todate"] != null)
{
DateTime.TryParse(this.Context.Request["todate"], provider, System.Globalization.DateTimeStyles.None, out toDate);
}
//try parse 'from date' parameter
if (this.Context.Request["fromdate"]!=null)
{
DateTime.TryParse(this.Context.Request["fromdate"], provider, System.Globalization.DateTimeStyles.None, out fromDate);
} 

4) Filter search results 

Filter results by creation date with start date and end date parameters. 
You have results in 

protected XmlDocument xmlResponseDoc;

Modfiy xml results the way you want. I do this using LINQ query, fast and easy.

//get original xml with search results XElement root = XElement.Parse(xmlResponseDoc.InnerXml);

//LINQ query, results are filtered by 'from date' and 'to date' 
IEnumerable<XElement> searchResults =
from el in root.Elements()
where DateTime.Parse((string)el.Element("write").Value, provider) > fromDate &&
DateTime.Parse((string)el.Element("write").Value, provider) < toDate
select el; 


5) Set filtered xml as a new search results value

//set filtered result as a new search result
root.ReplaceNodes(searchResults); 
xmlResponseDoc.InnerXml = root.ToString();

Below complete method listing





#region Private methods


///










/// Filter original results xml by create date.
/// Filter parameters are requested from context.
///

private void FilterSearchResultsByCreateDate()
{           
    //set initial values for parameters
    DateTime fromDate = DateTime.MinValue;
    DateTime toDate = DateTime.MaxValue; 

    System.Globalization.CultureInfo provider = System.Globalization.CultureInfo.CurrentCulture;

    //filter when one of the date parameters is present 'fromdate' or 'todate'
    if (this.Context.Request["todate"] != null || this.Context.Request["fromdate"] != null)
    {
        //try parse 'to date' parameter
        if (this.Context.Request["todate"] != null)
        {
            DateTime.TryParse(this.Context.Request["todate"], provider, System.Globalization.DateTimeStyles.None, out toDate);
        }

        //try parse 'from date' parameter
        if (this.Context.Request["fromdate"]!=null)
        {
            DateTime.TryParse(this.Context.Request["fromdate"], provider, System.Globalization.DateTimeStyles.None, out fromDate);
        }

        //get original xml with search results
        XElement root = XElement.Parse(xmlResponseDoc.InnerXml);
       
        //LINQ query, results are filtered by 'from date' and 'to date'                
        IEnumerable searchResults =
        from el in root.Elements()
        where DateTime.Parse((string)el.Element("write").Value, provider) > fromDate &&
              DateTime.Parse((string)el.Element("write").Value, provider) < toDate
        select el;                               
       
        //set filtered result as a new search result
        root.ReplaceNodes(searchResults);               
        xmlResponseDoc.InnerXml = root.ToString();
    }
}

#endregion Private methods



2 comments:

  1. Thanks a lot dude..You save my time

    ReplyDelete
  2. Given so much information in it. its very useful .Thanks for your valuable information.
    dot net training center in chennai |
    best dot net training in chennai

    ReplyDelete