3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

FeedjiraでRSSの独自タグ拡張

Last updated at Posted at 2021-05-13

FeedjiraでRSSの独自タグ拡張

feedjira gemを利用した独自タグ拡張の方法について説明します。

Feedjiraには add_common_feed_entry_element というメソッドがあります。
https://www.rubydoc.info/github/feedjira/feedjira/master/Feedjira/Feed#add_common_feed_entry_element-class_method

ドキュメントがなくコードを読んでも
https://github.com/feedjira/feedjira/blob/master/lib/feedjira/feed.rb#L18

だいぶ深追いしないと把握できないのでとりあえずどういう動きをするのかを説明します。

シンプルな構造の場合(ネストしていない)

以下のような my:tag という独自タグが含まれるRSSがあったとします

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:media="http://search.yahoo.com/mrss/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  >
  <channel>
    <title>サイトタイトル</title>
    <link>https://example.com/</link>
    <description>サイト説明</description>
    <pubDate>Mon, 19 Jun 2020 09:00:00 7JunJST</pubDate>
    <language>ja</language>
    <copyright>誰か</copyright>
    <item>
      <title><![CDATA[タイトル]]></title>
      <link>https://example.com/item/1</link>
      <guid>https://example.com/item/1</guid>
      <description><![CDATA[ディスクリプション]]></description>
      <pubDate>Mon, 19 Jun 2020 02:55:52 2JunJST</pubDate>
      <content:encoded><![CDATA[
        コンテンツ本文
      ]]></content:encoded>
      <!-- 独自タグ -->
      <my:tag link="https://example.com/" title="example">独自タグ</my:tag>
      <!-- /独自タグ -->
    </item>
  </channel>
</rss>

独自タグ部分をparseしてFeedjiraのentryオブジェクトに追加したい場合

<my:tag link="https://example.com/" title="example">独自タグ</my:tag>

普通にFeedjira::parseしただけでは取得できません。

そこで add_common_feed_entry_element の登場です。

Feedjira::Feed.add_common_feed_entry_element("my:tag", as: :my_tag)

このように書くことでFeedjiraのentryオブジェクトにmy_tagという名前で追加されタグのinner textを取得することが出来ます。

Feedjira::Feed.add_common_feed_entry_element("my:tag", :as => :my_tag)
resp = Faraday.get('http://example.com/feed')
feed = Feedjira.parse(resp.body)
feed.entries.each do |entry|
  puts entry.my_tag
  # stdout: 独自タグ
end

link アトリビュートや title アトリビュートが必要な場合は value にアトリビュート名を設定します。

Feedjira::Feed.add_common_feed_entry_element("my:tag", as: :my_tag)
Feedjira::Feed.add_common_feed_entry_element("my:tag", as: :my_tag_title, value: :title)
Feedjira::Feed.add_common_feed_entry_element("my:tag", as: :my_tag_link, value: :link)
resp = Faraday.get('http://example.com/feed')
feed = Feedjira.parse(resp.body)
feed.entries.each do |entry|
  puts entry.my_tag
  # stdout: 独自タグ
  puts entry.my_tag_title
  # stdout: example
  puts entry.my_tag_link
  # stdout: https://example.com/
end

ネストしていないシンプルな構造の独自タグの場合は add_common_feed_entry_element で簡単に取得することが出来ます。

複雑な構造の場合(ネストしている)

以下のようなRSSがあったとします。

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:media="http://search.yahoo.com/mrss/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  >
  <channel>
    <title>サイトタイトル</title>
    <link>https://example.com/</link>
    <description>サイト説明</description>
    <pubDate>Mon, 19 Jun 2020 09:00:00 7JunJST</pubDate>
    <language>ja</language>
    <copyright>誰か</copyright>
    <item>
      <title><![CDATA[タイトル]]></title>
      <link>https://example.com/item/1</link>
      <guid>https://example.com/item/1</guid>
      <description><![CDATA[ディスクリプション]]></description>
      <pubDate>Mon, 19 Jun 2020 02:55:52 2JunJST</pubDate>
      <content:encoded><![CDATA[
        コンテンツ本文
      ]]></content:encoded>
      <!-- ここから独自拡張 -->
      <my:nested_tag>
        <my:child link="https://exmaple.com/1" title="example1" />
        <my:child link="https://exmaple.com/2" title="example2" />
        <my:child link="https://exmaple.com/3" title="example3" />
      </my:nested_tag>
      <!-- /ここまで独自拡張 -->
    </item>
  </channel>
</rss>

このような場合は add_common_feed_entry_element を普通に使用しただけでは思った通りに取得が出来ません。

Feedjira::Feed.add_common_feed_entry_element("my:nested_tag", as: :nested_tag)
# valueを指定しないとinner textを返すのでブランクになる

Feedjira::Feed.add_common_feed_entry_element("my:child", as: :sponsored_link, value: :link)
# my:childから取得を試みた場合は3件のうち1件目のみが取得できる

どうするか?

add_common_feed_entry_element には class オプションにparserを渡せる仕組みがあります。
ドキュメントにはありませんが以下のコードから class を渡せるということがわかります。

公式のコードを参考にして独自parserクラスを定義
module Feedjira
  module Parser
    class MyNestedTag
      include SAXMachine

      elements :"my:child", as: :link, value: :link
      elements :"my:child", as: :title, value: :title
    end
  end
end
classに独自parserクラスを指定してみる
Feedjira::Feed.add_common_feed_entry_element("my:nested_tag", as: :nested_tag, class: Feedjira::Parser::MyNestedTag)
resp = Faraday.get('http://example.com/feed')
feed = Feedjira.parse(resp.body)
feed.entries.each do |entry|
  entry.nested_tag.each do |ads|
    puts ads.link
    puts ads.title
  end
  # stdout:
  #   https://exmaple.com/ads/1
  #   example1
  #   https://exmaple.com/ads/2
  #   example2
  #   https://exmaple.com/ads/3
  #   example3
end

意図した通りに動きました。
parserクラスの書き方自体は公式のparserが参考になるのでそちらを参考にすると良いと思います

公式parser: https://github.com/feedjira/feedjira/tree/master/lib/feedjira/parser

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?