201201/25 Memo
RSSなどのxmlファイルを静的なHTMLに表示させる方法あれこれ(2014.11.05追記)
あけましておめでとうございました。本年もよろしくお願いいたします。
さて去年後半、xmlを読み込んでは切ったり貼ったりする仕事が相次いでました。
大変勉強になったので、サンプルや注意点、参考URLなどをまとめておきます。
本当にメモ書きのようなものなので、JS部分のみ抜粋してます。詳しい書き方はサンプルのソース見てくださると助かります。
外部サーバのXMLファイルを読み込む
「ア○ーバブログの更新情報をサイトに載せたい!」なんて時に使えます。
Google AJAX Feed API を使う
シンプルにデータ取得→HTMLに表示はこんな感じでできます。
<script src="https://www.google.com/jsapi" type="text/javascript"></script> <script type="text/javascript"> var xmlUrl = "http://arcaxxx.blog21.fc2.com/?xml"; //feedのURL var setNum = 5; //表示件数 var setID = "feed"; //表示させる箇所のID google.load("feeds", "1"); function initialize() { var html = ''; var feed = new google.feeds.Feed(xmlUrl); feed.setNumEntries(setNum); feed.load(function(result) { if (!result.error){ var container = document.getElementById(setID); for (var i = 0; i < result.feed.entries.length; i++) { var entry = result.feed.entries[i]; var title = entry.title; //記事タイトル取得 var link = entry.link; //記事のリンクを取得 //日付を取得し年月日を整形 var publishedDate = entry.publishedDate; var pubDD = new Date(publishedDate); yy = pubDD.getYear();if (yy < 2000) { yy += 1900; } mm = pubDD.getMonth() + 1;dd = pubDD.getDate(); var pubDate = yy +'年'+ mm +'月'+ dd +'日'; //カテゴリ要素がある場合は取得 for (var j = 0; j < entry.categories.length; j++) { var categorie = entry.categories[j]; } //表示する部分を整形 html += '<li><a href="' + link + '">' + title +'</a> - ' + categorie + '(' + pubDate + ')</li>'; } container.innerHTML = html; } }); } google.setOnLoadCallback(initialize); </script>
ちょっと凝ったのはこんな感じ
<script type="text/JavaScript" src="js/jquery.js"></script> <script src="https://www.google.com/jsapi" type="text/javascript"></script> <script type="text/javascript"> var xmlUrl = "http://mei331.tumblr.com/rss"; //feedのURL var setNum = 3; //表示件数 var setID = "feed"; //表示させる箇所のID google.load("feeds", "1"); function initialize() { DD = new Date();HH = DD.getHours();MM = DD.getMinutes();SS = DD.getSeconds(); xmlUrl = xmlUrl+"?"+HH+MM+SS; //キャッシュ対策のクエリを付与 var feed = new google.feeds.Feed(xmlUrl); feed.setNumEntries(setNum); feed.setResultFormat(google.feeds.Feed.XML_FORMAT); feed.load(function(result) { if (!result.error){ var container = document.getElementById(setID); var xmlDoc = result.xmlDocument; var items = xmlDoc.getElementsByTagName("item"); var html = ''; $(xmlDoc).find('item').each(function(){ title = $(this).find('title').text(); //タイトル取得 description = $(this).find('description')[0].firstChild.nodeValue; //コンテンツ取得 link = $(this).find('link').text(); //link取得 guid = $(this).find('guid').text(); //guid取得 //日付を取得し年月日を整形 publishedDate = $(this).find("pubDate").text(); var pubDD = new Date(publishedDate); yy = pubDD.getYear();if (yy < 2000) { yy += 1900; } mm = pubDD.getMonth() + 1;dd = pubDD.getDate(); var pubDate = yy +'年'+ mm +'月'+ dd +'日'; //表示する部分を整形 html += '<li><h3><a href="' + link + '">' + title + '</a></h3>'; html += '<div class="contents">' + description + '</div>'; html += '<p>'+ guid + '(' + pubDate + ')</p></li>'; }); container.innerHTML = html; } }); } google.setOnLoadCallback(initialize); </script>
補足)
Tumblrのコンテンツ(descriptionタグの中身)は、firstChild.nodeValue で取得できます。
ただ、タグ内にある情報を全て表示してしまうので、CSS等での調整が必要だと思います。
/** 2012.9.4追記ここから **/
サンプル2がIE8以下で動いていないという指摘を受けまして、色々調べてみました。
上記コードの20〜37行目を以下のように修正するとIE8以下でも問題なく動作するようです。
for (var i = 0; i < items.length; i++) { var title = items[i].getElementsByTagName("title")[0].firstChild.nodeValue; var link = items[i].getElementsByTagName("link")[0].firstChild.nodeValue; var guid = items[i].getElementsByTagName("guid")[0].firstChild.nodeValue; var description = items[i].getElementsByTagName("description")[0].firstChild.nodeValue; //日付を取得し年月日を整形 publishedDate = items[i].getElementsByTagName("pubDate")[0].firstChild.nodeValue; var pubDD = new Date(publishedDate); yy = pubDD.getYear();if (yy < 2000) { yy += 1900; } mm = pubDD.getMonth() + 1;dd = pubDD.getDate(); var pubDate = yy +'年'+ mm +'月'+ dd +'日'; //表示する部分を整形 html += '<li><h3><a href="' + link + '">' + title + '</a></h3>'; html += '<div class="contents">' + description + '</div>'; html += '<p>'+ guid + '(' + pubDate + ')</p></li>'; }
IE8以下はどうやら<![CDATA[~]]>で囲まれていないHTMLタグの書かれた要素の中身を取得する場合、$(xmlDoc).find(‘item’).eachを使って参照しようとすると上手く参照出来ないようです。
古い記事ですがこちらにあるように、thisを使った参照の仕方だと上手くいかないみたいです。
最初のサンプルではdescription以外はきちんと取得出来ていたので、RSS側のdescriptionが<![CDATA[~]]>で囲まれていないとノードの取得が上手くできない、もしくはタグとして認識してしまうのかもしれないな、と。憶測ですが。
/** 2012.9.4追記ここまで **/
自分で書くのが面倒!よくわからない!場合はプラグインで。
これ系のプラグインは色々有りますが、色々試した中では「zRssfeed」がカスタマイズしやすくて便利でした。
プラグインならzRssfeedがオススメ!
参考)jQueryでサイト内に簡単にRSSフィードを組み込めるプラグイン「zRSSFeed」
PHPを使う
google Feed APIを使わないで、外部サーバのXMLファイルを読みに行く為のPHPを設置する方法もあります。
feed2jsというのがあるんですが、これがサクッとできて一番お手軽ですね。
php側で表示数や日付などを設定できます。表示するHTMLには吐き出されたscriptタグを書くだけ。
ただCSSの設定がちょっと面倒なうえ、php側の設定画面が英語なのでちょっと難しいです。
feed2js
同一サーバのXMLファイルを読み込む
jQueryを使う
jqueryには便利なajax関数があるので、そちらを使って読み込んだりします。
<script type="text/JavaScript" src="js/jquery.js"></script> <script type="text/javascript"> $(function() { var setURL = '../feed'; //feedのURL var setNUM = 5; //表示件数 var setID = 'feed'; //表示させる箇所のID xmlLoad(setURL,setID,setNUM); }); function xmlLoad(_xmlUrl,_id,_num){ DD = new Date();HH = DD.getHours();MM = DD.getMinutes();SS = DD.getSeconds(); var xmlUrl = _xmlUrl+"?"+HH+MM+SS; //キャッシュ対策のクエリを付与 var main = this; $.ajax({ url: xmlUrl, type: 'GET', dataType: 'xml', timeout: 10000, error: function(){ _msg = 'error'; xmlOpen(_msg,_id,_num); }, success: function(_xml){ main.xml = _xml; _msg = 'load'; xmlOpen(_msg,_id,_num); } }); return; } var xmlOpen = function(_msg,_id,_num){ var main = this; var html = ''; var ID = _id; var Num = _num; if(_msg == 'load'){ xml = main.xml; var channelData = $(xml).find('channel')[0]; $(channelData).find('item').each(function(i){ if(i < Num){ postTitle = $(this).find('title').text();//記事タイトル取得 postLink = $(this).find('link').text();//記事リンク取得 //日付を取得し年月日を整形 publishedDate = $(this).find('pubDate').text(); var pubDD = new Date(publishedDate); yy = pubDD.getYear();if (yy < 2000) { yy += 1900; } mm = pubDD.getMonth() + 1;dd = pubDD.getDate(); var postDate = yy +'年'+ mm +'月'+ dd +'日'; //カテゴリが1記事に複数あるのである分だけ取得 var postCategory = ''; $(this).find('category').each(function(i){ category = $(this).text(); if(i <= 0){ postCategory += category; }else{ postCategory += ',' + category; } }); //表示する部分を整形 html += '<li><a href="' + postLink + '">' + postTitle +'</a> - ' + postCategory + '(' + postDate + ')</li>'; } }); }else{ html += '<li>通信エラー</li>'; } $("#"+ID).html(html); } </script>
ちょっと複雑なxmlを読み込む場合はこんな感じ
<script type="text/JavaScript" src="js/jquery.js"></script> <script type="text/javascript"> $(function() { var setURL = '../feed'; //feedのURL var setNUM = 5; //表示件数 var setID = 'feed'; //表示させる箇所のID xmlLoad(setURL,setID,setNUM); }); function xmlLoad(_xmlUrl,_id,_num){ DD = new Date();HH = DD.getHours();MM = DD.getMinutes();SS = DD.getSeconds(); var xmlUrl = _xmlUrl+"?"+HH+MM+SS; //キャッシュ対策のクエリを付与 var main = this; $.ajax({ url: xmlUrl, type: 'GET', dataType: 'xml', timeout: 10000, error: function(){ _msg = 'error'; xmlOpen(_msg,_id,_num); }, success: function(_xml){ main.xml = _xml; _msg = 'load'; xmlOpen(_msg,_id,_num); } }); return; } var xmlOpen = function(_msg,_id,_num){ var main = this; var html = ''; var ID = _id; var Num = _num; var userAgent = window.navigator.userAgent.toLowerCase(); if(_msg == 'load'){ xml = main.xml; var channelData = $(xml).find('channel')[0]; $(channelData).find('item').each(function(i){ if(i < Num){ postTitle = $(this).find('title').text();//記事タイトル取得 postLink = $(this).find('link').text();//記事リンク取得 //日付を取得し年月日を整形 publishedDate = $(this).find('pubDate').text(); var pubDD = new Date(publishedDate); yy = pubDD.getYear();if (yy < 2000) { yy += 1900; } mm = pubDD.getMonth() + 1;dd = pubDD.getDate(); var postDate = yy +'年'+ mm +'月'+ dd +'日'; postDescription = $(this).find('description').text(); //記事冒頭部分取得 if ((userAgent.indexOf('msie') != -1) || (userAgent.indexOf('firefox') != -1)) { postMaster = $(this).find('dc\\:creator').text(); //投稿者名取得 commentNum = $(this).find('slash\\:comments').text(); //コメント数取得 }else{ postMaster = $('creator:first', this).text(); //投稿者名取得 commentNum = $('comments', this)[1].textContent; //コメント数取得 } //カテゴリが1記事に複数あるのである分だけ取得 var postCategory = ''; $(this).find('category').each(function(i){ category = $(this).text(); if(i <= 0){ postCategory += category; }else{ postCategory += ',' + category; } }); //表示する部分を整形 html += '<li><a href="' + postLink + '">' + postTitle +'</a> - ' + postMaster + '<br>' + postDescription; html += '<span>' + postCategory + '/コメント数:'+ commentNum +' (' + postDate + ')</span></li>'; } }); }else{ //エラー時の表示 html += '<li>通信エラー</li>'; } $("#"+ID).html(html); } </script>
補足)
xml内にある<dc:creator>などの要素は、$(xml).find(‘dc\\:creator’) という感じで「:」の前に「\\」を追加することで取得出来ます。
xml内にある<dc:creator>などの要素の取得については、2014.11.05追記をご確認ください。
また、今回のサンプルには無いですが、<tags status="date"></tags> というタグがあった場合。
tagsのstatusの値を取得すしたい時は、$(xml).find(‘tags’).attr(‘status’) という指定で取得出来ます。
jQueryを使わない
使わないでやる方法を色々と試してみたんですが、ブラウザによって読み込みの仕様が違うため、難しくて断念しましたorz
jQueryさまさまですね…。
どうしても!となると同一サーバのファイルだけど、Google AJAX Feed APIを使って取得する、という方法になるのでしょうか。
その他xmlをjsで扱う場合に注意することなど
- ローカルでxmlを参照する場合、表示するhtmlより下位の階層にあること
セキュリティ的な問題で、ローカルで参照する場合は下階層に無ければ参照できません。 - Google Chromeはローカルでxmlを参照することができない
できるようにする方法ももちろんありますが、セキュリティの問題もありますので、自己責任でお願いします。
参考)Google Chrome でAjaxを利用しローカルファイルにアクセスする[to-R] - xmlのキャッシュに注意
「xmlを更新しても更新されない!」場合はキャッシュを読んでしまってる可能性があります。
xmlファイルの末尾にタイムスタンプのクエリなどを追加しておくと回避できます。
(サンプル1以外にはキャッシュ対策のクエリを追加してますので参考までに) - xmlファイルのエラーに注意
「jsでおかしい部分はないのに、うまく読み込めない!」場合はxmlファイル自体がパースエラーを起こしている場合もあります。また、xmlファイルは「&」をそのまま書いているとエラーになります。「&」にしておきましょう。
パースエラーかどうかはxmlファイルをfirefoxなどのブラウザで読み込むことで確認できます。 - xmlに記載したタグを表示したい
xmlの表示したい部分を<![CDATA[~]]>で囲むと幸せになれます。 - 文字化けする時はJSや読み込むXML、表示するHTMLの文字コードをチェック
結構それが原因だったりします。特にIEさんとかIEさんとか… - Google Feed API Key は必要?/* 2014.1.20 追記 */
色んなサイトで呪文のように「まずはGoogle Feed API Keyを取得します」とあるんですが、どうやら不要のようです?(ちょっと曖昧)サンプルではソースを見ていただければ分かる通り使ってはいませんが、動いてはいます。不要になったようです。
JSONの取得のみならAPI Keyは要らない、という記述はみつけましたが。
参考)Google AJAX Feed APIのJSONをjQueryで取得する [Feed to JSON] : ずっと工事中
ある日突然必要になる可能性もなきにしもあらず。公式のリンクがあちこちNot Foundで上手く探せないですね。
こちらは引き続き探しておきたいと思います。
Sign-up for an API Key – Google Loader — Google Developers
↑にあるように、「The Google Loader no longer requires keys.」必要としないようです。
/* 2014.1.20 追記ここまで */
こんなもんでしょうか。
去年このブログを開設したけど、そんなに書かなくなってしまい。原因を考えて、webだけにくくってるからかなーと
思い至ったので、それ以外のことも書いていきたいなーと思います。はい。
とかいいつつ、webの記事で始まりましたが、気にしないでください。
今年はもうちょっとブログ更新できるようにするぞー@・ェ・@
参考記事一覧)
・Google AJAX Feed API入門
・Google Feed APIで用意されている要素以外の要素にアクセスする方法 – KUMA TYPE
・Google AJAX Feed APIのJSONをjQueryで取得する [Feed to JSON] : ずっと工事中
・小粋空間: RSS Feed(フィード)を表示する
・jQueryでサイト内に簡単にRSSフィードを組み込めるプラグイン「zRSSFeed」
・Using jQuery on WSH – 葉っぱ日記
・Google Chrome でAjaxを利用しローカルファイルにアクセスする[to-R]
/* 2014.7.24追記 */
複数のURLを指定する場合についてよくご質問をいただくので、記事にしました。
・複数のRSSなどのxmlファイルを静的なHTMLに表示させる方法
どうぞご参考までに。
/* 2014.11.05追記 */
<dc:creator>などの要素を、$(xml).find(‘dc\\:creator’)で取得できていたのですが、Chromeで取得できなくなっていたので対策についての追記です。
ChromeまたはSafariの場合、
<dc:creator>は、$('creator:first', this).text();
で取得できます。
参考)javascript – Get first element from tag name in jQuery – Stack Overflow(英語)
<slash:comments>は、$('comments', this)[1].textContent;
で取得できました。
xml内の「comments」という文字列を含むタグから探して参照しているので、xmlの内容によっては[1]
の部分は数字が変わります。
IEやfirefoxの場合はこれまでと同じ$(xml).find('dc\\:creator')
で取得できます。
ブラウザで取得方法をかえるので、ブラウザ判定を追加してこんな感じでできます。
var userAgent = window.navigator.userAgent.toLowerCase(); if ((userAgent.indexOf('msie') != -1) || (userAgent.indexOf('firefox') != -1)) { postMaster = $(this).find('dc\\:creator').text(); //投稿者名取得 commentNum = $(this).find('slash\\:comments').text(); //コメント数取得 }else{ postMaster = $('creator:first', this).text(); //投稿者名取得 commentNum = $('comments', this)[1].textContent; //コメント数取得 }
そういえば、SuefaceRTのIEはMSIE
で判別されませんでした。ユーザーエージェント違うみたいですね?
いつも参考にさせていただいています。
ちょっと質問なのですが、サンプル2がIE8以下で動かないのはなぜでしょうか。
確認していただけると助かります。
お返事だいぶ遅くなってすみません。
対策を追記しましたので、ご確認ください。
仕事でウェブサイト作るのに大変参考になりました。ありがとうございます。見ると他にもいろいろ役に立つ記事があるのでブックマークします。育児頑張ってください。
ありがとうございます。
参考にしていただけたら幸いです。
頑張ります。
いつもお世話になっています。
Google AJAX Feed API を使った外部RSSを読み込む方法をいつも使用させていただいております。
今回、複数のRSSを別のDIVに表示させたいと考えております。
そこでスクリプトごとコピーし何度か書き換えを試みたのですが、どうしてもうまくいきません。
恐れ入りますが、方法がございましたらお教えいただきたく存じます。
お忙しい中お手数おかけいたしますが、
よろしくお願いいたします。
こんにちわ。返信が遅くなってスミマセン。
>複数のRSSを別のDIVに表示させたい
とのことですが、これは複数のRSSを一つにまとめて表示したい、ということでしょうか?
もしかしたら、もうすでに解決しているかもしれませんが、
以下の記事など参考になるかもしれません。
http://berry.org.cn/blog/rss/30/
ブログのRSSを抜き出し、別ページに更新情報として出すものを探してました。
いろいろあったのですが、どうもかゆいところに手がとどかに、、
しかし、ここへきて、これが最適だと思いました!
まだ、テストしているところですが、
ひとつ質問あります。
そこで、description ブログの本文の文字数を調整することは可能でしょうか?
よろしくお願いいたします
toshikiさま
初めまして。ご質問のブログの本文の文字数を調整したい、ということですが、
このスクリプトで出来ることは「RSSに記載されている物を、形を整えて表示する」ということだけなんですね。
なので、RSS側でdescriptionを全文配信していれば、全文を表示することができますし、文字数をsubstr()などで制限して表示することもできます。
ただ、RSS側で100文字までしか配信していない場合は、100文字までしか表示出来ません。
RSS側で調整するか、JavaScriptで制限するか、のどちらかになるかと思います。
その辺りはお好みになると思いますので、お好きな方法で設定してみてください。
初めまして。
質問させていただきます。
Google AJAX Feed API を使うのサンプル1の方法で、複数のURLを指定する場合は
どのように記述すればよろしいのですか?
返信が遅くなりました。すみません。
複数のURLを指定する場合はまた違う書き方をしなければいけません。
コメント欄では長くなってしまうので、記事にしました。
複数のRSSなどのxmlファイルを静的なHTMLに表示させる方法
こちらをご参考ください。
こんばんわ
勉強させてもらっています。ありがとうございます。
複数のURL(feed)を表示する時に、
例えば、feed1 と feed2 の ID を分けて、
1ページの中で表示したい場所を、分けしたいと思いますが、
あれこれ検索しても、見つからなかったので、
いつも勉強させてもらいっている Mei Koutsuki さんに聞いたほうが良いと思い。
書かせてもらいました。
よろしくお願いいたします。
toshikiさん
コメントありがとうございます。
以下の記事で複数のfeedをそれぞれ表示させる方法について書きましたので、ご参考ください。
複数のRSSなどのxmlファイルを静的なHTMLに表示させる方法
Mei Koutsukiさん
早速、ありがとうございます。
試しにさっそくしてみると、うまくできました。
そこで、下記の2点について、疑問点がでてきました。
いろいろ試したたり、ググってみては試しでもうまくいかなかったです。。
1)
ここにも書いてあるキャッシュの件です。
更新と表示のタイムラグですね。
複数のRSSなどのxmlファイルを静的なHTMLに表示させる方法のとき、
どうも挿入場所がわるいのか、うまくできません。
DD = new Date();HH = DD.getHours();MM = DD.getMinutes();SS = DD.getSeconds();
var xmlUrl = _xmlUrl+”?”+HH+MM+SS; //キャッシュ対策のクエリを付与
を挿入しています。
複数表示は違う設定なのでしょうか?
2)
表示を 5 に設定しているとき、
もとブログの記事が 3 しかない場合に、
「読み込み中」となるので、
ブログ開始時期だけのことですが、表示以下の投稿数でも、
表示させるときの設定をおしえていただければと思います。
すいません、あと2つ教えていただければと、、、
よろしくお願いいたします。
tosikiさん
すみません、帰省でPCのない生活をしていたので、返信が遅くなりました。
1)について
の部分を、
とすることで解決できます。
2)について
ここは24行目辺りの
の部分を
にすることで解決できると思います。
result.feed.entries.length
で取得できた記事の数を返します。こちらのサンプルで上記部分を修正しているので、参考にしてください。
いえいえ、とんでもないです。
今回も、ありがとうございます。
若干、修正して、みごとに完成しました。
ほとんど、素人で、見比べながら色々やって、
なんとかできました〜。
ちなみに、修正した所は、
1)は、
rssUrl = rssUrl+"?"
↓
rssUrl = _rssUrl+”?”
" → ” に変更しました。
2)は、
for (var i = 0; i < result.
↓
for (var i = 0; i < result.
< → < に変更しました。
ほんとうに、ありがとうございました。
勉強になります。
また、よろしくお願いします。
あらら?
さっき返信したメセージ見たら、、、
修正のはずが、、、
文字コードの関係だったのですね、
失礼しました。
こちらもちゃんと確認せずですみません。
勝手に変換されてしまうみたいですね。
ご指摘ありがとうございました。
お世話になります。
とてもすばらしいコードを公開くださりありがとうございます!
大変ありがたく使わせていただいております。
ところでauthorを取得するにはどうしたらいいのでしょうか・・?
feedではdc:creatorと表示があるところなのですが、取得できずにおります。
お忙しい中恐れ入りますが、方法がありましたら教えていただけると大変助かります。
よろしくお願いいたします。
ようこさん
コメントありがとうございます。
dc:creatorの取得方法が少し変わったようだったので、追記させていただきました。
ご確認ください。