GoogleやBingなどの検索エンジンにクロールしてほしいページを指定する場合、サイトマップを表すXMLファイル(以下、sitemap.xml)を配置するのが一般的だが、手動でこれを記述するのはつらいので、通常はPHPなどによって自動生成することが多い。
今回はgulpで静的なhtmlを大量に書き出す案件で、sitemap.xmlが必要になったので、gulpというかNode.jsでsitemap.xmlを書き出す方法をメモしておく。
予備知識
sitemap.xmlのフォーマット
sitemap.xmlのフォーマットは下記のようにシンプルだ。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://kenzauros.com/</loc>
<priority>1</priority>
<changefreq>always|hourly|daily|weekly|monthly|yearly|never</changefreq>
<lastmod>2015-09-17</lastmod>
</url>
<url>...</url>
</urlset>
基本的にはurlset
というルート要素の下に必要なだけurl
要素が並ぶ。
urlの下の要素などに関しては Sitemapsの記述方法 – インフォセンター – Yahoo!検索 などを参照されたい。
Node.jsでのXML書き出し
Node.jsでXMLを生成するにはxml2jsを使う。あまり需要がないのか、情報が少ないが、とりあえず使うだけならそんなに難しくない。
xml2jsをインストールしておく。
npm install xml2js
詳しくは下記ページを参照のこと。
これに加えて、ファイルに書き出すためにfsパッケージも必要だが、これは標準でインストールされているので、jsファイル内でrequireするだけでよい。
ソースコード
xml2jsとfsを使用したsitemap.xmlの書き出しは次のような感じ。
// ルートURL
var baseUrl = 'http://kenzauros.com/';
// 各ページのurl要素
var urls = [];
// lastmod用日付生成
var today = new Date();
var date = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2) + '-' + ('0' + today.getDate()).slice(-2);
// トップページ
urls.push({ loc:baseUrl, priority:1.0, changefreq:"weekly", lastmod:date });
// 下層ページ
urls.push({ loc:baseUrl+filename, priority:0.6, changefreq:"weekly" });
var fs = require('fs');
var xml2js = require('xml2js');
// urlsetをルート要素としてXMLビルダーを初期化
var builder = new xml2js.Builder({ rootName : "urlset" });
// urlsをセット
var xml = builder.buildObject({ url : urls });
// xmlns追加
xml = xml.replace(/<urlset>/, '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">')
// ファイル書き出し
fs.writeFile('sitemap.xml', xml, function (err) {
console.log('Sitemap updated.');
});
簡単な説明
xml2js.Builderを使用することで、JavaScriptのオブジェクトからXMLに直接変換できるので、ソース自体はシンプルになった。
このとき、オブジェクトに配列を含んでいれば、自動的にそのキー名で複数の要素が生成されるので、わかりやすい。
- url/locは絶対URLで表記するので
baseUrl
に基本となるURLを定義しておく。 - urlを格納する配列
urls
には{ loc:baseUrl, priority:1.0, changefreq:"weekly", lastmod:date }
のようなオブジェクトをurls.push
でどんどん追加していく。 - fsとxml2jsを
require
する。 xml2js.Builder
をnew
する(ルート要素名(rootName)にurlsetを指定)。builder.buildObject
でurlを格納した配列をxmlに変換。<urlset>
タグに名前空間指定がないので追加。fs.writeFile
でファイルを書き出す。
名前空間のあたりは多少泥臭いが、xml2jsに名前空間を指定する方法がなさそうなので、これでしのいだ。
以上で所望のsitemap.xmlを得ることができた。