Добавление предложений в поисковый плагин

Влад Мержевич

Поисковик Google был один из первых, кто добавил к своему поиску предложение популярных запросов — вы набираете текст и сразу же получаете список слов начинающихся с введенных символов. В дальнейшем эта технология стала настолько популярна, что теперь ее можно встретить повсеместно. Также она включена и в спецификацию OpenSearch, на основе которой работает поисковый плагин для браузера.

Подключить возможность показывать предложения в поиске браузера достаточно просто, для этого следует в файл search.xml добавить следующую строку.

<Url type="application/x-suggestions+json" template="http://mysite.ru/suggestion.php?q={searchTerms}"/>

Здесь файл suggestion.php отвечает за получение запроса по методу GET и отдаче результатов. Сам запрос вставляется вместо ключевого слова {searchTerms}, оно стандартно и неизменно, а переменная q произвольна. Путь к файлу suggestion.php, а также его имя также зависит от предпочтений разработчика и легко может быть заменено на другое.

Сам файл search.xml, к примеру, для сайта htmlbook.ru с учетом вышеизложенного выглядит следующим образом.

Пример 1

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
  <ShortName>htmlbook.ru</ShortName>
  <Description>Поиск по htmlbook.ru</Description>
  <Image height="16" width="16" type="image/x-icon">http://htmlbook.ru/favicon.ico</Image>
  <Url type="text/html" method="GET" xmlns:referrer="http://a9.com/-/opensearch/extensions/referrer/" 
       template="http://htmlbook.ru/sites/search/?q={searchTerms}"/>
  <Url type="application/x-suggestions+json" 
       template="http://htmlbook.ru/sites/search/suggestion.php?q={searchTerms}"/>
  <InputEncoding>UTF-8</InputEncoding>
  <AdultContent>false</AdultContent>
</OpenSearchDescription>

Формат данных

Файл suggestion.php при запросе возвращает следующие данные в формате JSON (JavaScript Object Notation, представление объектов JavaScript).

  • Строка запроса
  • Результаты поиска
  • Примечания
  • Адрес страницы

Общее количество результатов не должно превышать десяти. Обязательно должны возвращаться строка запроса и результаты поиска, примечания и адреса при желании можно опустить.

В качестве примера возьмем цвета. Пользователь вводит символы «ма», на которые начинаются цвета из нашего списка: магнолия (f8f4ff), малиновый (dc143c), мандариновый (f28500), маренго (4c5866). В скобках указано значение цвета в шестнадцатеричной системе, оно же будет и адресом страницы. В итоге, результат будет таким.

Пример 2

["ма",
 ["магнолия",
  "малиновый",
  "мандариновый",
  "маренго"],
 ["http://mysite.ru/f8f4ff",
  "http://mysite.ru/dc143c",
  "http://mysite.ru/f28500",
  "http://mysite.ru/4c5866"]]

Каждый блок отправляемых данных берется в квадратные скобки и сам результат целиком тоже, блоки разделяются между собой запятыми. Вначале пишется вводимое пользователем слово, затем в квадратных скобках результат поиска, последними идут адреса. В данном примере примечания опущены за ненадобностью.

В общем случае возвращаемые данные имеют следующий формат.

["строка запроса",
 ["результат поиска 1", " результат поиска 2", ...],
 ["примечание 1", "примечание 2", ...],
 ["адрес  1", "адрес 2", ...]
]

Браузер Firefox не отображает примечания, несмотря на их наличие, а Internet Explorer выводит примечания ниже результатов поиска.

На этом простые вещи заканчиваются, и начинается много, много программирования. В качестве основы я выбрал PHP за его популярность и некоторую простоту.

Программируем файл suggestion.php

Отправка данных браузеру разбивается на три задачи:

  1. получение введенного пользователем текста;
  2. выбор данных, начинающихся с указанных символов;
  3. отправка полученных данных в формате JSON.

Получение данных через метод GET осуществляется через массив $_GET['q'], где q это переменная, задаваемая в файле search.xml (пример 1). Таким образом, получение данных сводится к следующей строке.

$query = $_GET['q'];

Выбор нужных данных зависит от способа их хранения, это может быть база данных, текстовый файл или массив. В качестве примера возьмем вариант с массивом.

Пример 3

<?php
$url = 'http://mysite.ru/'; // Адрес сайта
$data = array ( // Массив с данными
  'color' => array ('белый', 'желтый', 'магнолия', 'малиновый', 'мандариновый', 'маренго', 'черный'),
  'url' => array ('ffffff', 'ffff00', 'f8f4ff', 'dc143c', 'f28500', '4c5866', '000000')
);

// 1. Получаем запрос
// --------------------------------------
$query = mb_strtolower($_GET['q']);
$query = mb_convert_encoding($query, 'UTF-8', 'windows-1251');
$len = strlen($query); // Длина строки 

// 2. Ищем совпадения
// --------------------------------------
// Введено не меньше двух символов 
if (isset($query) && $len >= 2) {
  $i = 0; // Обнуляем счетчик
  $res = array(); // Массив с результатами
  // Пробегаемся по всему массиву
  foreach ($data['color'] as $item) {
    // Ограничиваем вывод 10 результатами
    if ($i >= 9) break;
    if ($query == substr($item, 0, $len)) {
    // Есть совпадения
    $res[] = $i;
  }
  $i++;
  }

// 3. Обрабатываем и выводим результаты
// --------------------------------------
  if (isset($res[0])) {
    $output = '["'. $query . '",' . "\n";
    $output .= '[';
    $n = count($res); // Количество результатов
    // Результаты поиска
    for ($i=0; $i<$n; $i++) {
      if ($i == $n-1) $semi = '"'; // в конце убираем запятую
      else $semi = '",';
      $output .= '"' . $data['color'][$res[$i]] . $semi . "\n";
    }
    $output .= "],\n";
    $output .= '[';
    // Адреса
    for ($i=0; $i<$n; $i++) {
      if ($i == $n-1) $semi = '"'; // в конце убираем запятую
      else $semi = '",';
      $output .= '"' . $url . $data['url'][$res[$i]] . $semi . "\n";
    }
    $output .= "]]";
    echo $output;
  }
} 
?>

Результат работы программы можно проверить, если обратиться к файлу по адресу suggestion.php?q=ма. При правильной работе будет выведен текст как в примере 2.

Internet Explorer

Браузер IE, начиная с версии 8.0, не только поддерживает спецификацию OpenSearch, но и расширяет ее за счет использования XML. Кроме формата JSON данные можно возвращать и в формате XML (eXtensible Markup Language, расширяемый язык разметки), причем не только текст, но и картинки. Так, пример 2 для этого формата поменяет свой вид и будет иметь следующую структуру.

<?xml version="1.0"?>
<SearchSuggestion xmlns="http://schemas.microsoft.com/Search/2008/suggestions">
<Query>ма</Query>
 <Section>
  <Item>
   <Text>магнолия</Text>
   <Image source="http://mysite.ru/f8f4ff.png" alt="Магнолия" width="75" height="75"/>
   <Url>http://mysite.ru/f8f4ff</Url>
  </Item>
  <Item>
   <Text>малиновый</Text>
   <Image source="http://mysite.ru/ dc143c.png" alt="Малиновый" width="75" height="75"/>
   <Url>http://mysite.ru/dc143c</Url>
  </Item>
  <Item>
   <Text>мандариновый</Text>
   <Image source="http://mysite.ru/ f28500.png" alt="Мандариновый" width="75" height="75"/>
   <Url>http://mysite.ru/f28500</Url>
  </Item>
  <Item>
   <Text>маренго</Text>
   <Image source="http://mysite.ru/4c5866.png" alt="Маренго" width="75" height="75"/>
   <Url>http://mysite.ru/4c5866</Url>
  </Item>
 </Section>
</SearchSuggestion>

Несмотря на некоторые преимущества, формат XML для поиска не универсален и работает только для браузера IE. Поэтому подробностей касаться не буду, заинтересованным рекомендую русскоязычную статью на сайте Microsoft, посвященную создание поискового плагина под Internet Explorer.

Сайты по теме

Не выкладывайте свой код напрямую в комментариях, он отображается некорректно. Воспользуйтесь сервисом cssdeck.com или jsfiddle.net, сохраните код и в комментариях дайте на него ссылку. Так и результат сразу увидят.