mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-16 17:16:25 +00:00
243 lines
8.2 KiB
Text
243 lines
8.2 KiB
Text
|
<%@ Page Language="C#" EnableViewState="False" %>
|
||
|
|
||
|
<script runat="server">
|
||
|
//=============================================================================
|
||
|
// System : Sandcastle Help File Builder
|
||
|
// File : SearchHelp.aspx
|
||
|
// Author : Eric Woodruff (Eric@EWoodruff.us)
|
||
|
// Updated : 07/03/2007
|
||
|
// Note : Copyright 2007, Eric Woodruff, All rights reserved
|
||
|
// Compiler: Microsoft C#
|
||
|
//
|
||
|
// This file contains the code used to search for keywords within the help
|
||
|
// topics using the full-text index files created by the help file builder.
|
||
|
//
|
||
|
// This code is published under the Microsoft Public License (Ms-PL). A copy
|
||
|
// of the license should be distributed with the code. It can also be found
|
||
|
// at the project website: http://SHFB.CodePlex.com. This notice, the
|
||
|
// author's name, and all copyright notices must remain intact in all
|
||
|
// applications, documentation, and source files.
|
||
|
//
|
||
|
// Version Date Who Comments
|
||
|
// ============================================================================
|
||
|
// 1.5.0.0 06/24/2007 EFW Created the code
|
||
|
//=============================================================================
|
||
|
|
||
|
private class Ranking
|
||
|
{
|
||
|
public string Filename, PageTitle;
|
||
|
public int Rank;
|
||
|
|
||
|
public Ranking(string file, string title, int rank)
|
||
|
{
|
||
|
Filename = file;
|
||
|
PageTitle = title;
|
||
|
Rank = rank;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Render the search results
|
||
|
/// </summary>
|
||
|
/// <param name="writer">The writer to which the results are written</param>
|
||
|
protected override void Render(HtmlTextWriter writer)
|
||
|
{
|
||
|
FileStream fs = null;
|
||
|
BinaryFormatter bf;
|
||
|
string searchText, ftiFile;
|
||
|
char letter;
|
||
|
bool sortByTitle = false;
|
||
|
|
||
|
// The keywords for which to search should be passed in the query string
|
||
|
searchText = this.Request.QueryString["Keywords"];
|
||
|
|
||
|
if(String.IsNullOrEmpty(searchText))
|
||
|
{
|
||
|
writer.Write("<b class=\"PaddedText\">Nothing found</b>");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// An optional SortByTitle option can also be specified
|
||
|
if(this.Request.QueryString["SortByTitle"] != null)
|
||
|
sortByTitle = Convert.ToBoolean(this.Request.QueryString["SortByTitle"]);
|
||
|
|
||
|
List<string> keywords = this.ParseKeywords(searchText);
|
||
|
List<char> letters = new List<char>();
|
||
|
List<string> fileList;
|
||
|
Dictionary<string, List<long>> ftiWords, wordDictionary =
|
||
|
new Dictionary<string,List<long>>();
|
||
|
|
||
|
try
|
||
|
{
|
||
|
// Load the file index
|
||
|
fs = new FileStream(Server.MapPath("fti/FTI_Files.bin"), FileMode.Open,
|
||
|
FileAccess.Read);
|
||
|
bf = new BinaryFormatter();
|
||
|
fileList = (List<string>)bf.Deserialize(fs);
|
||
|
fs.Close();
|
||
|
|
||
|
// Load the required word index files
|
||
|
foreach(string word in keywords)
|
||
|
{
|
||
|
letter = word[0];
|
||
|
|
||
|
if(!letters.Contains(letter))
|
||
|
{
|
||
|
letters.Add(letter);
|
||
|
ftiFile = Server.MapPath(String.Format(
|
||
|
CultureInfo.InvariantCulture, "fti/FTI_{0}.bin", (int)letter));
|
||
|
|
||
|
if(File.Exists(ftiFile))
|
||
|
{
|
||
|
fs = new FileStream(ftiFile, FileMode.Open, FileAccess.Read);
|
||
|
ftiWords = (Dictionary<string, List<long>>)bf.Deserialize(fs);
|
||
|
fs.Close();
|
||
|
|
||
|
foreach(string ftiWord in ftiWords.Keys)
|
||
|
wordDictionary.Add(ftiWord, ftiWords[ftiWord]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if(fs != null && fs.CanRead)
|
||
|
fs.Close();
|
||
|
}
|
||
|
|
||
|
// Perform the search and return the results as a block of HTML
|
||
|
writer.Write(this.Search(keywords, fileList, wordDictionary, sortByTitle));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Split the search text up into keywords
|
||
|
/// </summary>
|
||
|
/// <param name="keywords">The keywords to parse</param>
|
||
|
/// <returns>A list containing the words for which to search</returns>
|
||
|
private List<string> ParseKeywords(string keywords)
|
||
|
{
|
||
|
List<string> keywordList = new List<string>();
|
||
|
string checkWord;
|
||
|
string[] words = Regex.Split(keywords, @"\W+");
|
||
|
|
||
|
foreach(string word in words)
|
||
|
{
|
||
|
checkWord = word.ToLower(CultureInfo.InvariantCulture);
|
||
|
|
||
|
if(checkWord.Length > 2 && !Char.IsDigit(checkWord[0]) &&
|
||
|
!keywordList.Contains(checkWord))
|
||
|
keywordList.Add(checkWord);
|
||
|
}
|
||
|
|
||
|
return keywordList;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Search for the specified keywords and return the results as a block of
|
||
|
/// HTML.
|
||
|
/// </summary>
|
||
|
/// <param name="keywords">The keywords for which to search</param>
|
||
|
/// <param name="fileInfo">The file list</param>
|
||
|
/// <param name="wordDictionary">The dictionary used to find the words</param>
|
||
|
/// <param name="sortByTitle">True to sort by title, false to sort by
|
||
|
/// ranking</param>
|
||
|
/// <returns>A block of HTML representing the search results.</returns>
|
||
|
private string Search(List<string> keywords, List<string> fileInfo,
|
||
|
Dictionary<string, List<long>> wordDictionary, bool sortByTitle)
|
||
|
{
|
||
|
StringBuilder sb = new StringBuilder(10240);
|
||
|
Dictionary<string, List<long>> matches = new Dictionary<string, List<long>>();
|
||
|
List<long> occurrences;
|
||
|
List<int> matchingFileIndices = new List<int>(),
|
||
|
occurrenceIndices = new List<int>();
|
||
|
List<Ranking> rankings = new List<Ranking>();
|
||
|
|
||
|
string filename, title;
|
||
|
string[] fileIndex;
|
||
|
bool isFirst = true;
|
||
|
int idx, wordCount, matchCount;
|
||
|
|
||
|
// TODO: Support boolean operators (AND, OR and maybe NOT)
|
||
|
|
||
|
foreach(string word in keywords)
|
||
|
{
|
||
|
if(!wordDictionary.TryGetValue(word, out occurrences))
|
||
|
return "<b class=\"PaddedText\">Nothing found</b>";
|
||
|
|
||
|
matches.Add(word, occurrences);
|
||
|
occurrenceIndices.Clear();
|
||
|
|
||
|
// Get a list of the file indices for this match
|
||
|
foreach(long entry in occurrences)
|
||
|
occurrenceIndices.Add((int)(entry >> 16));
|
||
|
|
||
|
if(isFirst)
|
||
|
{
|
||
|
isFirst = false;
|
||
|
matchingFileIndices.AddRange(occurrenceIndices);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// After the first match, remove files that do not appear for
|
||
|
// all found keywords.
|
||
|
for(idx = 0; idx < matchingFileIndices.Count; idx++)
|
||
|
if(!occurrenceIndices.Contains(matchingFileIndices[idx]))
|
||
|
{
|
||
|
matchingFileIndices.RemoveAt(idx);
|
||
|
idx--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(matchingFileIndices.Count == 0)
|
||
|
return "<b class=\"PaddedText\">Nothing found</b>";
|
||
|
|
||
|
// Rank the files based on the number of times the words occurs
|
||
|
foreach(int index in matchingFileIndices)
|
||
|
{
|
||
|
// Split out the title, filename, and word count
|
||
|
fileIndex = fileInfo[index].Split('\x0');
|
||
|
|
||
|
title = fileIndex[0];
|
||
|
filename = fileIndex[1];
|
||
|
wordCount = Convert.ToInt32(fileIndex[2]);
|
||
|
matchCount = 0;
|
||
|
|
||
|
foreach(string word in keywords)
|
||
|
{
|
||
|
occurrences = matches[word];
|
||
|
|
||
|
foreach(long entry in occurrences)
|
||
|
if((int)(entry >> 16) == index)
|
||
|
matchCount += (int)(entry & 0xFFFF);
|
||
|
}
|
||
|
|
||
|
rankings.Add(new Ranking(filename, title, matchCount * 1000 / wordCount));
|
||
|
}
|
||
|
|
||
|
// Sort by rank in descending order or by page title in ascending order
|
||
|
rankings.Sort(
|
||
|
delegate(Ranking x, Ranking y)
|
||
|
{
|
||
|
if(!sortByTitle)
|
||
|
return y.Rank - x.Rank;
|
||
|
|
||
|
return x.PageTitle.CompareTo(y.PageTitle);
|
||
|
});
|
||
|
|
||
|
// Format the file list and return the results
|
||
|
foreach(Ranking r in rankings)
|
||
|
sb.AppendFormat("<div class=\"TreeItem\">\r\n<img src=\"Item.gif\"/>" +
|
||
|
"<a class=\"UnselectedNode\" target=\"TopicContent\" " +
|
||
|
"href=\"{0}\" onclick=\"javascript: SelectSearchNode(this);\">" +
|
||
|
"{1}</a>\r\n</div>\r\n", r.Filename, r.PageTitle);
|
||
|
|
||
|
// Return the keywords used as well in a hidden span
|
||
|
sb.AppendFormat("<span id=\"SearchKeywords\" style=\"display: none\">{0}</span>",
|
||
|
String.Join(" ", keywords.ToArray()));
|
||
|
|
||
|
return sb.ToString();
|
||
|
}
|
||
|
|
||
|
</script>
|