Umbraco网站制作(五) 搜索

一个网站肯定是少不了搜索的啦,虽然Umbraco自带有写好的这个组建下载就可以,但是只能对英文进行搜索。

中文会报错,经过两天研究,我改了一个出来,先说下怎么使用吧~!

前面具体步骤我不做多细致的讲解。

我们先找到Developer在Macros里面创建一个[XSLT]Search文件,名字必须得要这个,好象是保留的,用其他的还出不来!

 

再去创建XSLTSearch.xslt文件。代码如下,这个就是被我改过的。

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE xsl:stylesheet [
  <!ENTITY nbsp " ">
]>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxml="urn:schemas-microsoft-com:xslt"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    xmlns:umbraco.library="urn:umbraco.library"
    xmlns:ps="urn:percipientstudios-com:xslt"
    exclude-result-prefixes="msxml umbraco.library">

  <xsl:output method="xml" omit-xml-declaration="yes" />

  <xsl:param name="currentPage"/>

  <xsl:variable name="searchFields" select="ps:getListParameter(string(//macro/searchFields), 'bodyText')"/>
  <xsl:variable name="previewFields" select="ps:getListParameter(string(//macro/previewFields), 'bodyText')"/>

  <xsl:variable name="search">
    <xsl:choose>
      <xsl:when test="string(umbraco.library:RequestQueryString('search')) != ''">
        <xsl:value-of select="ps:escapeSearchTerms(string(umbraco.library:RequestQueryString('search')))" />
      </xsl:when>
      <xsl:when test="string(umbraco.library:RequestForm('search')) != ''">
        <xsl:value-of select="ps:escapeSearchTerms(string(umbraco.library:RequestForm('search')))" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="''"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:variable name="unescapedSearch" select="ps:unescapeSearchTerms($search)"/>

  <xsl:variable name="searchUpper" select="ps:uppercase(string($search))"/>

  <xsl:template match="/">

     <xsl:choose>
      <xsl:when test="$search = ''">
        <xsl:call-template name="search">
          <xsl:with-param name="items" select="./node[1=2]"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="search">
          <xsl:with-param name="items" select="umbraco.library:GetXmlAll()"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose> 
         
  </xsl:template>

 

  <xsl:template name="search">
    <xsl:param name="items"/>
    <xsl:variable name="possibleNodes" select="$items/descendant-or-self::node[
                                                umbraco.library:IsProtected(@id, @path) = 0
                                                and string(data [@alias='umbracoNaviHide']) != '1']"/>

    <xsl:variable name="matchedNodesIdList">
      <xsl:call-template name="booleanAndMatchedNodes">
        <xsl:with-param name="yetPossibleNodes" select="$possibleNodes"/>
        <xsl:with-param name="searchTermList" select="concat($searchUpper, ' ')"/>
      </xsl:call-template>
    </xsl:variable>

    <!-- get the actual matching nodes as a nodeset -->
    <xsl:variable name="matchedNodes" select="$possibleNodes[contains($matchedNodesIdList, concat(';', concat(@id, ';')))]" />
  <div align="center">
          <xsl:choose>
            <xsl:when test="count($matchedNodes) = 0">
              没有符合 <strong>
                <xsl:value-of select="$unescapedSearch"/>
              </strong> 的项
            </xsl:when>
            <xsl:otherwise>
              项符合 <strong>
                <xsl:value-of select="$unescapedSearch"/>
              </strong> 的有 <strong>
                <xsl:value-of select="count($matchedNodes)"/>
              </strong> 项
            </xsl:otherwise>
          </xsl:choose>
</div>

<ul>
 <xsl:for-each select="$matchedNodes">
 <li>
       <a href="{umbraco.library:NiceUrl(@id)}" class="xsltsearch_title">
           <xsl:value-of select="data [@alias = 'PageHeader']"/>
       </a>
</li>

</xsl:for-each>
</ul>
  </xsl:template>

 

  <xsl:template name="booleanAndMatchedNodes">
    <xsl:param name="yetPossibleNodes"/>
    <xsl:param name="searchTermList"/>

    <xsl:variable name="searchTerm">
      <xsl:value-of select="ps:getFirstElement($searchTermList, ' ')"/>
    </xsl:variable>
    <xsl:variable name="remainingSearchTermList">
      <xsl:value-of select="ps:removeFirstElement($searchTermList, ' ')"/>
    </xsl:variable>

    <xsl:variable name="evenYetPossibleNodes" select="$yetPossibleNodes[attribute::*[(contains($searchFields,name())
                                              and contains(ps:uppercase(umbraco.library:StripHtml(string(.))), $searchTerm)) ]]
                                              |
                                              $yetPossibleNodes[data[(contains($searchFields, concat(',',@alias,','))
                                              and contains(ps:uppercase(umbraco.library:StripHtml(string(.))), $searchTerm)) ]]" />
    <xsl:choose>
      <xsl:when test="string-length($remainingSearchTermList) &gt; 1">
        <!-- continue to search the rest of the terms -->
        <xsl:call-template name="booleanAndMatchedNodes">
          <xsl:with-param name="yetPossibleNodes" select="$evenYetPossibleNodes"/>
          <xsl:with-param name="searchTermList" select="$remainingSearchTermList"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <!-- finished searching: return a list of the attribute @id's of the currently possible nodes as the final set of matched nodes -->
        <xsl:variable name="nodeIDList">
          <xsl:text>;</xsl:text>
          <xsl:for-each select="$evenYetPossibleNodes">
            <!-- @id for this node -->
            <xsl:value-of select="@id"/>
            <xsl:text>;</xsl:text>
          </xsl:for-each>
        </xsl:variable>

        <!-- return the actual list of id's -->
        <xsl:value-of select="$nodeIDList"/>
      </xsl:otherwise>
    </xsl:choose>

  </xsl:template>

  <msxsl:script language="C#" implements-prefix="ps">
    <![CDATA[

    public string uppercase(string s)
    {
        return s.ToUpper();
    }

    public string escapeSearchTerms(string data)
    {
        return data.Replace(Convert.ToString((char)38), "&amp;");
    }

    public string unescapeSearchTerms(string data)
    {
        return data.Replace("&amp;", Convert.ToString((char)38));
    }

    public string getFirstElement(string delimitedList, string delimiter)
    {
        // strip all leading delimiters
        while (delimitedList.IndexOf(delimiter) == 0)
            delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();

        if (delimitedList.Length == 0)
            return "";

        // searching on a phrase
        if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1)
            return delimitedList.Substring(1, delimitedList.IndexOf("'", 1) - 1);

        if (delimiter == " " && delimitedList.Substring(0, 1) == "\"" && delimitedList.IndexOf("\"", 1) > -1)
            return delimitedList.Substring(1, delimitedList.IndexOf("\"", 1) - 1);

        // only one element
        if (delimitedList.IndexOf(delimiter) == -1)
            return delimitedList.Trim();

        // return first element
        return delimitedList.Split(delimiter.ToCharArray()[0])[0].Trim();
    }

    public string removeFirstElement(string delimitedList, string delimiter)
    {
        string firstElement = getFirstElement(delimitedList, delimiter);

        // handle phrase delimiters
        if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1)
            return delimitedList.Remove(0, firstElement.Length + 2).Trim();

        if (delimiter == " " && delimitedList.Substring(0, 1) == "\"" && delimitedList.IndexOf("\"", 1) > -1)
            return delimitedList.Remove(0, firstElement.Length + 2).Trim();

        while (delimitedList.IndexOf(delimiter) == 0)
            delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();

        return delimitedList.Remove(0, firstElement.Length).Trim();
    }

   
    public string getListParameter(string value, string defaultValue)
    {
        /* Here is the XSLT way to do this, though it is slower and not as fault-tolerant as the C# function:
        <xsl:variable name="previewFields">
         <xsl:choose>
            <!-- set default value -->
            <xsl:when test="string(//macro/previewFields) = ''">,bodyText,description,</xsl:when>
            <xsl:otherwise>
              ,<xsl:value-of select="string(//macro/previewFields)"/>,
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>-->
        */

        // remove all spaces
        value = value.Replace(" ", "");
        defaultValue = defaultValue.Replace(" ", "");

        if (value == "")
            return "," + defaultValue + ",";
        else
            return "," + value + ",";
    }

    ]]>
  </msxsl:script>
</xsl:stylesheet>

 

 

然后在[XSLT]Search这个文件中有改动如下

指定xslt文件。然后Parameters里面设置如下参数

有点多,虽然这些参数在我xslt中没用到,被我改了,但是,少了也出不来,这个原因还在寻找。有知道也请交流下。

如果闲麻烦的朋友可以直接先下载一个他写好的搜索这块的代码,然后把我的xslt文件代码粘进去也可以,具体如何去下载,我会在下一篇文章中讲解。

接着,我们在Document Type中添加一个Seache Page的文件类型。

具体步骤像前几篇说到的。最后我们编辑模板。

 

<?UMBRACO_MACRO macroAlias="XSLTSearch" source="-1" searchFields="@nodeName,PageTitle,secondaryTitle,bodyText" previewFields="bodyText,secondaryTitle,PageTitle" searchBoxLocation="TOP" previewType="CONTEXT" resultsPerPage="5" previewChars="100" showPageRange="1" showOrdinals="1" showScores="0" showStats="1"></?UMBRACO_MACRO>

 

这是Seache Page模板中的内容,就是掉用搜索的xslt,参数那么多,就是因为上面我们定义的~!

注意选择:Master template 这样一个搜索页面就OK啦~!

 

接下来比如我们想要在主模板的一个div里面把我们的搜索放上,该如何做呢?

我们找到主模板在需要搜索的地方放上如下代码:

<!--  搜索  -->
 <form method="post" action="/Search.aspx">
   <input type="text" name="search" /><input type="submit" name="submit" value="" class="Submit" style="border-style: none; background-image: url('../data/images/Seach.jpg'); background-repeat: no-repeat; width: 23px;"/>
  </form>
就是一个表单,这个表单也是同样提交给我的Seach页面效果如图:

这个时候搜索就完啦~!效果请看

符合的内容都出来了~!说明下,这里的搜索不当搜索标题,而且也会搜索内容。但是在数据特别多的时候就显的力不从心啦,

因为Umbraco的数据读取都是从数据到XML的,而搜索是读取整个XML文件,当内容特别多的时候,就会比较慢啦~!但是对于小网站

门户网站组够用了,而且效果都还不错~!

 

希望能给大家帮助,如果有更好的方法还请多多交流。

 

posted @ 2008-07-25 14:19  李路平  阅读(2858)  评论(1编辑  收藏  举报