Zenn

LEAF WriterとGakuNin RDMを用いたTEI/XMLファイルの編集環境の試作

2025/03/21に公開

概要

LEAF WriterとGakuNin RDMを用いたTEI/XMLファイルの編集環境の試作を行いましたので、備忘録です。

参考

以下の記事で、LEAF WriterをNext.jsから使用する方法を紹介しました。

https://zenn.dev/nakamura196/articles/ea9e000c32ef6b

特に、以下のnpmパッケージを使用しています。

https://www.npmjs.com/package/@cwrc/leafwriter

上記で編集対象とするTEI/XMLファイルの入出力にあたり、GakuNin RDMを使用してみます。GakuNin RDMのAPIをJavaScriptから使用する方法について、以下も参考になりましたら幸いです。

https://zenn.dev/nakamura196/articles/12f3bd0b1d6ef4

使い方

以下がプロトタイプシステムのURLです。(色々と不具合が含まれる点にご注意ください。)

https://rdm-leaf-editor.vercel.app/

UIはClaude 3.7 Sonnetに作成してもらっています。

「サインイン」ボタンを押すと、認証画面に進むので、ログインします。

ログイン後、リダイレクトされ、プロジェクトの一覧が表示されます。

TEI/XMLファイルが含まれるディレクトリまで移動します。ファイル名に「.xml」が含まれる場合、「Leaf Writer」の列に「編集」ボタンが表示されます。

LEAF Writerの編集画面に遷移するので、テキストを編集します。作業が完了したら、画面右上の「保存」ボタンを押します。

GakuNin RDMのUIから確認してみると、バージョンごとに保存されていることが確認できます。

実装

GakuNin RDMからのファイルの取得および更新は以下で行っています。

/**
 * ファイルの内容を取得する
 */
export async function fetchFileContent(
  url: string,
  accessToken: string
): Promise<string> {
  const response = await fetch(url, {
    method: "GET",
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  });

  if (!response.ok) {
    throw new Error(
      `ファイルの取得に失敗しました。ステータスコード: ${response.status}`
    );
  }

  return await response.text();
}

/**
 * ファイルの内容を更新する
 */
export async function updateFileContent(
  url: string,
  content: string,
  accessToken: string,
  contentType: string = "application/xml"
): Promise<void> {
  const blob = new Blob([content], { type: contentType });

  const response = await fetch(url, {
    method: "PUT",
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
    body: blob,
  });

  if (!response.ok) {
    const errorText = await response.text();
    console.error("保存に失敗しました。ステータスコード:", response.status);
    console.error("レスポンス:", errorText);
    throw new Error(`保存に失敗しました。ステータスコード: ${response.status}`);
  }
}

上記で使用するURLは以下です。

const url = `https://files.rdm.nii.ac.jp/v1/resources/${project}/providers/${provider}/${id}?kind=file`;

以下のAPIから取得可能なJSONデータから、値を確認できます。(以下のURLには権限の関係でアクセスいただけないはずです。)

https://api.rdm.nii.ac.jp/v2/files/67da847416000900109e0454/

{
  "data": {
    "id": "67da847416000900109e0454",
    "type": "files",
    "attributes": {
      "guid": "b45mp",
      "checkout": null,
      "name": "01.xml",
      "kind": "file",
      "path": "/67da847416000900109e0454",
      "size": 72093,
      "provider": "osfstorage",
      "materialized_path": "/01.xml",
      "last_touched": null,
      "date_modified": "2025-03-21T00:29:59.408950Z",
      "date_created": "2025-03-19T08:46:44.636107Z",
      "extra": {
        "hashes": {
          "md5": "a49f7d8fafd3a8c01cb82fe4b9442d9a",
          "sha256": "3de7d4d948e9d11ad3fe169f3d7a7786e668baf8e56c347b50bbb80d258c52af"
        },
        "downloads": 0
      },
      "tags": [],
      "current_user_can_comment": true,
      "current_version": 16
    },
    "relationships": {
      "parent_folder": {
        "links": {
          "related": {
            "href": "https://api.rdm.nii.ac.jp/v2/files/674034a483bdc200108b8a95/?format=json",
            "meta": {}
          }
        },
        "data": {
          "id": "674034a483bdc200108b8a95",
          "type": "files"
        }
      },
      "versions": {
        "links": {
          "related": {
            "href": "https://api.rdm.nii.ac.jp/v2/files/67da847416000900109e0454/versions/?format=json",
            "meta": {}
          }
        }
      },
      "comments": {
        "links": {
          "related": {
            "href": "https://api.rdm.nii.ac.jp/v2/nodes/wzv9g/comments/?format=json&filter%5Btarget%5D=b45mp",
            "meta": {}
          }
        }
      },
      "metadata_records": {
        "links": {
          "related": {
            "href": "https://api.rdm.nii.ac.jp/v2/files/67da847416000900109e0454/metadata_records/?format=json",
            "meta": {}
          }
        }
      },
      "node": {
        "links": {
          "related": {
            "href": "https://api.rdm.nii.ac.jp/v2/nodes/wzv9g/?format=json",
            "meta": {}
          }
        },
        "data": {
          "id": "wzv9g",
          "type": "nodes"
        }
      },
      "target": {
        "links": {
          "related": {
            "href": "https://api.rdm.nii.ac.jp/v2/nodes/wzv9g/",
            "meta": {
              "type": "node"
            }
          }
        },
        "data": {
          "type": "node",
          "id": "wzv9g"
        }
      }
    },
    "links": {
      "info": "https://api.rdm.nii.ac.jp/v2/files/67da847416000900109e0454/",
      "move": "https://files.rdm.nii.ac.jp/v1/resources/wzv9g/providers/osfstorage/67da847416000900109e0454",
      "upload": "https://files.rdm.nii.ac.jp/v1/resources/wzv9g/providers/osfstorage/67da847416000900109e0454",
      "delete": "https://files.rdm.nii.ac.jp/v1/resources/wzv9g/providers/osfstorage/67da847416000900109e0454",
      "download": "https://rdm.nii.ac.jp/download/b45mp/",
      "render": "https://mfr.rdm.nii.ac.jp/render?url=https://rdm.nii.ac.jp/download/b45mp/?direct%26mode=render",
      "html": "https://rdm.nii.ac.jp/wzv9g/files/osfstorage/67da847416000900109e0454",
      "self": "https://api.rdm.nii.ac.jp/v2/files/67da847416000900109e0454/"
    }
  }
}

まとめ

LEAF-Writer Commonsについては、GitHubをデフォルトのストレージおよび認証システムとして使用しています。

https://leaf-writer.leaf-vre.org/

今回開発したシステムは、GitHubの代わりにGakuNin RDMを使用しているといった関係です。

LEAF Writerをnpmパッケージとして公開してくださっている方々に感謝いたします。

Discussion

ログインするとコメントできます