Site Search with Google Site Search XML

Description

This code will allow you to connect to Google Site Search's XML and display it's search engine results in your page. This is done on the server side, and doesn't need any Javascript to function.

Google Site Search (which has XML) is the paid version of Google Custom Search Engine (which doesn't). You will need to pay for this service and get an ID before you can use this code.

I've attempted to use most of the features available in the XML feed, including suggested spellings, thumbnail images and "Promotions," which are custom results that you can manually put in yourself through the Google Site Search control panel on Google's site.  For those wanting to expand on my work, a complete reference to the XML API is available here. 

As of August, 2012, this is working, production code. You can see it in action on the Oklahoma Christian University search page.

 

Link: http://www.oc.edu/search

Code

<p>
	<form action="$VTLSERVLET_URI" method="get">
		<input class="box" name="q" placeholder="Search OC" value="$!request.getParameter('q')">
		<input type="submit" />
	</form>
</p>

############### Set some starting variables

	## Limit to specific domain(s)
	## set($domainQuery = "&as_sitesearch=www.oceagles.com")
	
	## Set number of results per page
	#set($resultsPerPage = 15)
	
	## Set the CSE (Google Custom Search Engine) ID that will be used
	#set($cseId = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")


############### Display the results

## Only show results if there is a query
#if($UtilMethods.isSet($request.getParameter("q")))

	<div id="searchResults">
		#set($searchQuery = $UtilMethods.encodeURL($request.getParameter("q")))
		
		## Determine the current page
		
			#if($UtilMethods.isSet($request.getParameter("p")))
				#set($currentPage = $webapi.parseInt($request.getParameter("p")))
			#else
				#set($currentPage = 1)
			#end
		
		## Determine where to start the search results
			#set($startResult = $resultsPerPage * ($currentPage - 1))
			
		## Load the XML!
			#set($xmlAddress = "http://www.google.com/cse?cx=$!{cseId}&client=google-csbe&output=xml_no_dtd&num=$!resultsPerPage&start=$!{startResult}&q=$!{searchQuery}$!{domainQuery}")
			#set($myXml = $xmltool.read($xmlAddress))
		
		## Find the total number of results (<M>)
			#set($numberOfResults = $webapi.parseInt($myXml.find("M").text))
				
		## Find the starting and ending result of this search
			#set($startingResult = $webapi.parseInt($myXml.find("RES").attr("SN")))
			#set($endingResult = $webapi.parseInt($myXml.find("RES").attr("EN")))
			
		## Find approximate total number of result pages
			#set($numberOfPages = $numberOfResults / $resultsPerPage)
	
		
			
		
		## Find results in the feed using XPath (http://www.w3schools.com/xpath/xpath_syntax.asp)
		#set($results = $myXml.find("/GSP/RES/R"))
		
		
		## Show search term
		
			## <p>Searching for <strong>"$!{myXml.find("/GSP/Q").text}"</strong></p>
			
			<p>Displaying $startingResult to $endingResult of $numberOfResults</p>
		
		
		## Show suggested spelling link
	
			#set($suggestionDisplay = $!{myXml.find("/GSP/Spelling/Suggestion").text})
			
			#if($UtilMethods.isSet($suggestionDisplay))
			
				## Swap out the current query in the link for the suggested on
				#set($suggestionEncoded = $UtilMethods.encodeURL($!{myXml.find("/GSP/Spelling/Suggestion").attr("q")}))
				#set($currentURI = "${request.getRequestURI()}")
				#set($currentQueryString = "${request.getQueryString()}")
				#set($suggestionQueryString = $currentQueryString.replaceAll("(q=)([^&]*)","$1$suggestionEncoded"))
				#set($suggestionUrl = "$!{currentURI}?$!{suggestionQueryString}")
			
				<p>Did you mean <a href="$!suggestionUrl">$suggestionDisplay</a>?</p>
			#end
		
		<ol>
		#foreach($result in $results)
		
			## Not sure why this is necessary, but it keeps it from displaying all the results' information at once
			#set($result = $xmltool.parse($result))
			
			## Set Up Thumbnail Image
				## Regular Thumbnail
				#set($thumbSrc = $result.find("/R/PageMap/DataObject[@type='cse_thumbnail']/Attribute[@name='src']").get(0).attr("value"))
				
				## Promotion ("Subscribed Link") thumbnail
				#set($SLthumb = "$!result.find('IMAGE_SOURCE').get(0).text") 
				
			## Promotion ("Subscribed Link") Description
				#set($SLdescription = $!result.find('/R/SL_RESULTS/SL_MAIN/BODY_LINE/BLOCK/T')) 
			
			<li value='$!result.attr("N")'> ## Make each ordered list item use the result number
				<a href="$result.U.text" class="result">
					#if($UtilMethods.isSet($!thumbSrc))
						<img src="$!thumbSrc" alt="$!esc.html($!{result.T.text})" class="right" />
					#elseif($UtilMethods.isSet($!SLthumb))
						<img src="$!SLthumb" alt="$!esc.html($!{result.T.text})" class="right" />
					#end
					
					<h3>$!{result.T.text}</h3>
					<p>
						$!{result.S.text.replaceAll("<br>","")}  ## Why does Google have breaks in the text, anyway?
						$!{SLdescription}
						<br />
						<span class="resultUrl">$!{result.UE.text}</span>
					</p>
					
					<div style="clear:both;"></div>
					
				</a>
				## Find out if there's a cached version - comment it into the page
				#if($UtilMethods.isSet($result.HAS.C.attr("CID")))
					#set($cachedLink = "http://www.google.com/search?q=cache:$!{result.HAS.C.attr('CID')}:$!{result.UE.text}")
					<!-- CACHED HERE: $cachedLink -->
				#end
				
			</li>
			
			#set($thumbSrc = "")
			#set($SLthumb = "")
		#end
		</ol>
		
		
		
		
		
		<div id="pageNav">
		
		
		#if($numberOfPages > 1)
			
			## Set Up Previous and Next Buttons
		
				#set($previousPage = $currentPage - 1)
				#set($nextPage = $currentPage + 1)
				
				#set($currentURI = "${request.getRequestURI()}")
				#set($currentQueryString = "${request.getQueryString()}")
				
				## Replace the page number in the current URL (or add it to the end), then use that as the link for the page
				#if($currentQueryString.matches(".*p=[0-9]*.*"))
					#set($previousQueryString = $currentQueryString.replaceAll("((&|^)p=)[0-9]*","$1$!{previousPage}"))
					#set($nextQueryString = $currentQueryString.replaceAll("((&|^)p=)[0-9]*","$1$!{nextPage}"))
				#else
					## Assumes a query string exists, since we checked for "q=" way above
					#set($previousQueryString = "$!{currentQueryString}&p=$!{previousPage}")
					#set($nextQueryString = "$!{currentQueryString}&p=$!{nextPage}")
				#end
	
			
			
			## Previous Page Link
				#if($previousPage > 0) 
					<a href="$!{currentURI}?$!{previousQueryString}" class="previousPage">< Previous</a>
				#end
	
			
			## Dynamic page numbering - Try to keep the current page in the middle of a list of 10 numbers, like Google does
			
				#set($currentURI = "${request.getRequestURI()}")
				#set($currentQueryString = "${request.getQueryString()}")
			
				## Determine starting and ending numbers
					#set($startNumber = $currentPage - 5)
					#if($startNumber < 1)
						#set($startNumber = 1)
					#end
					#set($endNumber = $startNumber + 9)
					#if($endNumber > $numberOfPages)
						#set($endNumber = $numberOfPages)
					#end
				
				## Loop through the pages and display links
				#foreach($pageNumber in [$startNumber .. $endNumber])
					
					## Replace the page number in the current URL (or add it to the end), then use that as the link for the page
					#if($currentQueryString.matches(".*p=[0-9]*.*"))
						#set($thisQueryString = $currentQueryString.replaceAll("((&|^)p=)[0-9]*","$1$!{pageNumber}"))
					#else
						## Assumes a query string exists, since we checked for "q=" way above
						#set($thisQueryString = "$!{currentQueryString}&p=$!{pageNumber}")
					#end
					
					
					## Only use link if not current page 
					#if($pageNumber == $currentPage)
						<span class="pageNumber">$pageNumber</span>
					#else
						<a href="$!{currentURI}?$!{thisQueryString}" class="pageNumber">$pageNumber</a>
					#end
				#end
				
				## Next Page Link
					<a href="$!{currentURI}?$!{nextQueryString}" class="nextPage">Next ></a> 
				
			#end
				
				
			
		
		
		</div>
	</div>

	
#end