JavaでRSSを作成・読込するライブラリとしてROMEが有名である。現在(2016年4月)の最新バージョンは1.7であるが、利用方法を調べてみるとバージョン1.0あたりの導入方法くらいしか見つからなかった。理由としては公式ウェブサイトがバージョン1.0までしか更新しておらずGithub上の最新リソースへのリンクがないことや、googleで検索する際にイタリアのローマが検索に引っかかったり、バージョンが上がって依存ライブラリが多くなったことや……まあ、いろいろ問題があるような気がする。
今回は、筆者のように「ライブラリ使うなら最新バージョン使うのが普通だよね」という人向けに、ROME1.7の利用方法についてみていく。JavaFXと銘打っているが、ROME自体はwebアプリやAndroidでの利用も可能である。
■ ROMEライブラリ
ROMEライブラリはRSSを作成・読込を行うためのライブラリである。ライセンスはApache License 2.0であるため、商用利用も可能である。
RSSには多くの規格があるが、ROMEライブラリではそれらを自動的に判別して読み込んでくれるのがよい点。また、ApacheにもRSSリーダであるFeedparserというプロジェクトがあるが、Feedparserの公式サイトでも気に入らなければROMEを使えばいいと書いてあるほど評価は高いようだ(*1)。
ROME及び依存ライブラリは以下のとおりである。以下のライブラリをクラスパスに登録する必要がある(クラスパスの登録方法は
別記事参照)。
ライブラリ名 |
必要ファイル |
ダウンロード場所 |
ROME 1.7 |
rome-1.7.0-SNAPSHOT.jar |
・Github 「rometools/rome」
→最新ソース。コンパイルにはMavenが必要。
・MVN Repository
→コンパイル済Jar。ただしver1.6 |
ROME-utils 1.6 |
rome-utils-1.7.0-SNAPSHOT.jar |
・MVN Repository
→ページ下部のリンク |
JDOM 2.0.6 |
jdom2-2.0.6.jar |
・MVN Repository
→ページ下部のリンク |
SLF4J 1.7.21 |
slf4j-api-1.7.21.jar
slf4j-simple-1.7.21.jar |
・MVN Repository
→ページ下部のリンク |
Apache HTTPClient(*) |
commons-codec-1.9.jar
commons-logging-1.2.jar
httpclient-4.5.2.jar
httpclient-cache-4.5.2.jar
httpclient-win-4.5.2.jar
httpcore-4.4.4.jar
httpmime-4.5.2.jar |
・Apache Software「HttpComponents Downloads」
→最新版のzipファイルを解凍し、左記のファイルを取得 |
* : キャッシュ機能を利用する場合のみ必要。以前はROME Fetcherライブラリでキャッシュを行うのが普通だったが、ROME1.6からは非推奨となった。代わりにHttpClientを利用するよう推奨している(*2)。
ROMEに関するチュートリアルは公式サイトに存在する(
*3)。ただし、バージョン1.0を前提としたチュートリアルなので、少し異なる箇所があるかもしれない。
■ サンプル・プログラム(RSS読込)
以下にROME1.7を利用してRSSを読込・表示するサンプルプログラムを示す。サンプルでは、イラストレイター向けのSNS『Drawr』のRSSを読み込み、表示している。
◇サンプルコード
package application;
import java.awt.Desktop;
import java.io.InputStream;
import java.net.URI;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import com.rometools.rome.feed.synd.SyndEntryImpl;
import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.SyndFeedInput;
import com.rometools.rome.io.XmlReader;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestRomeRead extends Application
{
// 定数
protected static final int WIDTH = 300;
protected static final int HEIGHT = 500;
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception
{
// フォント色がおかしくなることへの対処
System.setProperty( "prism.lcdtext" , "false" );
// シーングラフの作成
ScrollPane scroll = new ScrollPane();
VBox root = new VBox();
scroll.setContent( root );
scroll.setHbarPolicy( ScrollBarPolicy.NEVER );
scroll.setVbarPolicy( ScrollBarPolicy.ALWAYS );
// シーンの作成
Scene scene = new Scene( scroll , WIDTH , HEIGHT );
// ウィンドウ表示
primaryStage.setScene( scene );
primaryStage.show();
// RSSの取込・表示を遅延実行タスクを定義
Task<Boolean> task = new Task<Boolean>()
{
@Override
public Boolean call() throws Exception
{
// RSSのURLを指定
String uri = "http://drawr.net/feed.php?md=h";
SyndFeed feed = null;
// RSSフィードを読み込み(キャッシュ機能付き)。
// try-with-resources構文での記述
try ( CloseableHttpClient client = HttpClients.createMinimal() )
{
// HTTPリクエストの作成
HttpUriRequest method = new HttpGet(uri);
// HTTPリクエストを発行
try ( CloseableHttpResponse response = client.execute(method);
InputStream stream = response.getEntity().getContent() )
{
// フィードを読込
SyndFeedInput input = new SyndFeedInput();
feed = input.build(new XmlReader(stream));
}
}
// 画面表示
for( Object entry : feed.getEntries() )
{
// エントリーの取得
SyndEntryImpl e = (SyndEntryImpl) entry;
// エントリーを順次表示
Node node = createDrawrEntry( e );
Platform.runLater( () -> root.getChildren().add( node ) );
}
return null;
}
};
// RSS取込・表示の遅延実行開始
Thread t = new Thread( task );
t.setDaemon( true );
t.start();
}
/**
* DrawrのRSSフィードから表示用のノードを作成する
* @param e
* @return
*/
protected Node createDrawrEntry( SyndEntryImpl e )
{
// エントリーの取得
String author = e.getAuthor();
String title = e.getTitle();
String link = e.getLink();
String value = e.getDescription().getValue();
// 画像URL解析
String imgUrl = value.substring( value.indexOf( "http" ) , value.lastIndexOf("\"") );
// 画目出力
Image img = new Image( imgUrl );
ImageView view = new ImageView( img );
Hyperlink hyperLink = new Hyperlink();
hyperLink.setText( title + "(" + author + ")" );
hyperLink.setGraphic( view );
hyperLink.setOnAction( arg ->
{
try {
// デフォルト・ブラウザを起動
Desktop desktop = Desktop.getDesktop();
desktop.browse( new URI( link ) );
} catch (Exception e1) {
e1.printStackTrace();
}
});
// 表示ノードを返す
return hyperLink;
}
}
◇実行結果
◇解析
RSSの読み込みには時間がかかるため、別スレッドとして実行するようにプログラムを組んでいる(63行目~107行目)。RSS読み込みロジック自体はTask::call関数(68行目~98行目)で行っている。
Task::call関数内の処理は、キャッシュ機能つきのHTTP通信(74行目~81行目)で対象のRSSファイルをInputStreamとして読み込んだ後、RSSの解析を行いエントリーを変数feedに代入(83行目~84行目)、それらを画面に表示している(90行目~98行目)。エントリーを画面に出力するための処理はcreateDrawEntry関数(96行目、116行目~146行目)で行っている。
■ サンプル・プログラム(RSS作成)
以下にROME1.7を利用してRSSを作成するサンプルプログラムを示す。サンプルでは10つの記事を含むRSSファイルを『rss.xml』という名前で保存している。
◇サンプル・コード
package application;
import java.io.File;
import java.sql.Date;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.SyndFeedOutput;
public class TestRomeCreate
{
// 定数
protected static final int WIDTH = 300;
protected static final int HEIGHT = 500;
protected static final String[] RSS_TYPE = { "rss_1.0" ,
"rss_2.0" ,
"rss_0.9" ,
"rss_0.92" ,
"atom_1.0" ,
"atom_0.3" };
public static void main(String[] args) throws Exception
{
// 変数
final String filename = "rss.xml"; // 出力先RSS
// フィードの全体情報を設定
SyndFeed feed = new SyndFeedImpl();
feed.setTitle( "RSSのタイトルです" );
feed.setLink( "http://krr.blog.shinobi.jp/" );
feed.setDescription( "RSSの内容を表す紹介文です" );
feed.setFeedType( RSS_TYPE[1] );
// フィードの記事を作成
List<SyndEntry> entries = new ArrayList<SyndEntry>();
for( int i=0 ; i<10 ; i++ )
{
// 1つ分の記事を作成
SyndEntry entry = new SyndEntryImpl();
SyndContent desc = new SyndContentImpl();
entry.setDescription( desc );
entry.setTitle( String.format( "%d番目の記事のタイトル" , i ) );
entry.setLink( "http://krr.blog.shinobi.jp/" );
entry.setPublishedDate( Date.valueOf( LocalDate.now() ) );
desc.setType( "text/plain" );
desc.setValue( String.format( "%d番目の記事の内容" , i ) );
// 一覧に記事を追加
entries.add( entry );
}
// 記事一覧をフィードに追加
feed.setEntries( entries );
// RSSフィードライタを作成し、ファイル出力
SyndFeedOutput o = new SyndFeedOutput();
o.output(feed, new File( filename ) );
}
}
◇実行結果
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
<title>RSSのタイトルです</title>
<link>http://krr.blog.shinobi.jp/</link>
<description>RSSの内容を表す紹介文です</description>
<item>
<title>0番目の記事のタイトル</title>
<link>http://krr.blog.shinobi.jp/</link>
<description>0番目の記事の内容</description>
<pubDate>Sat, 09 Apr 2016 15:00:00 GMT</pubDate>
<guid>http://krr.blog.shinobi.jp/</guid>
<dc:date>2016-04-09T15:00:00Z</dc:date>
</item>
<item>
<title>1番目の記事のタイトル</title>
…中略
</item>
</channel>
</rss>
◇解説
RSSの作成はSyndFeedOutput::output関数で行っている(66行目~67行目)。フィードデータと内部の記事データは、それぞれSyndFeedクラス・SyndEntryクラスで表される。
■ 参照
- Apache Commons 「Jakarta FeedParser」
- Github issues 「[fetcher] Deprecation and removal of ROME Fetcher #276」
- ROME 「Rss and atOM utilitiEs (ROME) v0.5 and above Tutorials and Articles」
- 技術への名残り「JavaでRSSを作成(ROME利用)」