diff --git a/app/static/js/RessourceLists/RessourceList.js b/app/static/js/RessourceLists/RessourceList.js
index 871a1e2f89cb6286d860ce559da81fbba43453a5..323f9d0e7b455e83fb04a43da03d919fecda6462 100644
--- a/app/static/js/RessourceLists/RessourceList.js
+++ b/app/static/js/RessourceLists/RessourceList.js
@@ -30,11 +30,11 @@ class RessourceList {
       ...{pagination: {item: `<li><a class="page" href="#${listElement.id}"></a></li>`}},
       ...options
     }
-    if ('ressourceMapper' in options) {
+    if ('ressourceMapper' in options && typeof options.ressourceMapper === 'function') {
       this.ressourceMapper = options.ressourceMapper;
       delete options.ressourceMapper;
     }
-    if ('initialHtmlGenerator' in options) {
+    if ('initialHtmlGenerator' in options && typeof options.initialHtmlGenerator === 'function') {
       this.initialHtmlGenerator = options.initialHtmlGenerator;
       listElement.innerHTML = this.initialHtmlGenerator(listElement.id);
       delete options.initialHtmlGenerator;
diff --git a/app/static/js/XMLtoObject.js b/app/static/js/XMLtoObject.js
new file mode 100644
index 0000000000000000000000000000000000000000..001376cb7139308833fedf4665c509873fcea357
--- /dev/null
+++ b/app/static/js/XMLtoObject.js
@@ -0,0 +1,102 @@
+/**
+ * XMLtoObject - Converts XML into a JavaScript value or object.
+ * GitHub: https://github.com/Pevtrick/XMLtoObject
+ * by Patrick Jentsch: https://github.com/Pevtrick
+ */
+
+/**
+ * The XMLDocument.toObject() method converts the XMLDocument into a JavaScript value or object.
+ * @param {String} [attributePrefix=] - A Prefix, which is added to all properties generated by XML attributes.
+ * @returns {Object} - The converted result.
+ */
+ XMLDocument.prototype.toObject = function(attributePrefix='') {
+  let obj = {};
+
+  obj[this.documentElement.nodeName] = this.documentElement.toObject(attributePrefix);
+
+  return obj;
+};
+
+/**
+* The Node.toObject() method converts the Node into a JavaScript value or object.
+* @param {String} [attributePrefix=] - A Prefix, which is added to all properties generated by XML attributes.
+* @returns {Object|String|null} - The converted result.
+*/
+Node.prototype.toObject = function(attributePrefix='') {
+  let obj = null;
+
+  switch (this.nodeType) {
+      case Node.ELEMENT_NODE:
+          let hasAttributes = this.attributes.length > 0;
+          let hasChildNodes = this.childNodes.length > 0;
+
+          /* Stop conversion if the Node doesn't contain any attributes or child nodes */
+          if (!(hasAttributes || hasChildNodes)) {
+              break;
+          }
+
+          obj = {};
+
+          /* Convert attributes */
+          for (let attribute of this.attributes) {
+              obj[`attributePrefix${attribute.name}`] = attribute.value;
+          }
+
+          /* Convert child nodes */
+          for (let childNode of this.childNodes) {
+              switch (childNode.nodeType) {
+                  case Node.ELEMENT_NODE:
+                      break;
+                  case Node.TEXT_NODE:
+                      /* Check whether the child text node is the only child of the current node. */
+                      if (!hasAttributes && this.childNodes.length === 1) {
+                          obj = childNode.toObject(attributePrefix);
+                          continue;
+                      }
+                      if (childNode.data.trim() === '') {continue;}
+                      break;
+                  default:
+                      /* This recursion leads to a console message. */
+                      childNode.toObject(attributePrefix);
+                      continue;
+              }
+              /**
+               * If the child node is the first of its type in this childset,
+               * process it and add it directly as a property to the return object.
+               * If not add it to an array which is set as a property of the return object.
+               */
+              if (childNode.nodeName in obj) {
+                  if (!Array.isArray(obj[childNode.nodeName])) {
+                      obj[childNode.nodeName] = [obj[childNode.nodeName]];
+                  }
+                  obj[childNode.nodeName].push(childNode.toObject(attributePrefix));
+              } else {
+                  obj[childNode.nodeName] = childNode.toObject(attributePrefix);
+              }
+          }
+          break;
+      case Node.TEXT_NODE:
+          if (this.data.trim() !== '') {obj = this.data;}
+          break;
+      case Node.COMMENT_NODE:
+          console.log('Skipping comment node:');
+          console.log(node);
+          break;
+      case Node.DOCUMENT_NODE:
+          obj = {};
+          obj[this.documentElement.nodeName] = this.documentElement.toObject(attributePrefix);
+          break;
+      default:
+          /**
+           * The following node types are not processed because they don't offer data, which has to be stored in the object:
+           * Node.PROCESSING_INSTRUCTION_NODE, Node.DOCUMENT_TYPE_NODE, Node.DOCUMENT_FRAGMENT_NODE
+           * The following node types are deprecated and therefore not supported by this function:
+           * Node.ATTRIBUTE_NODE, Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE, Node.ENTITY_NODE, Node.NOTATION_NODE
+           */
+          console.log(`Node type: '${this.nodeType}' is not supported.`);
+          console.log(node);
+          break;
+  }
+
+  return obj;
+}
diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2
index 7cc8a8f80de6738d86e3c86585835fe2a578bf73..24d24d974bc7877efa90c7670149afa29498179b 100644
--- a/app/templates/_scripts.html.j2
+++ b/app/templates/_scripts.html.j2
@@ -26,7 +26,8 @@
   'js/RessourceLists/JobResultList.js',
   'js/RessourceLists/SpacyNLPPipelineModelList.js',
   'js/RessourceLists/TesseractOCRPipelineModelList.js',
-  'js/RessourceLists/UserList.js'
+  'js/RessourceLists/UserList.js',
+  'js/XMLtoObject.js'
 %}
 <script src="{{ ASSET_URL }}"></script>
 {%- endassets %}
@@ -52,7 +53,7 @@
 
   // Initialize components
   M.AutoInit();
-  M.CharacterCounter.init(document.querySelectorAll('input[data-length][type="text"], input[data-length][type="email"], input[data-length][type="search"], input[data-length][type="password"], input[data-length][type="tel"], input[data-length][type="url"], textarea[data-length]'));
+  M.CharacterCounter.init(document.querySelectorAll('input[data-length], textarea[data-length]'));
   M.Dropdown.init(
     document.querySelectorAll('#nav-more-dropdown-trigger'),
     {alignment: 'right', constrainWidth: false, coverTrigger: false}
diff --git a/app/templates/corpora/corpora.html.j2 b/app/templates/corpora/corpora.html.j2
index 8cc701f819d3c60ac7f1132817d9b7ae3b20663c..9be377f32a9fc7b1444f376b89d57a72242629dc 100644
--- a/app/templates/corpora/corpora.html.j2
+++ b/app/templates/corpora/corpora.html.j2
@@ -1,30 +1,46 @@
 {% extends "base.html.j2" %}
 
+{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
+
 {% block page_content %}
-<div class="parallax-container">
-  <div class="parallax"><img src="{{ url_for('static', filename='images/parallax_hq/canvas.png') }}"></div>
-  <div style="position: absolute; bottom: 0; width: 100%;">
-    <div class="container">
-      <div class="white-text">
-        <h1 id="title"><i class="nopaque-icons" style="font-size: inherit;">I</i>Corpora</h1>
-      </div>
-      <div class="white" style="padding: 0 15px; border-radius: 20px;">
-        <div class="input-field">
-          <i class="material-icons prefix">search</i>
-          <input id="public-corpora-search" placeholder="Find public corpora" type="text">
+<div class="corpus-list no-autoinit" id="corpus-list">
+  <div class="parallax-container">
+    <div class="parallax"><img src="{{ url_for('static', filename='images/parallax_hq/canvas.png') }}"></div>
+    <div style="position: absolute; bottom: 0; width: 100%;">
+      <div class="container">
+        <div class="white-text">
+          <h1 id="title"><i class="nopaque-icons" style="font-size: inherit;">I</i>Corpora</h1>
+        </div>
+        <div class="white" style="padding: 1px 35px 0 10px; border-radius: 35px;">
+          <div class="input-field">
+            <i class="material-icons prefix">search</i>
+            <input class="search" id="corpus-list-search" type="text">
+            <label for="corpus-list-search">Search corpus</label>
+          </div>
         </div>
       </div>
     </div>
   </div>
-</div>
 
 
-<div class="container">
   <div class="row">
     <div class="col s12" id="corpora">
       <div class="card">
         <div class="card-content">
-          <div class="corpus-list"></div>
+          <div>
+            <table>
+              <thead>
+                <tr>
+                  <th></th>
+                  <th>Title and Description</th>
+                  <th>Status</th>
+                  <th></th>
+                </tr>
+              </thead>
+              <tbody class="list"></tbody>
+            </table>
+            <ul class="pagination"></ul>
+          </div>
         </div>
       </div>
     </div>
@@ -36,9 +52,21 @@
 {% block scripts %}
 {{ super() }}
 <script>
-  let publicCorporaSearchElement = document.querySelector('#public-corpora-search');
-  let corpusList = CorpusList.getInstance(document.querySelector('#corpora .corpus-list .list'));
-  publicCorporaSearchElement.addEventListener('keyup', function() {corpusList.listjs.search(this.value);});
+  let corpusListElement = document.querySelector('#corpus-list');
+  let corpusListOptions = {
+    initialHtmlGenerator: null,
+    item: `
+      <tr class="clickable hoverable">
+        <td><a class="btn-floating disabled"><i class="material-icons service-color darken" data-service="corpus-analysis">book</i></a></td>
+        <td><b class="title"></b><br><i class="description"></i></td>
+        <td><span class="status badge new corpus-status-color corpus-status-text" data-badge-caption=""></span></td>
+        <td class="right-align">
+          <a class="action-button btn-floating service-color darken waves-effect waves-light" data-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a>
+        </td>
+      </tr>
+    `.trim(),
+  };
+  let corpusList = new CorpusList(corpusListElement, corpusListOptions);
   corpusList._init({{ corpora|tojson }});
 </script>
 {% endblock scripts %}
diff --git a/app/templates/main/news.html.j2 b/app/templates/main/news.html.j2
index b7204f0746a7ac23288cd0d0d25be611141aafe1..c374237c47074462047d77009236a1d5289ce144 100644
--- a/app/templates/main/news.html.j2
+++ b/app/templates/main/news.html.j2
@@ -9,7 +9,7 @@
     </div>
 
     <div class="col s12">
-      <div id="mastodon"></div>
+      <div id="aggregated-news"></div>
 
       <div class="card" id="april-2022-update">
         <div class="card-content">
@@ -132,29 +132,116 @@
 {% block scripts %}
 {{ super() }}
 <script>
-  let mastodonElement = document.querySelector('#mastodon');
-  fetch(`https://fedihum.org/api/v1/accounts/109386364241901080/statuses`, {method: 'GET', headers: {Accept: 'application/json'}})
-    .then((response) => {return response.json();})
-    .then((statuses) => {
-      for (let status of statuses) {
-        console.log(status);
-        let contentHtml = `<div>${status.content}</div>`
-        let tagsHtml = '<p>';
-        for (let tag of status.tags) {
-          tagsHtml += `<a href="${tag.url}" class="chip">${tag.name}</a>`;
-        }
-        tagsHtml += '</p>';
-        let statusHtml = `
-          <div id="${status.id}" class="card">
+  function getMastodonStatuses() {
+    return new Promise((resolve, reject) => {
+      fetch(`https://fedihum.org/api/v1/accounts/109386364241901080/statuses`, {method: 'GET', headers: {Accept: 'application/json'}})
+        .then((response) => {
+          if (!response.ok) {reject(response);}
+          return response.json();
+        })
+        .then((statuses) => {resolve(statuses);})
+      });
+  }
+  function getBisBlogsEntries() {
+    return new Promise((resolve, reject) => {
+      fetch(`https://blogs.uni-bielefeld.de/blog/uniintern/feed/entries/atom?cat=%2FAllgemein`, {method: 'GET', headers: {Accept: 'application/xml'}})
+        .then((response) => {
+          if (!response.ok) {reject(response);}
+          return response.text();
+        })
+        .then((responseText) => {return new DOMParser().parseFromString(responseText, 'application/xml');})
+        .then((xmlDocument) => {return xmlDocument.toObject();})
+        .then((feed) => {resolve(feed);});
+    });
+  }
+  function sortAggregatedNews(a, b) {
+    let aDate;
+    let bDate;
+
+    switch (a.source) {
+      case 'mastodon':
+        aDate = new Date(a.created_at);
+        break;
+      case 'big-blogs':
+        aDate = new Date(a.published);
+        break;
+      default:
+        throw new Error('Unknown source');
+    }
+    switch (b.source) {
+      case 'mastodon':
+        bDate = new Date(b.created_at);
+        break;
+      case 'big-blogs':
+        bDate = new Date(b.published);
+        break;
+      default:
+        throw new Error('Unknown source');
+    }
+    return bDate - aDate;
+  }
+  function aggregateNews() {
+    return new Promise((resolve, reject) => {
+      Promise.all([getMastodonStatuses(), getBisBlogsEntries()])
+        .then(
+          (responses) => {
+            console.log(responses[1]);
+            let mastodonStatuses = responses[0].map((obj) => {return { ...obj, source: 'mastodon'}});
+            let bisBlogsEntries = responses[1].feed.entry.map((obj) => {return { ...obj, source: 'big-blogs'};});
+            let aggregatedNews = [...mastodonStatuses, ...bisBlogsEntries];
+            aggregatedNews.sort(sortAggregatedNews);
+            resolve(aggregatedNews);
+          },
+          (error) => {reject(error);}
+        );
+    });
+  }
+
+  function mastodonStatusToHtml(status) {
+    return htmlString = `
+      <div class="card white-text" style="background-color:#5D50E7;">
+        <div class="card-content">
+          <span class="card-title">New Actitvity on Mastodon</span>
+          ${status.content}
+        </div>
+      </div>
+    `.trim();
+  }
+  function bisBlogsEntryToHtml(entry) {
+    return `
+      <div class="row">
+        <div class="col s1">
+          <img src="https://blogs.uni-bielefeld.de/blog/uniintern/resource/themabilder/unilogo-square.svg" alt="Bielefeld University Blogs" class="responsive-img">
+        </div>
+        <div class="col s11">
+          <div class="card" style="background-color: #14f5b4;">
             <div class="card-content">
-              <span class="card-title">Mastodon News</span>
-              ${contentHtml}
-              ${tagsHtml}
+              <span class="card-title">${entry.title['#text']}</span>
+              ${entry.content['#text']}
             </div>
           </div>
-        `;
-        mastodonElement.insertAdjacentHTML('beforeend', statusHtml);
+        </div>
+      </div>
+    `.trim();
+  }
+
+  let aggregatedNewsElement = document.querySelector('#aggregated-news');
+  aggregateNews().then((aggregatedNews) => {
+    for (let item of aggregatedNews) {
+      let itemHtmlString;
+      switch (item.source) {
+        case 'mastodon':
+          console.log(item);
+          itemHtmlString = mastodonStatusToHtml(item);
+          break;
+        case 'big-blogs':
+          itemHtmlString = bisBlogsEntryToHtml(item);
+          break;
+        default:
+          throw new Error('Unknown source');
       }
-    });
+      aggregatedNewsElement.insertAdjacentHTML('beforeend', itemHtmlString);
+    }
+  });
 </script>
 {% endblock scripts %}