0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ExcelからJsonに変換してローカルHTMLで検索するだけの簡易データベース

Posted at

概要

中身は標題のとおりですが、真新しいこと、技術的な知見はまったくありませんが、超簡単なわりには、事務的な作業には便利です。
Excelファイルを、簡単なPythonスクリプト(Pandas)でJsonに変換したものに、HTMLの簡単なUIをかぶせただけです。

Excelファイル

なんでもいいのですが、列名の一つは’Title’とすること、A列(0列目)は行番号にします。

ExcelからJsonへ

import pandas as pd
import os

df = pd.read_excel(r'./test.xlsx', index_col=0)
path = r"./test.json"

df.to_json(path, orient='records', force_ascii=False)

例えばこんなjsonファイルができます。

test.json
[
{"著者名":"杉崎 光一 and 阿部 雅人 and 全 邦釘","Title":"大規模言語モデルの専門領域への適用に関する検討","雑誌名":"AI・データサイエンス論文集","ISSN":"2435-9262","出版者名":"公益社団法人 土木学会","出版日付":2023,"巻":4,"号":3,"ページ":"474-481","URL":"https:\/\/cir.nii.ac.jp\/crid\/1390579599242174080","URL(DOI)":"https:\/\/doi.org\/10.11532\/jsceiii.4.3_474"},
{"著者名":"尾崎 大晟 and 中川 智皓 and 内藤 昭一 and 井之上 直也 and 山口 健史 and 新谷 篤彦","Title":"大規模言語モデルによる高品質反論文の自動生成","雑誌名":"人工知能学会全国大会論文集","ISSN":"2758-7347","出版者名":"一般社団法人 人工知能学会","出版日付":2023,"巻":"JSAI2023","号":0,"ページ":"4Xin111-4Xin111","URL":"https:\/\/cir.nii.ac.jp\/crid\/1390859758174987520","URL(DOI)":"https:\/\/doi.org\/10.11517\/pjsai.jsai2023.0_4xin111"},
{"著者名":"藤井 純一郎 and 大久保 順一 and 緒方 陸 and 天方 匡純","Title":"LLMを土木分野に適応するための基礎的研究","雑誌名":"AI・データサイエンス論文集","ISSN":"2435-9262","出版者名":"公益社団法人 土木学会","出版日付":-2034374400000,"巻":4,"号":3,"ページ":"779-785","URL":"https:\/\/cir.nii.ac.jp\/crid\/1390861074219063168","URL(DOI)":"https:\/\/doi.org\/10.11532\/jsceiii.4.3_779"},{"著者名":"宮下, 丈明 and 片山, 徹郎","Title":"テスト駆動開発における継続的な支援を目的としたフレームワークCATddの試作","雑誌名":"ソフトウェアエンジニアリングシンポジウム2023論文集","ISSN":null,"出版者名":"情報処理学会","出版日付":1692144000000,"巻":2023,"号":null,"ページ":"144-153","URL":"https:\/\/cir.nii.ac.jp\/crid\/1050015719934135168","URL(DOI)":null},
{"著者名":"玉置 亮太","Title":"特集 「日の丸LLM」に挑む : 生成AI安全保障は実現するか","雑誌名":"日経コンピュータ = Nikkei computer","ISSN":2854619,"出版者名":"東京 : 日経BP","出版日付":1692230400000,"巻":null,"号":1101,"ページ":"28-37","URL":"https:\/\/cir.nii.ac.jp\/crid\/1520015741622314112","URL(DOI)":null}
]

HTML

index.html
<!DOCTYPE html>
<html lang="ja">
<title>簡易検索</title>
<script type="module">
// urlから、jsonデータをfetchして取得する
async function getData(url) {
  const response = await fetch(url);
  const data = await response.json();
  return data;
}
  function searchObjectsByKeyword(data, keyword) {
    const pattern = new RegExp(keyword, 'i'); // 大文字・小文字を無視
    const result = [];
    // オブジェクトや配列を再帰的に探索
    function containsKeyword(obj) {
      if (Array.isArray(obj)) {
        return obj.some(item => containsKeyword(item));
      }
      return Object.values(obj).some(value => {
        if (value === null || value === undefined) return false;

        if (typeof value === 'string') {
          return pattern.test(value);
        } else if (typeof value === 'object') {
          return containsKeyword(value);
        }
        return false;
      });
    }
    // 検索本体 return data.filter(item => containsKeyword(item));
    const filter_data = data.filter(item => containsKeyword(item));
    return filter_data.map(item => {
      // 不要なプロパティを削除  
      const newItem = {};
      for (const key in item) {
        if (item[key] !== null && item[key] !== undefined) {
          newItem[key] = item[key];
        }
      }
      return newItem;
    });
  }

  // 結果表示を組み立てる
  function createResult(keys2) {
    let resultList2 = '';
    resultList2 += '<ol class="resultHtml4">';
    for (let i = 0; i < keys2.length; ++i) {
      let resultHtml4 = craeteHtmlFromJson(keys2[i]);
      resultList2 += resultHtml4 + '</li>'; // </ol>';  
    }
    resultList2 += '</ol>';
    return [resultList2, keys2.length];
  }

  function craeteHtmlFromJson(keys2i) {
    let resultHtml3 = [];
    const title = keys2i['Title'] || 'No Title';
    resultHtml3.push(`<li class="title">${title}</li><ul class="hidden hidden2">`);
    for (const [key, value] of Object.entries(keys2i)) {
      resultHtml3.push(`<li class="${key}">${key} ${value}</li>`);
    }
    resultHtml3.push('</ul>');
    return resultHtml3.join('');
  }

  // console.log('要素を消す');
  const deleteElem = (elem) => {
    let items = document.querySelectorAll(elem);  // '.resultHtml4');
    for (const item of items) {
      item.remove();
    }
  }

const url = './test.json'; // ここにjsonファイルのURLを指定
const data = await getData(url);

// 入力フォーム
const input = document.getElementById("sampleForm");
const span = document.getElementById("inputCounter");
input.addEventListener("keyup", function () {
  span.textContent = input.value.length;
  if (span.textContent > 2) {
      let search_word = input.value;
      const result = searchObjectsByKeyword(data, search_word); // ←検索したい単語を指定
      console.log('result:', result);
      const resultList = createResult(result);
      document.getElementById('resultHtml').innerHTML = resultList[0];
      document.getElementById('resultTotal').innerHTML = '<div class="total">Total: ' + resultList[1] + '件です。</div>';
            document.getElementById('clickBtn1').innerHTML = '<input type="button" value="詳細表示" id="clickBtn1" />';
        } else {
            console.log('ここで要素を消す');
            deleteElem('.resultHtml4');
            deleteElem('.total');
        };
    });
</script>
<style>
.hidden {
  display: none;
}
</style>
</head>

<body>
    <label for="sampleForm">検索
        <ul>
            <li>3文字以上入力すると検索を開始します。</li>
            <li>正規表現が使えます(2文字で検索したい場合、ドットを加えることで可能)。</li>
        </ul>
    </label>

    <br />
    <input type="text" id="sampleForm" placeholder=".*大規模.*"/>
    <p><span id="inputCounter">0</span>文字</p>
    <div id="clickBtn1"></div>
    <div id="resultTotal"></div>
    <div id="resultHtml"></div>
<script>// ...existing code...
// 詳細表示をトグルする
const btn = document.getElementById('clickBtn1');
btn.addEventListener('click', () => {
  const categories = document.getElementsByClassName('hidden2');
  Array.from(categories).forEach(e => {
    if (e.classList.contains('hidden')) {
      e.classList.remove('hidden');
    } else {
      e.classList.add('hidden');
    }
  });
});
</script>
</body>
</html>

一応解説

  • jsonファイrをfetchしてきて、オブジェクトをfilter()しているだけです。
  • 完全にローカルだけで動きますが、適切なところにおけばjsonファイルはインターネットのどこかでも大丈夫です。
  • 3文字入力すると、インクリメンタルに検索します。
  • 正規表現が使えるので、2文字でも dot をつければ検索できます。
  • だだし、元のエクセルで列が違えば、掛け合わせはできません。
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?