xml2jsを使って複数のRSS 2.0をマージするパッケージ、FeedMixを作った。手元で結構前から使っていたGruntタスクをNode.jsパッケージにして、それを叩くだけのGruntタスクを同梱するという形にした。

混ぜたいRSSファイルを配列としてmerge()の引数に指定する。XMLファイルではない場合はxml2jsが、RSSファイルではなさそうな場合はFeedMixがそれぞれ例外を吐いて落ちる。落ちる。

var feedmix = require('feedmix');
var fs = require('fs');

var a = f.readFileSync('a.rss', 'utf8');
var b = f.readFileSync('b.rss', 'utf8');
var c = f.readFileSync('c.rss', 'utf8');
var m = feedmix.merge([a, b, c], {
  trim: true
});

これでmの内容がb.rssc.rssのすべてのitem要素をa.rssへ混ぜ込んだJavaScriptオブジェクトになる。itempubDate要素の値を使ってソートされるが、切り詰められたりはしない。channel要素はa.rssのものが採用されるが、lastBuildDate要素の値のみ最初のitem要素のpubDate要素の値がコピーされ書き換えられる。

console.log(feedmix.stringify(m, {
  cdata: true,
  xmldec: {
    encoding: 'UTF-8',
    version: '1.0'
  }
}));

XMLへの変換はstringify()へパース結果のオブジェクトを渡して行う。xml2jsのビルダーの単なるラッパーで、特に何もしない。

またmerge()では第二引数にxmljsのパーサーのオプションが、strigify()ではxml2jsのビルダーのオプションがそれぞれ指定できる。ただしパーサーのexplicitArrayオプションはパース後のオブジェクトの構造を変えてしまうので、強制的にtrueにしているため指定しても効果はない。他にも指定するとおかしくなるオプションがあるかもしれない。


同梱されているGruntタスクも凝ってはいない。

feedmix: {
  main: {
    options: {
      builder: {
        cdata: true,
        xmldec: {
          encoding: 'UTF-8',
          version: '1.0'
        }
      },

      parser: {
        trim: true
      }
    },

    dest: 'build/feed',
    src: [
      'src/feed/index.rss',
      'build/blog/feed'
    ]
  }
}

こちらはsrcでファイルを指定してやるとdestにマージした結果を吐いてくれる。動的マッピングだと配列の順序が思ったようにいかない可能性があるので、普通に指定したほうが良いだろう。options.builderoptions.parser経由でstringify()merge()に渡すオプションを指定することはできるので、入出力もモジュールと同等に制御することができる。


RSS 1.0とかAtomとかもうよく知らないので無視した。RSS 0.9xなどは通ってしまいそうな気がする。