Содержание
Помогаем ботам найти все страница сайта
Проблема: есть достаточно большой сайт, у которого есть карта в формате XML. Есть бот, который этот сайт индексирует. Но бот не может найти страницы, имеющие уровень вложенности больше трёх. Нужно помочь боту проиндексировать весь сайт.
Самый простой способ — создание страницы, в которой будут перечислены все страницы сайта и размещение на неё ссылки из подвала сайта. Идеальный кандидат на такую страницу — карта сайта в формате XML. Проблема в том, что не все боты утруждают себя разбором XML-карт. Для таких ботов карту нужно преобразовывать в формат HTML.
Как и в другом похожем случае, на помощь приходит преобразование XSL.
Пример шаблона стилей XML:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:x="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="x">
<xsl:output method="xml" indent="yes" encoding="UTF-8" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/x:urlset">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Site Map</title>
</head>
<body>
<h1><a href="http://blog.sjinks.pro/">Карта сайта</a></h1>
<ul>
<xsl:apply-templates select="x:url">
<xsl:sort select="lastmod" order="descending"/>
</xsl:apply-templates>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="/x:urlset/x:url">
<li><strong><a href="{x:loc}"><xsl:value-of select="x:loc" disable-output-escaping="yes"/></a></strong><xsl:if test="x:lastmod"> (<xsl:value-of select="x:lastmod" disable-output-escaping="yes"/>)</xsl:if></li>
</xsl:template>
</xsl:stylesheet>
Преобразование выполняется так:
xsltproc -o /path/to/sitemap.html /path/to/sitemap2html.xml /path/to/sitemap.xml
Можно выполнение xsltproc повесить на крон и наслаждаться результатом.
Как сделать не более N ссылок на файл
Продолжение статьи «Генерация карты сайта в HTML из XML».
В этой части мы рассмотрим, как сделать так, чтобы на одной генерируемой странице располагалось не более определённого количества ссылок.
Нам понадобятся дополнительно:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:x="http://www.sitemaps.org/schemas/sitemap/0.9">
<xsl:output method="text" media-type="text-plain" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/x:urlset/x:url">
<xsl:value-of select="x:loc" disable-output-escaping="yes"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
и немного фантазии
Алгоритм работы простой:
- Преобразовываем исходную карту в текстовый список адресов (один URL на строку)
- Разбиваем файл на несколько частей с заданным количеством строк
- Преобразовываем каждый из полученных файлов в XML
- Преобразовываем полученные XML-файлы в HTML
Пункты 3 и 4 можно совместить: вместо генерации XML-файла можно сразу генерировать HTML. Но на всякий случай будем генерировать и XML, и HTML.
Получим такой скрипт:
#! /bin/sh
xsltproc -o urls.txt sitemap2txt.xsl sitemap.xml
split -d -l 100 urls.txt map
for i in map*; do
awk '
BEGIN {
print "<?xml version=\"1.0\"?>\
<urlset\
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\
xsi:schemaLocation=\"http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd\"\
xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">"
}
{
print "<url><loc>"$1"</loc></url>"
}
END {
print "</urlset>"
}
' $i > site$i.xml
xsltproc -o site$i.html sitemap2html.xsl site$i.xml
done
Всё просто!™
Автоматизация: перекладываем работу на Google XML Sitemaps
В данной статье будет рассмотрен вопрос модификации плагина Google XML Sitemaps с целью добавления поддержки автоматической генерации HTML-версии карты сайта; как и в предыдущих статьях, преобразование будет осуществляться средствами XSL.
В первой части статьи мы рассматривали вариант, основанный на использовании утилиты xsltproc. Предполагалось, что генерация HTML-версии карты сайта осуществляется с использованием cron. Создание карты по расписанию означает, что построение HTML-карты будет запаздывать на некоторое время; а если не сравнивать время модификации XML- и HTML-версий карт, получим бесполезные вызовы xsltproc.
Те, кто используют WordPress, очень часто для автоматического построения карты сайта используют плагин Google XML Sitemaps; для них предлагается вариант с модификацией кода плагина для автоматической генерации HTML-карты.
Плагин позволяет задавать свою таблицу стилей XSLT:
Мы изменим плагин таким образом, чтобы при заданной таблице стилей XSL плагин создавал HTML-файл с результатами преобразований XSL.
В файле sitemap-core.php ищем такой кусок кода:
if($this->GetOption("b_xml")) {
if($this->_fileHandle && fclose($this->_fileHandle)) {
$this->_fileHandle = null;
$status->EndXml(true);
$pingUrl=$this->GetXmlUrl();
} else $status->EndXml(false,"Could not close the sitemap file.");
После него добавляем такой:
if (class_exists('XSLTProcessor', true)) {
$file = $this->GetXmlPath();
$styleSheet = ($this->GetDefaultStyle() && $this->GetOption('b_style_default') === true ? $this->GetDefaultStyle() : $this->GetOption('b_style'));
if (!empty($styleSheet)) {
$xsl = new DOMDocument();
$xsl->load($styleSheet);
$xml = new DOMDocument();
$xml->load($file);
$proc = new XSLTProcessor();
$proc->importStyleSheet($xsl);
$proc->transformToURI($xml, 'file://' . str_replace('.xml', '.html', $file));
}
}
Данный код требует PHP 5 и расширения XSLT (в Debian/Ubuntu оно предоставляется пакетом php5-xsl). Код получает имя файла с картой сайта и адрес таблицы стилей (этот адрес должен быть задан абсолютным URL); XML и XSL скармливаются XSLT Processor’у, результат записывается в файл с тем же именем, что и карта сайта XML, но с расширением .html.
Теперь при каждом построении карты сайта будет создаваться и HTML-версия.
Тем, кто любит патчи (патч кумулятивный, исправляет и некоторые другие недостатки плагина):
--- sitemap-core.php.orig 2010-08-16 10:49:16.000000000 +0300
+++ sitemap-core.php 2010-11-28 02:10:08.000000000 +0200
@@ -1654,9 +1654,9 @@
$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<' . '?xml-stylesheet type="text/xsl" href="' . $styleSheet . '"?' . '>'));
}
- $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generator=\"wordpress/" . get_bloginfo('version') . "\""));
- $this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
- $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date(get_option("date_format") . " " . get_option("time_format")) . "\""));
+// $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generator=\"wordpress/" . get_bloginfo('version') . "\""));
+// $this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
+// $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date(get_option("date_format") . " " . get_option("time_format")) . "\""));
//All comments as an asso. Array (postID=>commentCount)
$comments=($this->GetOption("b_prio_provider")!=""?$this->GetComments():array());
@@ -2172,6 +2172,22 @@
$status->EndXml(true);
$pingUrl=$this->GetXmlUrl();
} else $status->EndXml(false,"Could not close the sitemap file.");
+
+ if (class_exists('XSLTProcessor', true)) {
+ $file = $this->GetXmlPath();
+ $styleSheet = ($this->GetDefaultStyle() && $this->GetOption('b_style_default') === true ? $this->GetDefaultStyle() : $this->GetOption('b_style'));
+ if (!empty($styleSheet)) {
+ $xsl = new DOMDocument();
+ $xsl->load($styleSheet);
+
+ $xml = new DOMDocument();
+ $xml->load($file);
+
+ $proc = new XSLTProcessor();
+ $proc->importStyleSheet($xsl);
+ $proc->transformToURI($xml, 'file://' . str_replace('.xml', '.html', $file));
+ }
+ }
}
if($this->IsGzipEnabled()) {
@@ -2514,9 +2530,9 @@
* @return int The time in seconds
*/
function GetTimestampFromMySql($mysqlDateTime) {
- list($date, $hours) = split(' ', $mysqlDateTime);
- list($year,$month,$day) = split('-',$date);
- list($hour,$min,$sec) = split(':',$hours);
+ list($date, $hours) = explode(' ', $mysqlDateTime);
+ list($year,$month,$day) = explode('-',$date);
+ list($hour,$min,$sec) = explode(':',$hours);
return mktime(intval($hour), intval($min), intval($sec), intval($month), intval($day), intval($year));
}
