Генерация карты сайта в HTML из XML

программирование

Помогаем ботам найти все страница сайта

Проблема: есть достаточно большой сайт, у которого есть карта в формате 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>&#x000A;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

и немного фантазии :)

Алгоритм работы простой:

  1. Преобразовываем исходную карту в текстовый список адресов (один URL на строку)
  2. Разбиваем файл на несколько частей с заданным количеством строк
  3. Преобразовываем каждый из полученных файлов в XML
  4. Преобразовываем полученные 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));
    }

 

Related posts

Оставить комментарий