Skip to content
RSSフィードから記事を取得しHTMLで表示させる記事のサムネイル

RSSフィードから記事を取得しHTMLで表示させる

最近、当サイトにRSSフィードを追加しました。 せっかくなので、このRSSフィードを使用したいなと思い、今回この記事を作成しました。 データの取得からXMLの解析、HTMLでの表示までを行ないたいと思います。 また今回は環境構築などには触れませんのでご自身で用意してください。

RSSで記事の内容を取得する

URLを指定してフェッチし、コンソールに出力してみます。 記事の情報がコンソールに出力されていれば取得できています。

ts
const rssUrl = 'https://blog.saga-web-engineer.com/rss.xml';

document.addEventListener('DOMContentLoaded', () => {
  fetch(rssUrl)
    .then((response) => response.text())
    .then((xmlString) => console.log(xmlString))
    .catch((error) => console.error('Error:', error));
});

INFO

ご自身で決めた場所から記事を取得する際はCORSエラーにご注意ください。

XMLを解析する

取得した記事の情報をDOMParserを使用して解析します。 解析後のものをforEachで繰り返してコンソールに出力してみます。 実際にコンソールに出力されていればOKです。

ts
const rssUrl = 'https://blog.saga-web-engineer.com/rss.xml';

const makeRssContents = (xmlString: string) => { 
  // DOMParserを使用してXMLを解析
  const parser = new DOMParser(); 
  const xmlDoc = parser.parseFromString(xmlString, 'application/xml'); 

  // 各item要素を取得
  const items = xmlDoc.querySelectorAll('item'); 
  items.forEach((item) => console.log(item)); 
}; 

document.addEventListener('DOMContentLoaded', () => {
  fetch(rssUrl)
    .then((response) => response.text())
    .then((xmlString) => makeRssContents(xmlString)) 
    .catch((error) => console.error('Error:', error));
});

INFO

当サイトのRSSフィードはitemで取得できますが、形式によってはitemではない場合がありますので、適宜変更してください。

記事を表示させてみる

まず取得したデータを変数に格納します。

ts
interface ContentsData { 
  title: string; 
  link: string; 
  description: string; 
  thumbnail: string; 
  date: string; 
} 

const rssUrl = 'https://blog.saga-web-engineer.com/rss.xml';

const makeRssContents = (xmlString: string) => {
  // DOMParserを使用してXMLを解析
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xmlString, 'application/xml');

  // 各item要素を取得
  const items = xmlDoc.querySelectorAll('item');
  items.forEach((item) => { 
    const data: ContentsData = { 
      title: item.querySelector('title')?.textContent || '', 
      link: item.querySelector('link')?.textContent || '', 
      description: item.querySelector('description')?.textContent || '', 
      thumbnail: item.querySelector('enclosure')?.getAttribute('url') || '', 
      date: item.querySelector('pubDate')?.textContent || '', 
    }; 
  }); 
}

// ...

INFO

画像の取得は各サイトのRSSフィードによって違う可能性があります。 media:contentとなっているRSSフィードでは、querySelector('content')で取得できました。

itemから取得した値を引数に渡し、記事表示のひな型になるテンプレートを作成します。 ここは自分が良きように適宜変更してください。

ts
// ...

const rssUrl = 'https://blog.saga-web-engineer.com/rss.xml';

const htmlTemplate = (data: ContentsData): string => {
  return `
    <article>
      <a href="${data.link}" target="_blank" rel="noreferrer">
        <img src="${data.thumbnail}" alt="" width="1200" height="630">
        <h3>${data.title}</h3>
        <time>${data.date}</time>
        <p>${data.description}</p>
      </a>
    </article>
  `;
};

// ...

INFO

当サイトのRSSフィードは画像サイズがありませんので、widthとheightに直接値を指定しています。 media:contentの場合は画像サイズが含まれていますので、そこから取得すると良いでしょう。

今回は記事をid="rss-target"に挿入しますので作成したmakeRssContents関数にidとして引数を渡してあげるように変更しましょう。

ts
// ...

const makeRssContents = (xmlString: string, id: string) => { 
  const targetElement = document.querySelector<HTMLDivElement>(`#${id}`); 

  // DOMParserを使用してXMLを解析
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xmlString, 'application/xml');

  // 各item要素を取得
  const items = xmlDoc.querySelectorAll('item');
  items.forEach((item) => {
    const data: ContentsData = {
      title: item.querySelector('title')?.textContent || '',
      link: item.querySelector('link')?.textContent || '',
      description: item.querySelector('description')?.textContent || '',
      thumbnail: item.querySelector('enclosure')?.getAttribute('url') || '',
      date: item.querySelector('pubDate')?.textContent || '',
    };
  });
};

document.addEventListener('DOMContentLoaded', () => {
  fetch(rssUrl)
    .then((response) => response.text())
    .then((xmlString) => makeRssContents(xmlString, 'rss-target')) 
    .catch((error) => console.error('Error:', error));
});

変数articleを定義してhtmlTemplateを呼び出します。 targetElementにtemplateを追加していきます。

ts
// ...

const makeRssContents = (xmlString: string, id: string) => {
  const targetElement = document.querySelector<HTMLDivElement>(`#${id}`);

  // DOMParserを使用してXMLを解析
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xmlString, 'application/xml');

  // 各item要素を取得
  const items = xmlDoc.querySelectorAll('item');
  items.forEach((item) => {
    const data: ContentsData = {
      title: item.querySelector('title')?.textContent || '',
      link: item.querySelector('link')?.textContent || '',
      description: item.querySelector('description')?.textContent || '',
      thumbnail: item.querySelector('enclosure')?.getAttribute('url') || '',
      date: item.querySelector('pubDate')?.textContent || '',
    };

    const article = htmlTemplate(data); 

    // 指定されたIDの要素にテンプレートを追加
    if (targetElement) targetElement.innerHTML += article; 
  });
};

// ...

表示するHTML側には、id="rss-target"の要素を置いておくのを忘れないようにしましょう

html
<!-- body以外は省略 -->
<body>
  <div id="rss-target"></div>
</body>

以上で記事が表示されたかと思います。

日付をフォーマットする

ここまでで記事を表示することはできたかと思います。 私の好みになるのですが日付を〇〇年〇〇月〇〇日と表示させたいので最後に日付のフォーマットをして終わりにしましょう。

ts
// ...

const makeRssContents = (xmlString: string, id: string) => {
  const targetElement = document.querySelector<HTMLDivElement>(`#${id}`);

  // DOMParserを使用してXMLを解析
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xmlString, 'application/xml');

  // 各item要素を取得
  const items = xmlDoc.querySelectorAll('item');
  items.forEach((item) => {
    const pubDate = new Date(item.querySelector('pubDate')?.textContent || ''); 

    const formatDate = (date: Date): string => { 
      const year = date.getFullYear(); 
      const month = date.getMonth() + 1; 
      const day = date.getDate(); 
      const result = `${year}年${month}月${day}日`; 
      return result; 
    }; 

    const data: ContentsData = {
      title: item.querySelector('title')?.textContent || '',
      link: item.querySelector('link')?.textContent || '',
      description: item.querySelector('description')?.textContent || '',
      thumbnail: item.querySelector('enclosure')?.getAttribute('url') || '',
      date: formatDate(pubDate), 
    };

    const article = htmlTemplate(data);

    // 指定されたIDの要素にテンプレートを追加
    if (targetElement) targetElement.innerHTML += article;
  });
};

// ...

最終的なコード

以下が最終的なコードになります。

ts
interface ContentsData {
  title: string;
  link: string;
  description: string;
  thumbnail: string;
  date: string;
}

const rssUrl = 'https://blog.saga-web-engineer.com/rss.xml';

const htmlTemplate = (data: ContentsData): string => {
  return `
    <article>
      <a href="${data.link}" target="_blank" rel="noreferrer">
        <img src="${data.thumbnail}" alt="" width="1200" height="630">
        <h3>${data.title}</h3>
        <time>${data.date}</time>
        <p>${data.description}</p>
      </a>
    </article>
  `;
};

const makeRssContents = (xmlString: string, id: string) => {
  const targetElement = document.querySelector<HTMLDivElement>(`#${id}`);

  // DOMParserを使用してXMLを解析
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xmlString, 'application/xml');

  // 各item要素を取得
  const items = xmlDoc.querySelectorAll('item');
  items.forEach((item) => {
    const pubDate = new Date(item.querySelector('pubDate')?.textContent || '');

    const formatDate = (date: Date): string => {
      const year = date.getFullYear();
      const month = date.getMonth() + 1;
      const day = date.getDate();
      const result = `${year}年${month}月${day}日`;
      return result;
    };

    const data: ContentsData = {
      title: item.querySelector('title')?.textContent || '',
      link: item.querySelector('link')?.textContent || '',
      description: item.querySelector('description')?.textContent || '',
      thumbnail: item.querySelector('enclosure')?.getAttribute('url') || '',
      date: formatDate(pubDate),
    };

    const article = htmlTemplate(data);

    // 指定されたIDの要素にテンプレートを追加
    if (targetElement) targetElement.innerHTML += article;
  });
};

document.addEventListener('DOMContentLoaded', () => {
  fetch(rssUrl)
    .then((response) => response.text())
    .then((xmlString) => makeRssContents(xmlString, 'rss-target'))
    .catch((error) => console.error('Error:', error));
});

いかがだったでしょうか。RSSフィードを活用することで、他サイトの記事を自動的に取得・表示できるようになりました。 応用すれば、複数のブログを統合したポータルサイトやニュースアグリゲーターなども作成できます。ぜひ様々な場面で活用してみてください。