Google Custom Search Engine lets website managers and developers easily integrate site search functionality into their websites with most of the required features. However, there are situations when you might have to control the display of search results (custom style guides), add more restrictions (search specific filetypes) or report meta data to web analytics software. I have covered this topic in two posts. This post covers querying , extracting, parsing and looping through the search results while the next part includes posting information (not easily available using iframe approach) to web analytics.
Calling Google Custom Search (CSE) Web Services
<cfhttp result=”cseresult” url=”http://www.google.com/cse?cx=#googleAPIKey#&client=google-csbe&output=xml_no_dtd&q=#q#&start=#start#&filter=0″ method=”get” resolveurl=”yes” />
In the above statement, googleAPIKey=key of the custom search engine; q=search query; start=Zero based paging index, use start=10 for page 2; filter=0= Don’t filter similar result, use 1 to filter results.
Extracting Metadata and Results
<cfscript>
resultsxml = XMLParse(cseresult.FileContent);
RES = XMLSearch(resultsxml, “GSP/RES”);
if (ArrayLen(RES) gt 0)
{
totalResults = XMLSearch(RES[1], “M”);
searchResults = XMLSearch(RES[1], “R”);
iTotalResults = totalResults[1].XmlText;
iStartNumber = RES[1].XmlAttributes.SN;
iEndNumber = RES[1].XmlAttributes.EN;
}
</cfscript>
All XPath queries in above code return Arrays of Structures. RES element in the xml contains all the results information. SN is the index of the first result on the page while EN is the index of the last result on a page. For example, if page 2 has 4 results, then SN=11 and EN=14 while START remains 10.
Displaying Results and Pager
<div id=”google-cse”>
<cfif ArrayLen(RES) gt 0><!— If more than zero results returned —>
<!—Results Pager Header —>
<cfoutput><p>Results <b>#iStartNumber#</b> – <b>#iEndNumber#</b> of about <b>#iTotalResults#</b> for <b>#q#</b></p></cfoutput>
<cfloop index=”i” from=”1″ to=”#ArrayLen(searchResults)#”>
<cfset current_result = searchResults[i]>
<!—Unique Result —>
<div>
<h2><a <cfif isdefined(‘current_result.XmlAttributes.MIME’) AND current_result.XmlAttributes.MIME eq ‘application/pdf’>class=”mime_pdf”</cfif> href=”<cfoutput>#current_result.U.XmlText#</cfoutput>”><cfoutput>#current_result.T.XmlText#</cfoutput></a></h2>
<p><cfoutput>#current_result.S.XmlText#</cfoutput></p>
<p><cfoutput>#current_result.UE.XmlText#</cfoutput></p>
</div>
</cfloop>
<cfif iTotalResults gt numresults>
<cfset num_of_pages = Ceiling(iTotalResults/numresults) >
<cfset current_page = (iStartNumber – 1) / numresults + 1 >
<!—Pager Navigation —>
<div id=”cse-pager”>
<cfif current_page gt 1>
<cfset startnew = (current_page-2)* numresults>
<cfoutput><a href=”#CGI.SCRIPT_NAME#?q=#q#&start=#startnew#”>Previous</a></cfoutput>
</cfif>
<cfloop index=”i” from=”1″ to=”#num_of_pages#”>
<cfset startnew = (i-1)* numresults>
<cfoutput><a <cfif current_page eq i >class=”active” <cfelse>href=”#CGI.SCRIPT_NAME#?q=#q#&start=#startnew#”</cfif>>#i#</a></cfoutput>
</cfloop>
<cfif current_page lt num_of_pages>
<cfset startnew = (current_page)* numresults>
<cfoutput><a href=”#CGI.SCRIPT_NAME#?q=#q#&start=#startnew#”>Next</a></cfoutput>
</cfif>
</div>
</cfif>
</cfif>
The above code will show specific icon for PDF files and a basic pager that includes all the links according to the number of results found.
Complete Implementation (Code Listing)
<div id=”middle_content”>
<cfset numresults = 10>
<cfset iTotalResults = 0>
<cfif not IsDefined(‘start’)>
<cfset start = 0>
</cfif>
<cfif not IsDefined(‘q’)>
<cfset q = ”>
</cfif>
<cfif q eq ”>
<p>Please use the search box above to find the information you need.</p>
<p>Thank you</p>
<cfelse>
<cfhttp result=”cseresult” url=”http://www.google.com/cse?cx=#googleAPIKey#&client=google-csbe&output=xml_no_dtd&q=#q#&start=#start#&filter=0” method=”get” resolveurl=”yes” />
<cfscript>
resultsxml = XMLParse(cseresult.FileContent);
RES = XMLSearch(resultsxml, “GSP/RES”);
if (ArrayLen(RES) gt 0)
{
totalResults = XMLSearch(RES[1], “M”);
searchResults = XMLSearch(RES[1], “R”);
iTotalResults = totalResults[1].XmlText;
iStartNumber = RES[1].XmlAttributes.SN;
iEndNumber = RES[1].XmlAttributes.EN;
}
</cfscript>
<div id=”google-cse”>
<cfif ArrayLen(RES) gt 0><!— If more than zero results returned —>
<!—Results Pager Header —>
<cfoutput><p>Results <b>#iStartNumber#</b> – <b>#iEndNumber#</b> of about <b>#iTotalResults#</b> for <b>#q#</b></p></cfoutput>
<cfloop index=”i” from=”1″ to=”#ArrayLen(searchResults)#”>
<cfset current_result = searchResults[i]>
<!—Unique Result —>
<div>
<h2><a <cfif isdefined(‘current_result.XmlAttributes.MIME’) AND current_result.XmlAttributes.MIME eq ‘application/pdf’>class=”mime_pdf”</cfif> href=”<cfoutput>#current_result.U.XmlText#</cfoutput>”><cfoutput>#current_result.T.XmlText#</cfoutput></a></h2>
<p><cfoutput>#current_result.S.XmlText#</cfoutput></p>
<p><cfoutput>#current_result.UE.XmlText#</cfoutput></p>
</div>
</cfloop>
<cfif iTotalResults gt numresults>
<cfset num_of_pages = Ceiling(iTotalResults/numresults) >
<cfset current_page = (iStartNumber – 1) / numresults + 1 >
<!—Pager Navigation —>
<div id=”cse-pager”>
<cfif current_page gt 1>
<cfset startnew = (current_page-2)* numresults>
<cfoutput><a href=”#CGI.SCRIPT_NAME#?q=#q#&start=#startnew#”>Previous</a></cfoutput>
</cfif>
<cfloop index=”i” from=”1″ to=”#num_of_pages#”>
<cfset startnew = (i-1)* numresults>
<cfoutput><a <cfif current_page eq i >class=”active” <cfelse>href=”#CGI.SCRIPT_NAME#?q=#q#&start=#startnew#”</cfif>>#i#</a></cfoutput>
</cfloop>
<cfif current_page lt num_of_pages>
<cfset startnew = (current_page)* numresults>
<cfoutput><a href=”#CGI.SCRIPT_NAME#?q=#q#&start=#startnew#”>Next</a></cfoutput>
</cfif>
</div>
</cfif>
<cfelse><!— If no results returned —>
<p>Your search – <b><cfoutput>#q#</cfoutput></b> – did not match any documents.<br /><br />
Suggestions:<br /></p>
<ul>
<li>Make sure all words are spelled correctly</li>
<li>Try different keywords</li>
<li>Try more general keywords</li>
<li>Try fewer keywords</li>
</ul>
</cfif>
</div>
</cfif>
</div><!—End of middle_content—>
Above code integrates everything and handles manages output when provided with empty search query or getting zero results from Google. To see the implementation of the above code, Take a look at OSHACampus.com